log4cpp日志库使用

2024-01-07 18:46:45

????????Log4cpp是一个开源的C++类库,它提供了C++程序中使用日志和跟踪调试的功能,它提供了应用程序运行上下文,方便跟踪调试;可扩展的、多种方式记录日志,包括命令行、文件、回卷文件、内存、syslog服务器、Win事件日志等;可以动态控制日志记录级别,在效率和功能中进行调整;所有配置可以通过配置文件进行动态调整;多语言支持,包括Java(log4j),C++(log4cpp、log4cplus),C(log4c),python(log4p)等;

1.源码下载

Log4cpp的主页为:Log library for C++ download | SourceForge.net

下载命令:wget https://nchc.dl.sourceforge.net/project/log4cpp/log4cpp-1.1.x%20%28new%29/log4cpp-1.1/log4cpp-1.1.3.tar.gz

2.Windows下源码编译

(1)打开mscv10文件夹,双击打开msvc10.sln文件

(2)配置管理器,选择Release x64

(3)log4cpp处右键属性,在预处理器定义处增加HAVE_SNPRINTF

(4)找到log4cpp下的NTEventLogCategories.mc右键属性,在命令行点击编辑

改为以下命令:

if not exist $(OutDir) md $(OutDir)
mc.exe -h $(OutDir) -r $(OutDir) $(ProjectDir)..\%(Filename).mc
RC.exe -r -fo $(OutDir)%(Filename).res $(OutDir)%(Filename).rc
link.exe /MACHINE:IX86 -dll -noentry -out:$(OutDir)NTEventLogAppender.dll $(OutDir)%(Filename).res

(5)倘若需编译log4cppLIB则需对log4cppLIB也执行以上2-5步操作,如需编译整个工程还需对testDailyRollingFileAppender下的testDailyRollingFileAppender.cpp的第43行增加一个空格,即由下图的1改为2

(6)在log4cpp处右键生成

(7)对log4cpp项目编译后生成的lib和dll文件在log4cpp\msvc10\x64\Release文件夹下

(8)Qt项目中加载log4cpp

  • 将log4cpp的头文件(include文件夹)拷贝到工程目录下
  • 将生成的log4cpp.lib库文件拷贝到工程目录下
  • 在Qt工程.pro文件中添加以下配置
LIBS += -L$$PWD/log4cpp/lib/ -llog4cpp

INCLUDEPATH += $$PWD/log4cpp/include
DEPENDPATH += $$PWD/log4cpp/include
  • 将生成的log4cpp.dll文件拷贝到工程生成目录下

PS:log4cpp在编译过程如果snprintf.c报错,可将snprintf.c移除后重新编译

3.linux下源码编译

1、编译

本地编译

./configure

交叉编译

./configure CC=aarch64-linux-gnu-gcc CXX=aarch64-linux-gnu-g++ --host=aarch64-linux-gnu --prefix=/home/xmr/log4cpp/build --with-pthreads

安装完成后,log4cpp.so库默认在/usr/local/lib下,头文件在/usr/local/include目录下。可通过该配置项修改为所描述的位置。

2、make

3、make check

4、make install

在程序运行时,依赖的动态库需要在执行时加入环境变量:

export LD_LIBRARY_PATH= $LD_LIBRARY_PATH:/usr/local/lib

4.log4cpp使用

log4cpp库中主要分三大类:Category(种类)、Appender(附加目的地)、Layout(布局)

  • category类是日志记录的主要执行类,相当于log4j中的Logger,它负责写日志,就是执行debug(Object msg)、info(Object msg)、warn(Object msg)、error(Object msg)等方法。
  • appender类用来指明目的地,即日志要写到什么地方去。log4cpp已经实现了多种不同目标的输出方式,可以向文件输出日志、向控制台输出日志、向Socket输出日志等。
  • layout类指明日志输出的格式

此外还有Priority(优先级)和NDC(嵌套的诊断上下文)等。

  • Priority被用来指定Category的优先级和日志的优先级
  • NDC则是一种用来区分不同场景中交替出现的日志的手段。

log4cpp记录日志的原理如下:

  • 每一个Category都有一个优先级,该优先级可以由setPriority方法设置,或者从其父Category中继承而来
  • 每条日志也有一个优先级,当Category记录该条日志时,如果日志优先级高于Category的优先级时,该日志被记录,否则被忽略

Category、Appender和Layout三者的关系如下:

  • 系统中可以有多个Category,它们都是继承自同一个根,每个Category负责记录自己的日志
  • 每个Category可以添加多个Appender,每个Appender指定了一个日志的目的地,比如文件、网络、终端
  • 当Category记录一条日志时,该复制被写入到所有附加到此Category的Appender
  • 每个Appender都包含一个Layout,该Layout定义了这个Appender上日志的格式

应用时的大概流程:

  • 定义一个layout类对象,确定输出日志信息的格式
  • 定义一个appender类对象,确定日志输出到什么地方,然后把layout对象用setlayout方法绑定一下
  • 定义一个category对象,与appender类对象绑定
  • 调用category对象进行写日志

简单使用:

#include "log4cpp/Category.hh"
#include "log4cpp/Appender.hh"
#include "log4cpp/OstreamAppender.hh"
#include "log4cpp/DailyRollingFileAppender.hh"
#include "log4cpp/FileAppender.hh"
#include "log4cpp/RollingFileAppender.hh"
#include "log4cpp/PropertyConfigurator.hh"
#include "log4cpp/PatternLayout.hh"
    
    //定义一个layout类对象,确定输出日志信息的格式
    log4cpp::Layout *lay = new log4cpp::SimpleLayout();
    
    //定义一个appender类对象,确定日志输出到什么地方,然后把layout对象用setlayout方法绑定一下
    log4cpp::Appender *appender = new log4cpp::FileAppender("FileAppender", "./log_name.log");
    appender->setLayout(lay);
    
    //定义一个category对象,与appender类对象绑定
    log4cpp::Category &category = log4cpp::Category::getRoot();
    category.setAppender(appender);

    //调用category对象进行写日志
    category.setPriority(log4cpp::Priority::INFO);
    category.info("Program info which cannot be wirten");
    category.debug("This debug message will fail to write");
    category.alert("Alert info");
    category.log(log4cpp::Priority::WARN, "This will be a logged warning");

    log4cpp::Category::shutdown();

(1)layout布局—日志输出格式

layout对象规定了日志输出的内容格式,创建后需要和append对象绑定生效。注意,一个布局仅能绑定一个appender对象。比较常用的布局有两种:log4cpp::BasicLayout和log4cpp::PatternLayout

  • log4cpp::BasicLayout是最简单的布局,输出时间戳,消息优先级和消息内容
  • log4cpp::PatternLayout布局支持通过类似print函数的格式控制符的方式自定义输出的信息和内容。通过如下函数进行设置:
log4cpp::PatternLayout::setConversionPattern (conststd::string& conversionPattern) ;

该函数接收的参数为格式控制字符串,其中符号含义如下:

 %c: 记录日志的category对象名称;
 %d: 日期;日期可以进一步的设置格式,用花括号包围,例如%d{%H:%M:%S,%l} 或者 %d{%d %m %Y%H:%M:%S,%l}。如果不设置具体日期格式,则如下默认格式被使用“Wed Jan 02 02:03:55 1980”。日期的格式符号与ANSI C函数strftime中的一致。但增加了一个格式符号%l,表示毫秒,占三个十进制位。
 %m: 要输出的日志消息字符串;
 %n: 换行符,会根据平台的不同而不同,但对于用户透明;
 %p: 优先级,warn,debug,info等待;
 %r: 自从layout被创建后的毫秒数;
 %R: 从1970年1月1日0时开始到目前为止的秒数;
 %u: 进程开始到目前为止的时钟周期数;
 %x: NDC

(2)Appender

append对象指定日志输出到什么地方去,创建后需要和category对象绑定才能生效。一个apender只能和一个category对象绑定,但是一个category对象可以有多个appnder,可以输出到多个位置。常用的appender类如下:

  • log4cpp::FileAppender // 输出到文件
  • log4cpp::RollingFileAppender // 输出到回卷文件,即当文件到达某个大小后回卷
  • log4cpp::OstreamAppender // 输出到一个ostream类
  • log4cpp::StringQueueAppender // 输出到内存队列
  • log4cpp::SyslogAppender // 本地syslog
  • log4cpp::RemoteSyslogAppender // 输出到远程syslog服务器

其中SyslogAppender和RemoteSyslogAppender需要与Syslog配合使用(Syslog是类Unix系统的一个核心服务,用来提供日志服务)

(3)Category

Log4cpp中有一个总是可用并实例化好的Category,即根Category。使用log4cpp::Category::getRoot()可以得到根Category。在大多数情况下,一个应用程序只需要一个日志种类(Category),但是有时也会用到多个Category,此时可以使用根Category的getInstance方法来得到子Category。不同的子Category用于不同的场合。

(4)利用配置文件定制日志

配置文件示例:

log4cpp.rootCategory=DEBUG,rootAppender
log4cpp.appender.rootAppender=RollingFileAppender
log4cpp.appender.rootAppender.fileName=amp.log
log4cpp.appender.rootAppender.maxFileSize=8388608
log4cpp.appender.rootAppender.maxBackupIndex=10
log4cpp.appender.rootAppender.layout=PatternLayout
log4cpp.appender.rootAppender.layout.ConversionPattern=%d{%Y-%m-%d %H:%M:%S,%l}: %p %c %x: %m%n

本配置文件完成个功能是:

1、输出DEBUG及以上级别的日志(值越小,优先级越高)

2、将日志输出到回滚日志文件中,主文件大小810241024字节,名字是amp.log,

3、备份文件10个(名字是amp.log.1,amp.log.2,amp.log.3,一直到amp.log.10,每个都是主文件大小+1KB,这是log4cpp规定的)

4、输出格式是:时间: 优先级 category名称 NDC名称: 消息 换行,其中时间是“年-月-日 时:分:秒,毫秒”格式

使用:

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

 try{
    log4cpp::PropertyConfigurator::configure("./log4cpp.conf");
}catch(log4cpp::ConfigureFailure& f){
    cout<<f.what()<<endl;
}

文章来源:https://blog.csdn.net/weixin_55238862/article/details/135442033
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。