跨平台 日志库 log4cpp :使用指南

1.log4cpp日志介绍

log4cplus 是一个灵活的日志库,不仅仅可以跨平台,功能强大,受到了 Java 的 log4j 库的启发,并为 C++ 设计。它提供了丰富的日志级别、日志格式和输出目标的配置选项,使得开发者能够根据应用程序的需要灵活地记录信息。

2.特点

    灵活性:log4cplus 提供了多种日志级别和输出选项,支持异步和同步日志记录。
    易用性:它的 API 简单直观,易于集成到现有项目中。
    可配置性:可以通过配置文件或编程方式配置日志行为。

3 log4cplus 的底层原理

log4cplus 的工作原理基于几个核心组件:记录器(Logger)、布局(Layout)和附加器(Appender)。记录器负责生成日志消息,布局负责格式化日志消息,附加器负责将格式化后的消息输出到不同的目标。

3.1 记录器

记录器是日志系统的入口点,开发者通过记录器记录消息。每个记录器都有一个名字和日志级别,只有当消息的级别高于或等于记录器的级别时,消息才会被记录。

3.2 布局

布局负责将日志消息转换为字符串,并按照特定的格式输出。log4cplus 提供了多种内置的布局,如简单布局、模式布局等。

3.3 附加器

附加器定义了日志消息的输出目标。常见的附加器有控制台附加器、文件附加器等。开发者可以根据需要配置一个或多个附加器。

3.4 log4cplus 的性能特点

log4cplus 的性能受到多种因素的影响,包括日志级别、输出目标和日志消息的复杂性。一般来说,异步日志记录的性能要优于同步日志记录。

3.4.1 日志级别

日志级别越高,记录的消息越少,性能越好。在生产环境中,建议将日志级别设置得较高,以提高性能。

3.4.2 输出目标

将日志消息输出到控制台通常比输出到文件要慢。如果对性能有较高要求,建议将日志消息输出到内存或网络。

3.4.3 异步日志记录

log4cplus 支持异步日志记录,这可以显著提高性能,特别是在高负载环境下。

3.5 log4cplus 的输出控制

log4cplus 提供了丰富的配置选项,允许开发者灵活地控制日志输出。

3.5.1 配置文件

开发者可以通过配置文件来设置日志级别、布局和附加器,实现灵活的输出控制。

3.5.2 编程方式配置

除了配置文件,log4cplus 也允许开发者通过编程方式来配置日志系统。

4. log4cplus 具体使用

4.1 下载

https://sourceforge.net/projects/log4cpp/files/latest/downloa

4.2、log4cpp日志级别

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

在使⽤⽇志库的时候要注意不同⽇志库的级别有差异,⽐如有些⽇志库 DEBUG和INFO的级别是反过来 的。

4.3、log4cpp日志格式化

一般日志输出时会携带一些关注的信息,比如

20210410 14:18:15.299684Z 30836 INFO NO.1506710 Root Error Message! - log_test.cpp:17

格式包含:年月日 时分秒 微妙 时区 日志级别 日志内容 文件名 行号。

比如Log4cpp支持的转义定义:
◼ %% - 转义字符’%’
◼ %c - Category
◼ %d - 日期;日期可以进一步设置格式,用花括号包围,例如%d{%H:%M:%S,%l}。日期的格式符号与ANSI C函数strftime中的一致。但增加了一个格式符号%l,表示毫秒,占三个十进制位。
◼ %m - 消息
◼ %n - 换行符;会根据平台的不同而不同,但对用户透明。
◼ %p - 优先级
◼ %r - 自从layout被创建后的毫秒数
◼ %R - 从1970年1月1日开始到目前为止的秒数
◼ %u - 进程开始到目前为止的时钟周期数
◼ %x - NDC
◼ %t - 线程id

4.4、log4cpp日志Loyout

log4cpp支持的日志布局有:

(1)BasicLayout::format。 基本布局。它会为你添加“时间”、“优先级”、“种类”、“NDC”。相当于PatternLayout格式化为:“%R %p %c %x: %m%n”。

(2) PassThroughLayout::format。 直通布局。顾名思义,这个就是没有布局的“布局”,你让它写什么它就写什么,它不会为你添加任何东西,连换行符都懒得为你加。但是,它支持自定义的布局,我们可以继承他实现自定义的日志格式。

(3) PatternLayout::format log4cpp。 格式化布局,支持用户配置日志格式。它的使用方式类似C语言中的printf,使用格式化它符串来描述输出格式;目前支持的转义定义。

(4) SimpleLayout::format 。 简单布局。比BasicLayout还简单的日志格式输出,它只会为你添加“优先级”的输出。相当于PatternLayout格式化为:“%p: %m%n”。

4.5、log4cpp日志输出

日志有不同的输出方式,以log4cpp为例: (1)日志输出到控制台。ConsoleAppender。 (2)日志输出到本地文件。FileAppender,值得注意的是,log4cpp使用write()来输出到文件,这种方式的性能不会太高i,因为要频繁的切换用户态和内核态。这是一个可以优化的地方。 (3)日志通过网络传输到远程服务器。RemoteSyslogAppender。

4.6、log4cpp日志回滚

日志库一般都具备如下功能: (1)本地日志支持最大文件限制。 (2)当本地日志达到最大文件限制的时候新建一个文件。 (3)每天至少一个文件。

比如log4cpp里的RollingFileAppender()。

RollingFileAppender(
	const std::string& name,
	const std::string& filename,
	size_t maxFileSize=10*1024*1024//日志文件支持最大的大小
	unsigned int maxBackupIndex=1,//最大生成文件数量
	bool append=true,// 是否以追加的方式写入
	mode_t mode = 00644
);

4.7、log4cpp日志配置

成熟的日志文件要支持配置文件,通过修改配置文件来改变日志输出方式而不需要修改代码。
比如log4cpp日志配置:

#指定rootCategory的log优先级是ERROR,其Appenders有两个,分别是console,TESTAppender
log4cpp.rootCategory=ERROR, console,TESTAppender

#-------定义console属性-------

#consoleAppender类型:控制台输出
#下面这三条语句表示控制台输出的log输出的布局按照指定的格式;输出格式是:[%p] %d{%H:%M:%S.%l} (%c): %m%n
log4cpp.appender.console=ConsoleAppender
log4cpp.appender.console.layout=PatternLayout
log4cpp.appender.console.layout.ConversionPattern=[%p] %d{%H:%M:%S.%l} (%c): %m%n
 
#-------定义TESTAppender的属性-------

#RollingFileAppender类型:输出到回卷文件,即文件到达某个大小的时候产生一个新的文件
#下面的语句表示文件输出到指定的log文件,输出的布局按照指定的格式,输出的格式是:[%d{%Y-%m-%d %H:%M:%S.%l} - %p] (%c): %m%n
log4cpp.appender.TESTAppender=RollingFileAppender
 
#当日志文件到达maxFileSize大小时,将会自动滚动
log4cpp.appender.TESTAppender.maxFileSize=400000
 
#maxBackupIndex指定可以产生的滚动文件的最大数
log4cpp.appender.TESTAppender.maxBackupIndex=3

#fileName指定信息输出到logs/TESTAppender.txt文件
log4cpp.appender.TESTAppender.fileName=logs/TESTAppender.txt

#PatternLayout 表示可以灵活指定布局模式
log4cpp.appender.TESTAppender.layout=PatternLayout
 
#append=true 信息追加到上面指定的日志文件中,false表示将信息覆盖指定文件内容
log4cpp.appender.TESTAppender.append=true
log4cpp.appender.TESTAppender.layout.ConversionPattern=[%d{%Y-%m-%d %H:%M:%S.%l} - %p] (%c): %m%n 

ConversionPattern的参数含义:

%d 输出日志时间点的日期或时间,可以在其后指定格式,如上%d{%Y-%m-%d %H:%M:%S.%l},输出类似:2017-02-14 09:25:00.953
%p 优先级,即DEBUG,INFO,WARN,ERROR,FATAL
%c 输出日志信息所属的类目,通常就是所在类的全名
%m 输出log的具体信息
%n 回车换行

 

读取配置文件示例代码:

#include "log4cpp/Category.hh"
#include "log4cpp/PropertyConfigurator.hh"

int main(int argc,char *argv[])
{
	//读取解析配置文件
	try
	{
		log4cpp::PropertyConfigurator::configure("./log4cpp.conf");
	}
	catch (log4cpp::ConfigureFailure &f)
    {
        std::cout << "Configure Problem " << f.what() << std::endl;
        return -1;
    }
    // 实例化category对象
    log4cpp::Category &root = log4cpp::Category::getRoot();

    // 正常使用这些category对象进行日志处理。
    root.debug("root debug");
    root.info("root info");
    root.notice("root notice");
    root.warn("root warn");
    root.error("root error");
    root.crit("root crit");
    root.alert("root alert");
    root.fatal("root fatal");
    root.emerg("root emerg");

    // ...

	// clean up and flush all appenders
	log4cpp::Category::shutdown();
	
	return 0;
}

 主要分为几个步骤: (1) 读取解析配置文件。读取出错, 完全可以忽略,可以定义一个缺省策略或者使用系统缺省策略。 (2)2 实例化category对象。这些对象即使配置文件没有定义也可以使用,不过其属性继承其父category;通常使用引用可能不太方便,可以使用指针,以后做指针使用。 (3)使用这些category对象进行日志处理。 (4)清理并刷新所有的appenders。

5、Log4cpp日志回滚

数字越大,数据越久。 当文件内容和文件数据都达到设定的阈值时,会执行如下操作(假如设置了最大文件数是5): 

(1)删除数字最大的文件。删除log5.txt。 

(2)文件重命名。

(3)新建log文件。

6、log4cpp日志性能分析

(1)实时写入磁盘 单笔 write。 多行(100行)日记累积再写入 -> 累积了99行,下一行一直不来。 a.单独起一个定时器(比如1秒)去刷新。 b.同一个日志管理线程去刷新数据。 注:实际glog他是累积一定的行数或者过了一定的时间间隔就让刷新。

(2) 回滚日志每次都取读取日志文件大小 肯定不能每次读取文件大小。

6.1、FileAppender优化

异步日志,从批量写入和超时方向的考量。

日志落盘线程,比如超过100条写入磁盘、超时一秒钟写入磁盘。

6.2、FileAppender改进之glog同步日志线程

glog日志线程逻辑相对简单。 (1)积累一定数量日志再写入。 (2)超时写入。比如,第一条日志1秒的时候写入;第二条日志3秒的时候写入。跟上一次刷新超过一定的时间,也会把所有的缓存日志刷新磁盘中。

这种方式支持批量写入,但不是最好的解决方案。

7、总结

通过剖析log4cpp日志库的日志框架,可以清晰一个成熟的、完善的日志框架应该支持:

(1)日志级别。 (2)日志格式化。 (3)日志输出方式。 (4)日志回滚。 (5)日志配置文件。

注意:

(1)日志的树状模块输出。 (2)支持多种输出方式,每种输出方式都可以有不同的格式化。 (3)log4cpp代码结构组织。

(4)不要直接把log4cpp用在服务器中,因为log4cpp的性能稍差

跨平台 日志库 log4cpp :使用指南_第1张图片

你可能感兴趣的:(C/C++,java,前端,开发语言)