17.muduo学习笔记之base_Logging.{h&cc}

本文详细解析了muduo日志系统的架构与实现,包括日志类间的关系、Logger类的成员变量与函数、内部类SourceFile与Impl的功能,以及日志宏的使用方式。介绍了日志等级的作用与应用,适合对muduo日志系统感兴趣的开发者阅读。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 说明

  • muduo的日志类,关于日志的相关信息见最后

  • 这个文件有点复杂,而且日志功能贯穿好几个文件,下面开始慢慢探索

  • 日志类之间的关系:

    Logger --> Impl --> LogStream --> operator<<FixedBuffer --> g_output --> g_flush    
    
    LOG_ERROR << "hello.";
    等价于:
    Logger(__FILE__, __LINE__, Logger::ERROR).stream() << "hello.";
    
  • 使用LOG宏时会创建一个匿名Logger对象(其中包含一个Impl类型的成员变量),并调用stream()函数得到一个LogStream对象的引用,而LogStream重载了<<操作符,可以将日志信息存入LogStream的buffer中。这样LOG_语句执行结束时,匿名Logger对象被销毁,在Logger的析构函数中,会在日志消息的末尾添加LOG_语句的位置信息(文件名和行号),最后调用g_output()回调函数将日志信息传输到后端,由后端日志线程将日志消息写入日志文件

2. Logger类

1. 成员变量

  1. LogLevel,枚举类型,标识几种日志等级
  2. impl_
    • Impl类型,Impl是个内部类,见下面说明

2. 成员函数

1. 普通
  1. 4种构造函数

    • Logger(SourceFile file, int line);
      • 空函数,只赋值impl_,指定SourceFile和line
      • 默认INFO级别,无错误
    • Logger(SourceFile file, int line, LogLevel level);
      • 和上面一样,多加了个指定级别
    • Logger(SourceFile file, int line, LogLevel level, const char* func);
      • 把func的地址信息加到impl_.stream_中
    • Logger(SourceFile file, int line, bool toAbort);
      • 如过toAbort为true,level设置为FATAL,否则为ERROR
  2. 析构函数

    • 把缓冲区中的内容取出来,用g_output输出到特定文件,默认为stdout,关于g_output,后面有说明
  3. stream()

    • 返回impl_stream_引用,实际就是LogStream类型
  4. (*OutputFunc)(const char* msg,int len)

    • 输出的控制函数,默认输出到stdout
  5. (*FlushFunc)()

    • 刷新的回调函数,默认刷新标准输出
2. 静态函数
  1. LogLevel()
    • 返回g_logLevel
  2. setLogLevel(LogLevel)
    • 设置g_logLevel
  3. setOutput(OutputFunc)
    • 设置输出函数,OutputFunc在.h文件的类中有typedef定义
  4. setFlush(FlushFunc)
    • 设置刷新函数
  5. setTimeZone(const TimeZone& tz)
    • 设置g_logTimeZone,这是一个全局变量

3. 内部类SourceFile

1. 成员变量

  1. data_
    • 存储文件名
  2. size_
    • 文件名大小

2. 成员函数

  1. 构造函数
    • 找到最后一个’/’,把后面的赋值给data_

4. 内部类Impl

1. 成员变量(全public)

  1. time_

    • Timestamp类型
  2. stream_

    • LogStream类型
  3. level_

    • LogLevel类型,一个枚举类型
  4. line_

    • 标识行数
  5. basename_

    • SourceFile类型

2. 成员函数

  1. 构造函数
    • 初始化一堆变量,生成时间和缓存tid
    • 重要的是指定SourceFile和line
  2. formatTime()
    • 时间格式化赋值给t_time数组,这是一个线程局部变量
  3. finish()
    • 结束后,给输出缓冲区加上basename_和行数

5. 几种宏定义

  1. LOG_TRACE
    如果level<=TRACE的话,用一个匿名Logger对象,调用stream(),返回一个LogStream类型的引用,这个类重载了<<运算符,然后把信息输入到缓冲区
  • 一下几种宏定义都和上面差不多,有细微差别,自己看吧
  1. LOG_DEBUG

  2. LOG_INFO

  3. …其他略

6. 其他

1. 变量

1. 普通全局变量
  1. g_logLevel

    • 在.cc文件中定义,所以.h文件中用extern
    • 用initLogLevel()函数对这个变量初始化
  2. LogLevelName

    • 数组,几种日志级别的名称字符串
  3. g_output

    • Logger::OutputFunc类型,输出函数,赋值为defaultOutput
  4. g_flush

    • Logger::FlushFunc类型,默认刷新函数,赋值为defaultFlush
  5. g_logTimeZone

    • TimeZone类型
2. 线程局部变量
  1. t_errnobuf

    • strerror_r()函数中要用到的错误信息存储的缓存空间
  2. t_time

    • 线程局部变量的time,在Impl的formatTime()中赋值
  3. t_lastSecond

    • 记录上一次记录的时间,在Impl的formatTime()中使用,如果时间不同才更新

2. 函数

  1. logLevel()

    • 返回g_logLevel,这个实际上Logger类函数
  2. strerror_tl()

    • 调用strerror_r(),对于函数strerror_r,第一个参数errnum是错误代码,第二个参数buf是用户提供的存储错误描述的缓存,第三个参数n是缓存的大小。strerror()不是线程安全的,strerror_r()是线程安全的。
    • 在单线程的程序中,errno是全局变量。然后,在多线程程序中,errno会按照每个线程来储存,因此具有线程安全性。
  3. CheckNotNull(Logger::SourceFile file, int line, const char *names, T* ptr)

  4. initLogLevel()

    • 看环境变量有没有特定的日志级别指定,没有的话,默认为INFO级别
  5. defaultOutput(const char* msg, int len)

    • 默认输出,把msg输出到stdout
  6. defaultFlush()

    • 默认刷新,调用fflush(stdout)

3. .cc中的类T

  1. 在编译时获取已知字符串长度的helper类,断言字符串的长度
  2. 这个类的作用就是判定字符串是不是给定的长度,如果不是,直接报错

7. 日志知识

1. 日志作用

  1. 不用gdb调试,把调试信息打印到日志中…之前为什么没想过这种办法,总是用gdb…

2. 日志等级

  1. TRACE
  2. DEBUG,上个和这个是调试的时候用,记录详细的程序运行过程,各变量的变化
  3. INFO,程序运行信息,上线后一般用这个等级
  4. WARN,警告
  5. ERROR,错误信息
  6. FATAL
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值