《ZLToolKit源码学习笔记》(2)工具模块之日志功能分析

系列文章目录

《ZLToolKit源码学习笔记》(1)VS2019源码编译

《ZLToolKit源码学习笔记》(2)工具模块之日志功能分析(本文)

《ZLToolKit源码学习笔记》(3)工具模块之终端命令解析

《ZLToolKit源码学习笔记》(4)工具模块之消息广播器

《ZLToolKit源码学习笔记》(5)工具模块之资源池

《ZLToolKit源码学习笔记》(6)线程模块之整体框架概述

《ZLToolKit源码学习笔记》(7)线程模块之线程池组件:任务队列与线程组

《ZLToolKit源码学习笔记》(8)线程模块之线程负载计算器

《ZLToolKit源码学习笔记》(9)线程模块之任务执行器

《ZLToolKit源码学习笔记》(10)线程模块之线程池

《ZLToolKit源码学习笔记》(11)线程模块之工作线程池WorkThreadPool

《ZLToolKit源码学习笔记》(12)事件轮询模块之整体框架概述

《ZLToolKit源码学习笔记》(13)事件轮询模块之管道的简单封装

《ZLToolKit源码学习笔记》(14)事件轮询模块之定时器

《ZLToolKit源码学习笔记》(15)事件轮询模块之事件轮询器EventPoller

《ZLToolKit源码学习笔记》(16)网络模块之整体框架概述

《ZLToolKit源码学习笔记》(17)网络模块之基础接口封装类SockUtil

《ZLToolKit源码学习笔记》(18)网络模块之Buffer缓存

《ZLToolKit源码学习笔记》(19)网络模块之套接字封装

《ZLToolKit源码学习笔记》(20)网络模块之TcpServer

《ZLToolKit源码学习笔记》(21)网络模块之TcpClient与Session

《ZLToolKit源码学习笔记》(22)网络模块之UdpServer


文章目录


前言

日志模块主要是logger.h和logger.cpp两个文件。


一、日志功能的使用

1、日志级别

作者定义了以下 五个日志级别:

typedef enum {
    LTrace = 0, LDebug, LInfo, LWarn, LError
} LogLevel;

2、日志的调用方式

#define TraceL LogContextCapturer(getLogger(), LTrace, __FILE__,__FUNCTION__, __LINE__)
#define DebugL LogContextCapturer(getLogger(),LDebug, __FILE__,__FUNCTION__, __LINE__)
#define InfoL LogContextCapturer(getLogger(),LInfo, __FILE__,__FUNCTION__, __LINE__)
#define WarnL LogContextCapturer(getLogger(),LWarn,__FILE__, __FUNCTION__, __LINE__)
#define ErrorL LogContextCapturer(getLogger(),LError,__FILE__, __FUNCTION__, __LINE__)
#define WriteL(level) LogContextCapturer(getLogger(),level,__FILE__, __FUNCTION__, __LINE__)

头文件中分别提供了五个日志级别的宏定义,使用方式在test_logger.cpp中有示例。这里不再CV。


二、源码结构分析

1、类图

先整体看下日志模块的类图,主要分为五部分,LogChannel、LogWriter、LogContext、logger、logContextCapturer。下面将会对这五个模块分别分析。

2、各模块分析

2.1、LogContextCapturer:

日志上下文捕获器,调用者使用日志功能时,直接接触到的就是该类,每次打印日志时,都实例化一个该类的对象。类的内部,持有LogContext和Logger两个类的对象。LogContext对象存储用户输出的日志信息,Logger对象最终把LogContext中字符串信息输出。该类重载了<<运算符,有以下两个版本:

template<typename T> LogContextCapturer &operator<<(T &&data);

LogContextCapturer &operator<<(ostream &(*f)(ostream &));

第一个版本,模板函数,主要是将用户输入的log信息存储到LogContext对象中。如果传入的data是c++内置数据类型或者是标准库中实现了ostream重载的类型,可以直接使用,如果是用户自定义类,则需要自己在自定义类中重载以下运算符:

friend ostream& operator<<(ostream& out, const userClass& userObj );

第二个版本,很多人可能没见过这种方式。参数f是一个函数指针,说明这个重载版本需要的是一个函数,那么什么时候会用到这个版本的重载呢?

重载这个版本的目的是为了立即将当前的日志信息进行输出,作者在这里直接复用了STL中的std::endl。在<<std::endl时会执行这个重载函数。这里我们需要了解下std::endl本质上到底是什么?以下是windows下看到的endl的定义:

template <class _Elem, class _Traits>
basic_ostream<_Elem, _Traits>& __CLRCALL_OR_CDECL endl(
    basic_ostream<_Elem, _Traits>& _Ostr) { // insert newline and flush stream
    _Ostr.put(_Ostr.widen('\n'));
    _Ostr.flush();
    return _Ostr;
}

可以看到,endl就是一个函数,且函数原型实际上就是ostream& endl(ostream&);

用户在使用该类输出日志时,首先实例化一个类对象,在构造函数中,实例化了LogContext对象。当执行logContextCapturer<<str时,会把日志先存储到logContext中,最后在调用logContextCapturer<<endl或者对象析构时,通过Logger的对象将日志内容输出。

LogContextCapturer &LogContextCapturer::operator<<(ostream &(*f)(ostream &)) {
    if (!_ctx) {
        return *this;
    }
    _logger.write(_ctx);
    _ctx.reset();
    return *this;
}

2.2、LogContext

日志上下文,用于存储日志信息,包括日志级别、日志所在文件名、函数名、行号、用户待输出的日志信息。

该类继承了ostringstream类,用户待输出的日志信息会先存储在ostringstream中。前边说的用户自定义类型在使用日志功能时,需要重载以下函数的原因就是基于此。ostringstream的基类是ostream。

friend ostream& operator<<(ostream& out, const userClass& userObj );

2.3、Logger

该类是一个单例类,用于日志模块的配置管理。主要有以下功能:

配置日志输出通道。是终端还是文件、或者系统日志中,对应函数add、del、get;

设置写日志器。实际上就是控制日志是否要异步输出,对应函数setWriter;

设置各类型通道的日志级别。对应函数setLevel;

控制是同步还是异步写日志。如果没有设置写日志器,就是同步写,否则就是异步写。实际的写日志操作最终是在各类型日志通道中完成。

2.4、logWriter

写日志器类,该类是一个抽象类,定义了一个write纯虚函数。实际上,该类目前也只有一个派生类,即AsyncLogWriter类,作用是开启一个线程,先将日志存储在队列中,然后异步的将日志信息输出。

2.5、LogChannel

日志通道类,该类是一个抽象类,且是所有特定类型通道的基类。该类包含一个纯虚函数write,以及一个静态函数printTime,两个成员函数name和setLevel,以及一个虚函数format,实际的日志输出最终在format中,如果是终端,还会对不同级别的日志信息分颜色输出。

ConsoleChannel,输出日志到终端,使用std::cout。

SysLogChannel,输出日志到系统日志。windows、IOS、Android不支持。

FileChannelBase,输出日志到文件,使用ofstream。因为写日志到文件还涉及文件的保存天数、单文件大小、文件数量等配置项,所以输出日志到文件最终使用的是FileChannel类。

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
Libevent是一个事件驱动的网络编程框架,而event.h是其核心头文件之一。该头文件定义了事件处理相关的结构体、函数和宏等内容。 下面是event.h中常用的一些定义和函数: ### 1.事件回调函数 ```c typedef void (*event_callback_fn)(evutil_socket_t fd, short events, void *arg); ``` 该类型定义了事件回调函数的原型,其中fd是事件所在的文件描述符,events是事件类型,arg是用户传入的参数。 ### 2.事件结构体 ```c struct event { event_callback_fn ev_callback; // 事件回调函数 int ev_fd; // 事件所在的文件描述符 short ev_events; // 事件类型 short ev_res; // 事件结果 struct event_base *ev_base; // 事件所属的event_base void *ev_arg; // 用户传入的参数 }; ``` 该结构体表示一个事件,其中ev_callback是事件回调函数,ev_fd是事件所在的文件描述符,ev_events是事件类型,ev_res是事件结果,ev_base是事件所属的event_base,ev_arg是用户传入的参数。 ### 3.事件类型 ```c #define EV_TIMEOUT 0x01 #define EV_READ 0x02 #define EV_WRITE 0x04 #define EV_SIGNAL 0x08 #define EV_PERSIST 0x10 #define EV_ET 0x20 ``` 该宏定义了事件类型,分别为超时事件、读事件、写事件、信号事件、持续事件和边缘触发事件。 ### 4.事件处理函数 ```c struct event_base *event_base_new(void); int event_base_dispatch(struct event_base *base); int event_base_loopexit(struct event_base *base, const struct timeval *tv); void event_base_free(struct event_base *base); ``` 这些函数用于创建event_base、处理事件、退出事件循环和释放event_base等操作。 以上是event.h中的一些常用内容,更多细节可以查看源码和官方文档。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秦时小

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值