【Linux C++】log4cpp日志库的安装和使用详解

log4cpp 是一个开源的 C++ 日志库,灵感来源于 Java 的 log4j。它提供了灵活的日志记录功能,可以帮助开发者在 C++ 应用程序中记录、管理和格式化日志信息。log4cpp 支持多种日志记录策略和输出目标,可以满足各种不同的需求。

1.安装

下载压缩包

下载地址:https://sourceforge.net/projects/log4cpp/files/

安装步骤

$ tar xzvf log4cpp-1.1.4rc3.tar.gz

$ cd log4cpp

$ ./configure  //进行自动化构建,自动生成makefile

$ make

$ sudo make install //安装  把头文件和库文件拷贝到系统路径下
    
//安装完后
//默认头文件路径:/usr/local/include/log4cpp
//默认lib库路径:/usr/local/lib

打开log4cpp官网:https://log4cpp.sourceforge.net/

拷贝simple example的内容,编译运行

#include "log4cpp/Category.hh"       // 引入 log4cpp 库的 Category 类
#include "log4cpp/Appender.hh"       // 引入 log4cpp 库的 Appender 基类
#include "log4cpp/FileAppender.hh"   // 引入 log4cpp 库的 FileAppender 类,用于将日志写入文件
#include "log4cpp/OstreamAppender.hh" // 引入 log4cpp 库的 OstreamAppender 类,用于将日志输出到流(如 std::cout)
#include "log4cpp/Layout.hh"          // 引入 log4cpp 库的 Layout 基类
#include "log4cpp/BasicLayout.hh"     // 引入 log4cpp 库的 BasicLayout 类,用于简单的布局格式
#include "log4cpp/Priority.hh"        // 引入 log4cpp 库的 Priority 类,用于设置日志优先级

int main(int argc, char** argv) {
    // 创建一个 OstreamAppender 对象,日志输出到标准输出流(std::cout)
    log4cpp::Appender *appender1 = new log4cpp::OstreamAppender("console", &std::cout);
    appender1->setLayout(new log4cpp::BasicLayout()); // 设置日志布局为 BasicLayout

    // 创建一个 FileAppender 对象,日志输出到文件 "program.log"
    log4cpp::Appender *appender2 = new log4cpp::FileAppender("default", "program.log");
    appender2->setLayout(new log4cpp::BasicLayout()); // 设置日志布局为 BasicLayout

    // 获取根日志类别并设置其优先级为 WARN(警告)
    log4cpp::Category& root = log4cpp::Category::getRoot();
    root.setPriority(log4cpp::Priority::WARN);
    root.addAppender(appender1); // 将 OstreamAppender 添加到根类别

    // 获取名为 "sub1" 的日志类别,并将 FileAppender 添加到该类别
    log4cpp::Category& sub1 = log4cpp::Category::getInstance(std::string("sub1"));
    sub1.addAppender(appender2);

    // 使用根类别记录错误和信息消息
    root.error("root error"); // 记录错误级别的日志,输出到 std::cout
    root.info("root info");  // 记录信息级别的日志,输出将被忽略(因根类别的优先级为 WARN)

    // 使用 "sub1" 类别记录错误和警告消息
    sub1.error("sub1 error"); // 记录错误级别的日志,输出到 "program.log"
    sub1.warn("sub1 warn");   // 记录警告级别的日志,输出到 "program.log"

    // 使用 printf 风格记录日志消息
    root.warn("%d + %d == %s ?", 1, 1, "two"); // 格式化日志消息并记录到 std::cout

    // 使用流的方式记录日志消息
    root << log4cpp::Priority::ERROR << "Streamed root error"; // 记录错误级别的日志,输出到 std::cout
    root << log4cpp::Priority::INFO << "Streamed root info";  // 记录信息级别的日志,输出将被忽略(因根类别的优先级为 WARN)
    sub1 << log4cpp::Priority::ERROR << "Streamed sub1 error"; // 记录错误级别的日志,输出到 "program.log"
    sub1 << log4cpp::Priority::WARN << "Streamed sub1 warn";  // 记录警告级别的日志,输出到 "program.log"

    // 使用 errorStream() 记录错误级别的日志消息
    root.errorStream() << "Another streamed error"; // 记录错误级别的日志,输出到 std::cout

    return 0; // 程序结束
}

编译指令:** g++ log4cppTest.cc -llog4cpp -lpthread**

可能报错:找不到动态库

解决方法:

cd /etc

sudo vim ld.so.conf

将默认的lib库路径写入,再重新加载

sudo ldconfig

让动态链接库为系统所共享

ld.so.cache 执行了sudo ldconfig之后,会更新该缓存文件,会将所有动态库信息写入到该文件。当可执行程序需要加载相应动态库时,会从这里查找。

完成这些操作后,再使用上面的编译指令去编译示例代码

2.日志系统的设计

日志系统的设计,一般而言要抓住最核心的一条,就是日志从产生到到达最终目的地期间的处理流程。一般而言,为了设计一个灵活可扩展,可配置的日志库,主要将日志库分为4个部分去设计,分别是:记录器、过滤器、格式化器、输出器四部分。

记录器(日志来源):负责产生日志记录的原始信息,比如(原始信息,日志优先级,时间,记录的位置)等等信息。

过滤器(日志系统优先级):负责按指定的过滤条件过滤掉我们不需要的日志。

格式化器(日志布局):负责对原始日志信息按照我们想要的格式去格式化。

输出器(日志目的地):负责将将要进行记录的日志(一般经过过滤器及格式化器的处理后)记录到日志目的地(例如:输出到文件中)。

下面以一条日志的生命周期为例说明日志库是怎么工作的。

一条日志的生命周期:

  1. 产生:info(“log information.”);

  2. 经过记录器,记录器去获取日志发生的时间、位置、线程信息等等信息;

  3. 经过过滤器,决定是否记录;

  4. 经过格式化器处理成设定格式后传递给输出器。例如输出“2018-3-22 10:00:00 [info] log information.”这样格式的日志到文件中。日志的输出格式由格式化器实现,输出目的地则由输出器决定;

  5. 这条日志信息生命结束。

3.log4cpp的核心组件

3.1日志目的地(Appender)

Appender 是 log4cpp 的核心组件之一,负责将日志消息输出到不同的目标,如控制台、文件、网络等。log4cpp 提供了多种类型的 Appender,允许你将日志信息输出到多种地方。

  • FileAppender:将日志消息写入文件。适合持久化日志记录。
  • OstreamAppender :C++通用输出流(如 cout)
  • ConsoleAppender:将日志消息输出到控制台。适用于调试和开发阶段。
  • SyslogAppender:将日志消息发送到系统日志服务。
  • RollingFileAppender:将日志写入文件,并支持日志文件的滚动,避免单个日志文件过大。

3.2日志布局(Layout)

Layout 定义了日志消息的格式。log4cpp 提供了不同类型的 Layout,用于格式化日志消息的输出内容。

  • PatternLayout:最常用的布局,允许自定义格式化模式。例如,可以指定时间戳、日志级别、日志消息等。
  • SimpleLayout:输出简洁的日志格式,通常只包含日志级别和消息。
  • XMLLayout:将日志消息格式化为 XML 格式,适用于需要结构化日志数据的场景。

注意(极易出错):

当日志系统有多个日志目的地时,每一个目的地Appender都需要设置一个布局Layout(一对一关系)

3.3日志记录器(Category)

Category 是日志记录的核心组件,代表一个日志记录器。它管理不同的 Appender 和日志级别。Category 提供了多种方法来记录日志,如 debuginfowarnerrorfatal

  • Root Category:系统默认的根日志记录器,所有日志记录都可以通过根记录器进行管理。
  • 子类 Category:可以创建子类记录器,用于更细粒度的日志记录和管理。

创建Category对象时,可以用getRoot先创建root模块对象,对root模块对象设置优先级和目的地;

再用getInstance创建叶模块对象,叶模块对象会继承root模块对象的优先级和目的地,可以再去修改优先级、目的地

补充:如果没有创建根对象,直接使用getInstance创建叶对象,会先隐式地创建一个Root对象。

子Category可以继承父Category的信息:优先级、目的地

3.4日志优先级(Priority)

对于 log4cpp 而言,有两个优先级需要注意,一个是日志记录器的优先级,另一个就是某一条日志的优先级。Category对象就是日志记录器,在使用时须设置好其优先级;某一行日志的优先级,就是Category对象在调用某一个日志记录函数时指定的级别,如 logger.debug("this is a debug message") ,这一条日志的优先级就是DEBUG级别的。简言之:

日志系统有一个优先级A,日志信息有一个优先级B

只有B高于或等于A的时候,这条日志才会被输出(或保存),当B低于A的时候,这条日志会被过滤;

class LOG4CPP_EXPORT Priority {
public:
	typedef enum {
			EMERG = 0,
			FATAL = 0,
			ALERT = 100,
			CRIT = 200,
			ERROR = 300,
			WARN = 400,
			NOTICE = 500,
			INFO = 600,
			DEBUG = 700,
			NOTSET = 800 //这个不代表可以使用的优先级
	} PriorityLevel;
	//......
};  //数值越小,优先级越高;数值越大,优先级越低

4.使用示例

4.1将日志输出到屏幕

#include <iostream>
#include <fstream>
#include <log4cpp/OstreamAppender.hh>
#include <log4cpp/PatternLayout.hh>
#include <log4cpp/Category.hh>
#include <log4cpp/Priority.hh>
using std::cout;
using std::endl;
using std::ofstream;
using namespace log4cpp;

void test0(){
    //1.创建布局对象
    PatternLayout * ptn1 = new PatternLayout();
    ptn1->setConversionPattern("%d %c [%p] %m%n");

    //2.创建目的地对象
    OstreamAppender* appender1 = new OstreamAppender("output",&cout);

    /* ofstream ofs("wd.log",std::ios::app); */
    /* OstreamAppender* appender1 = new OstreamAppender("output",&ofs); */
    //目的地绑定布局
    appender1->setLayout(ptn1);

    //3.创建记录器
    /* Category & sub1 = Category::getRoot(); */
    Category & sub1 = Category::getRoot().getInstance("sub1");
    //4.设置系统的优先级
    sub1.setPriority(Priority::WARN);
    //5.记录器添加目的地
    sub1.addAppender(appender1);

    //6.写日志
    sub1.emerg("this is an emerg msg");
    sub1.fatal("this is a fatal msg");
    sub1.alert("this is an alert msg");
    sub1.crit("this is a crit msg");
    sub1.error("this is an error msg");
    sub1.warn("this is a warn msg");
    sub1.notice("this is a notice msg");
    sub1.info("this is an info msg");
    sub1.debug("this is a debug msg");
    
    
    //7.关闭资源
    Category::shutdown();


}

int main(void){
    test0();
    return 0;
}

编译:g++ 01-log4cppPattern.cpp -llog4cpp -lpthread

4.2将日志输出到屏幕和保存到日志文件中

#include <iostream>
#include <log4cpp/OstreamAppender.hh>
#include <log4cpp/FileAppender.hh>
#include <log4cpp/PatternLayout.hh>
#include <log4cpp/Category.hh>
#include <log4cpp/Priority.hh>
using std::cout;
using std::endl;
using namespace log4cpp;

void test0(){
    //1.创建布局对象
    PatternLayout * ptn1 = new PatternLayout();
    ptn1->setConversionPattern("%d %c [%p] %m%n");

    PatternLayout * ptn2 = new PatternLayout();
    ptn2->setConversionPattern("%d %c [%p] %m%n");

    //2.创建目的地对象
    OstreamAppender* appender1 = new OstreamAppender("output",&cout);
    //目的地绑定布局
    appender1->setLayout(ptn1);

    FileAppender * appender2 = new FileAppender("fileApp","wd.log");
    appender2->setLayout(ptn2);//目的地与布局一对一进行绑定

    //3.创建记录器
    /* Category & sub1 = Category::getRoot(); */
    Category & sub1 = Category::getRoot().getInstance("sub1");
    //4.设置系统的优先级
    sub1.setPriority(Priority::WARN);
    //5.记录器添加目的地
    sub1.addAppender(appender1);
    sub1.addAppender(appender2);

    //6.写日志
    sub1.emerg("this is an emerg msg");
    sub1.fatal("this is a fatal msg");
    sub1.alert("this is an alert msg");
    sub1.crit("this is a crit msg");
    sub1.error("this is an error msg");
    sub1.warn("this is a warn msg");
    sub1.notice("this is a notice msg");
    sub1.info("this is an info msg");
    sub1.debug("this is a debug msg");
    
    //7.关闭资源
    Category::shutdown();
    
    //不要这样使用
    /* delete ptn1; */
}

int main(void){
    test0();
    return 0;
}

4.3将日志输出保存到回滚文件

#include <iostream>
#include <log4cpp/OstreamAppender.hh>
#include <log4cpp/FileAppender.hh>
#include <log4cpp/RollingFileAppender.hh>
#include <log4cpp/PatternLayout.hh>
#include <log4cpp/Category.hh>
#include <log4cpp/Priority.hh>
using std::cout;
using std::endl;
using namespace log4cpp;

void test0(){
    //1.创建布局对象
    PatternLayout * ptn1 = new PatternLayout();
    ptn1->setConversionPattern("%d %c [%p] %m%n");

    PatternLayout * ptn2 = new PatternLayout();
    ptn2->setConversionPattern("%d %c [%p] %m%n");

    PatternLayout * ptn3 = new PatternLayout();
    ptn3->setConversionPattern("%d %c [%p] %m%n");

    //2.创建目的地对象
    OstreamAppender* appender1 = new OstreamAppender("output",&cout);
    //目的地绑定布局
    appender1->setLayout(ptn1);

    FileAppender * appender2 = new FileAppender("fileApp","wd.log");
    appender2->setLayout(ptn2);//目的地与布局一对一进行绑定

    auto appender3 = new RollingFileAppender("rolling",
                                             "ROLL.log",
                                             5 * 1024,
                                             9); 
    appender3->setLayout(ptn3);



    //3.创建记录器
    /* Category & sub1 = Category::getRoot(); */
    Category & sub1 = Category::getRoot().getInstance("sub1");
    //4.设置系统的优先级
    sub1.setPriority(Priority::DEBUG);
    //5.记录器添加目的地
    sub1.addAppender(appender1);
    sub1.addAppender(appender2);
    sub1.addAppender(appender3);

    //6.写日志
    int count = 0;
    while(count < 30){
        sub1.emerg("this is an emerg msg");
        sub1.fatal("this is a fatal msg");
        sub1.alert("this is an alert msg");
        sub1.crit("this is a crit msg");
        sub1.error("this is an error msg");
        sub1.warn("this is a warn msg");
        sub1.notice("this is a notice msg");
        sub1.info("this is an info msg");
        sub1.debug("this is a debug msg");
        count++;
    }

    //7.关闭资源
    Category::shutdown();

    //不要这样使用
    /* delete ptn1; */
}

int main(void){
    test0();
    return 0;
}

4.4log4cpp配置文件读取

#include <log4cpp/Category.hh>          // 引入 log4cpp 库的 Category 类,用于日志记录
#include <log4cpp/PropertyConfigurator.hh> // 引入 log4cpp 库的 PropertyConfigurator 类,用于从配置文件中配置日志

int main(int argc, char* argv[])
{
    // 指定配置文件名,通常是 log4cpp 的配置文件
    std::string initFileName = "log4cpp.properties";
    
    // 从配置文件中配置 log4cpp 的日志系统
    log4cpp::PropertyConfigurator::configure(initFileName);

    // 获取根日志类别
    log4cpp::Category& root = log4cpp::Category::getRoot();

    // 获取名为 "sub1" 的日志类别
    log4cpp::Category& sub1 = 
        log4cpp::Category::getInstance(std::string("sub1"));

    // 获取名为 "sub1.sub2" 的日志类别
    log4cpp::Category& sub2 = 
        log4cpp::Category::getInstance(std::string("sub1.sub2"));

    // 使用根类别记录警告消息
    root.warn("Storm is coming");

    // 使用 "sub1" 类别记录调试和信息消息
    sub1.debug("Received storm warning");
    sub1.info("Closing all hatches");

    // 使用 "sub1.sub2" 类别记录调试和错误消息
    sub2.debug("Hiding solar panels");
    sub2.error("Solar panels are blocked");
    sub2.debug("Applying protective shield");
    sub2.warn("Unfolding protective shield");
    sub2.info("Solar panels are shielded");

    // 使用 "sub1" 类别记录信息消息
    sub1.info("All hatches closed");

    // 使用根类别记录信息消息
    root.info("Ready for storm.");

    // 关闭 log4cpp 日志系统
    log4cpp::Category::shutdown();

    return 0; // 程序结束
}
//log4cpp.properties
log4cpp.rootCategory=DEBUG, rootAppender
log4cpp.category.sub1=DEBUG, A1, A2
log4cpp.category.sub1.sub2=DEBUG, A3

log4cpp.appender.rootAppender=ConsoleAppender
log4cpp.appender.rootAppender.layout=PatternLayout
log4cpp.appender.rootAppender.layout.ConversionPattern=%d [%p] %m%n 

log4cpp.appender.A1=FileAppender
log4cpp.appender.A1.fileName=A1.log
log4cpp.appender.A1.layout=BasicLayout

log4cpp.appender.A2=FileAppender
log4cpp.appender.A2.threshold=WARN
log4cpp.appender.A2.fileName=A2.log
log4cpp.appender.A2.layout=PatternLayout
log4cpp.appender.A2.layout.ConversionPattern=%d [%p] %m%n 

log4cpp.appender.A3=RollingFileAppender
log4cpp.appender.A3.fileName=A3.log
log4cpp.appender.A3.maxFileSize=200
log4cpp.appender.A3.maxBackupIndex=1
log4cpp.appender.A3.layout=PatternLayout
log4cpp.appender.A3.layout.ConversionPattern=%d [%p] %m%n 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值