1、日志概述
- 日志模块在任何系统中,都是非常重要的,它有助于定位程序运行时出现的问题。日志除了输出的内容,还需要包括文件名、行号、线程号、协程号、时间、日志级别等信息,打印致命的日志时,最好也将程序调用堆栈的信息打印出来。
- 一个完整的日志模块应该可以:1)区分不同的级别,可以通过指定级别,将某个级别的日志输出到一个地方。这样可以灵活控制日志输出的量,以及只保留需要的日志信息,比如文件a.txt中只保留Error级别的日志。 2)区分不同的输出地,通过配置可以将一条日志输出到不同的输出地,比如,标准输出流、文件、syslog。 3)用户可以自行配置日志输出的格式 4)可以通过文件配置实现上述功能
2、设计目标 - 高性能:支持高并发环境下的日志记录,尽量减少对系统性能的影响。
- 灵活性:支持多种日志格式和日志级别,能够动态调整日志配置。
- 扩展性:易于扩展,支持自定义的日志输出方式(如文件、控制台、网络等)。
- 线程安全:在多线程环境下安全使用,避免日志记录的竞争条件。
3、框架中关键组件 - LogEvent 用来记录日志现场,比如该日志的级别,文件名/行号,日志消息,线程/协程号等。
- LogEventWrap 日志事件包装器,每条日志会创建一个对象,在析构函数中打印日志
- LogFormatter 日志格式器,每个appender中都会有一个LogFornatter,在程序开始的时候将输出日志的格式格式化好,放到m_items中,当用到的时候,直接调用对应方法输出日志。这个类中init函数解析字符串是重点,目前支持的配置如下:
%m 消息
%p 日志级别
%c 日志器名称
%d 日期时间,后面可跟一对括号指定时间格式,比如%d{%Y-%m-%d %H:%M:%S},这里的格式字符与C语言strftime一致
%r 该日志器创建后的累计运行毫秒数
%f 文件名
%l 行号
%t 线程id
%F 协程id
%N 线程名称
%% 百分号
%T 制表符
%n 换行
- LogAppender 日志输出地,负责将日志消息输出到不同的目标,可以是控制台、文件、远程服务器等。常见的Appender包括ConsoleAppender(控制台输出器)和FileAppender(文件输出器)。其中有一个log方法,输出日志的时候调用,log方法会去将event中的内容按照formatter的格式输出。
- Logger 日志器, 负责进行日志输出。一个Logger包含多个LogAppender和一个日志级别,提供log方法,传入日志事件,判断该日志事件的级别高于日志器本身的级别之后调用LogAppender将日志进行输出,否则该日志被抛弃。
- LogManager: 日志器管理类,单例模式,用于统一管理所有的日志器,提供日志器的创建与获取方法。LogManager自带一个root Logger,用于为日志模块提供一个初始可用的日志器。