muduo库学习第四天日志类的封装Logging

本文详细介绍了muduo库中的日志类封装,包括Logger类和LogStream的实现。Logger类定义了日志等级,并通过Impl类和LogStream进行实际操作,将数据写入缓冲区。LogStream使用FixedBuffer存储数据,并重载<<操作符,方便将各类数据转化为字符串。文章还介绍了如何设置输出位置以及宏的使用方法,展示了日志记录的完整流程。

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

https://blog.csdn.net/weixin_46074727/article/details/115752252?spm=1001.2014.3001.5501

https://blog.csdn.net/weixin_46074727/article/details/115690387?spm=1001.2014.3001.5501

https://blog.csdn.net/weixin_46074727/article/details/115657695?spm=1001.2014.3001.5501

整体的思路为:Logging类定义日志的等级,在Logging类中包含一个Impl类用来执行,Impl类中还包含一个Logstream类,类似于iostream这种重载<< >>操作将数据输入到缓冲区。

Logging->Impl->LogStream->FixedBuffer.

目录

1.Logger类

2.LogStream

三用法


1.Logger类

Logger包含一个enum表示日志的等级

enum LogLevel
  {
    TRACE,
    DEBUG,
    INFO,
    WARN,
    ERROR,
    FATAL,
    NUM_LOG_LEVELS,
  };

还包含一个sourfile类主要是用来包装__FILE__的,保留basename。比如对于一个路径lhb/home/下载/test.cpp  其中test.cpp就是basename。

最后是一个Impl类,Impl类中有一个LogStream对象,最终的操作都会转到Impl类中去执行,并将内容添加到LogStream对象的缓冲区中。在Logger的构造函数中最终都是调用impl的构造函数。这里有一个小细节就是最后一个构造函数,当是关闭程序的时候日志等级为FATAL,否则为ERROR。

Logger::Logger(SourceFile file, int line)
  : impl_(INFO, 0, file, line)
{
}
Logger::Logger(SourceFile file, int line, LogLevel level, const char* func)
  : impl_(level, 0, file, line)
{
  impl_.stream_ << func << ' ';
}
Logger::Logger(SourceFile file, int line, LogLevel level)
  : impl_(level, 0, file, line)
{
}
Logger::Logger(SourceFile file, int line, bool toAbort)
  : impl_(toAbort?FATAL:ERROR, errno, file, line)
{
}

而impl构造函数会将这些信息缓存到LogStream对象的缓冲区中,其中的T帮助在编译的时候知道字符串的长度。

Logger::Impl::Impl(LogLevel level, int savedErrno, const SourceFile& file, int line)
  : time_(Timestamp::now()),
    stream_(),
    level_(level),
    line_(line),
    basename_(file)
{
  formatTime();
  CurrentThread::tid();
  stream_ << T(CurrentThread::tidString(), CurrentThread::tidStringLength());//打印当前线程的tid
  stream_ << T(LogLevelName[level], 6);打印//日志等级
  if (savedErrno != 0)
  {
    stream_ << strerror_tl(savedErrno) << " (errno=" << savedErrno << ") ";
  }//如果有错误信息的话打印出错误信息。
}

还有一些功能比如就是设置输出的地方的。

 typedef void (*OutputFunc)(const char* msg, int len);
  typedef void (*FlushFunc)();
  static void setOutput(OutputFunc);
  static void setFlush(FlushFunc);

最后是析构函数,析构函数先调用finish函数,而finish函数是将一些最后的信息打印到缓冲区中,然后返回LogStream中的缓冲区并且将其打印到默认的输出地方,最后判断是否关闭程序。

2.LogStream

LogStream包含一个FixedBuffer,然后重载<<操作符,所有的操作都是将内容添加到FixedBuffer中。其中最为精彩的地方是将整数转换为字符串,我在其中添加了注释

const char digits[] = "9876543210123456789";
const char* zero = digits + 9;
// Efficient Integer to String Conversions, by Matthew Wilson.
template<typename T>
size_t convert(char buf[], T value)
{
  T i = value;
  char* p = buf;

  do
  {
    int lsd = static_cast<int>(i % 10);
    i /= 10;
    *p++ = zero[lsd];//这里是考虑还有负数的情况,假如lsd为负数那么根据zero的索引最后得到的字符也是正确的
  } while (i != 0);

  if (value < 0)
  {
    *p++ = '-';
  }
  *p = '\0';
  std::reverse(buf, p);//最后将其反正

  return p - buf;//然后返回添加的长度
}

而将浮点数转换为字符串时作者用了snprintf。 其实很多操作我都进行了简化,主要是现在的我因为缺乏经验而不明白其中的用意。

三用法

首先作者定义了如下的宏

#define LOG_TRACE if (muduo::Logger::logLevel() <= muduo::Logger::TRACE) \
  muduo::Logger(__FILE__, __LINE__, muduo::Logger::TRACE, __func__).stream()
#define LOG_DEBUG if (muduo::Logger::logLevel() <= muduo::Logger::DEBUG) \
  muduo::Logger(__FILE__, __LINE__, muduo::Logger::DEBUG, __func__).stream()
#define LOG_INFO if (muduo::Logger::logLevel() <= muduo::Logger::INFO) \
  muduo::Logger(__FILE__, __LINE__).stream()
#define LOG_WARN muduo::Logger(__FILE__, __LINE__, muduo::Logger::WARN).stream()
#define LOG_ERROR muduo::Logger(__FILE__, __LINE__, muduo::Logger::ERROR).stream()
#define LOG_FATAL muduo::Logger(__FILE__, __LINE__, muduo::Logger::FATAL).stream()
#define LOG_SYSERR muduo::Logger(__FILE__, __LINE__, false).stream()
#define LOG_SYSFATAL muduo::Logger(__FILE__, __LINE__, true).stream()

使用方法如下:LOG_DEBUG<<"123";  宏替换为Logger(__FILE__, __LINE__, muduo::Logger::DEBUG, __func__).stream()<<"123"

整体流程为先构造一个匿名的Logger类,调用Logger的构造函数,而Logger的构造函数又调用Impl的构造函数,Impl在构造函数中将,__FILE__ __LINE__等信息添加到LogStream对象的缓冲区中,然后返回LogStream对象,因为LogStream重载了<<操作符,所以<<"123"也是将其加入缓冲区中,当语句结束后,调用Logger的析构函数,将缓冲区的内容刷新到文件或者屏幕中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值