
log4cpp 是一个基于 C 的开源日志库灵感来源于 Java 的 log4j提供了灵活的日志管理功能包括日志级别控制、多种输出目的地、日志格式自定义等。它特别适合中大型 C 项目能够满足复杂的日志需求。本文将详细介绍 log4cpp 的核心概念、使用方法和最佳实践。一、log4cpp 核心概念在使用 log4cpp 之前需要了解几个核心组件Category日志类别用于区分不同模块的日志类似日志的命名空间可以通过层次结构组织如root.category、root.category.net。Appender输出器定义日志的输出目的地如控制台、文件、网络等一个 Category 可以关联多个 Appender。Layout布局控制日志的输出格式如是否包含时间、日志级别、文件名、行号等信息。Priority优先级日志级别从高到低为FATAL、ALERT、CRIT、ERROR、WARN、NOTICE、INFO、DEBUG。二、安装 log4cpp1. Linux 系统安装12345# Ubuntu/Debiansudoapt-getinstallliblog4cpp5-dev# CentOS/RHEL需先配置 EPEL 源sudoyuminstalllog4cpp-devel2. 源码编译安装123456789# 下载源码wget https://downloads.sourceforge.net/project/log4cpp/log4cpp-1.1.x%20%28new%29/log4cpp-1.1.3/log4cpp-1.1.3.tar.gztarzxvf log4cpp-1.1.3.tar.gzcdlog4cpp-1.1.3# 编译安装./configure--prefix/usr/localmakesudomakeinstall三、log4cpp 基本使用示例下面是一个包含函数名、行号等信息的 log4cpp 入门示例1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798#include log4cpp/Category.hh#include log4cpp/PropertyConfigurator.hh#include log4cpp/Appender.hh#include log4cpp/FileAppender.hh#include log4cpp/OstreamAppender.hh#include log4cpp/Layout.hh#include log4cpp/PatternLayout.hh#include log4cpp/Priority.hh// 定义日志宏自动添加文件名、函数名和行号#define LOG_DEBUG(msg) \log4cpp::Category::getRoot() log4cpp::Priority::DEBUG [ __FILE__ : __LINE__ ] __func__ : msg#define LOG_INFO(msg) \log4cpp::Category::getRoot() log4cpp::Priority::INFO [ __FILE__ : __LINE__ ] __func__ : msg#define LOG_WARN(msg) \log4cpp::Category::getRoot() log4cpp::Priority::WARN [ __FILE__ : __LINE__ ] __func__ : msg#define LOG_ERROR(msg) \log4cpp::Category::getRoot() log4cpp::Priority::ERROR [ __FILE__ : __LINE__ ] __func__ : msg#define LOG_FATAL(msg) \log4cpp::Category::getRoot() log4cpp::Priority::FATAL [ __FILE__ : __LINE__ ] __func__ : msg// 带格式化输出的日志宏#define LOG_DEBUG_F(fmt, ...) \do{ \charbuffer[1024]; \snprintf(buffer,sizeof(buffer), fmt, ##__VA_ARGS__); \LOG_DEBUG(buffer); \}while(0)#define LOG_INFO_F(fmt, ...) \do{ \charbuffer[1024]; \snprintf(buffer,sizeof(buffer), fmt, ##__VA_ARGS__); \LOG_INFO(buffer); \}while(0)// 初始化日志配置voidinitLog() {// 创建控制台输出器log4cpp::Appender* consoleAppender newlog4cpp::OstreamAppender(console, std::cout);// 创建文件输出器log4cpp::Appender* fileAppender newlog4cpp::FileAppender(file,app.log);// 创建布局设置日志格式log4cpp::PatternLayout* layout newlog4cpp::PatternLayout();// 格式说明%d-日期 %p-优先级 %c-类别 %m-消息 %n-换行layout-setConversionPattern(%d{%Y-%m-%d %H:%M:%S} %p %c %m%n);// 为输出器设置布局consoleAppender-setLayout(layout);fileAppender-setLayout(layout);// 获取根日志类别并添加输出器log4cpp::Category root log4cpp::Category::getRoot();root.addAppender(consoleAppender);root.addAppender(fileAppender);// 设置根日志的优先级低于此级别的日志不输出root.setPriority(log4cpp::Priority::DEBUG);}// 测试函数voidtestLogFunction(intvalue) {LOG_DEBUG(进入测试函数);LOG_INFO_F(参数值为: %d, value);if(value 0) {LOG_WARN(参数值为负数);}if(value 0) {LOG_ERROR(参数值不能为零);}}intmain() {// 初始化日志initLog();LOG_INFO(程序启动);// 测试日志输出testLogFunction(10);testLogFunction(-5);testLogFunction(0);LOG_INFO(程序退出);// 清理日志资源log4cpp::Category::shutdown();return0;}编译与运行编译时需要链接 log4cpp 库12g log4cpp_demo.cpp -o log_demo -llog4cpp -lpthread./log_demo运行后会生成app.log文件同时在控制台输出日志典型输出如下2024-09-15 10:30:00 INFO root [log4cpp_demo.cpp:66] main: 程序启动2024-09-15 10:30:00 DEBUG root [log4cpp_demo.cpp:59] testLogFunction: 进入测试函数2024-09-15 10:30:00 INFO root [log4cpp_demo.cpp:60] testLogFunction: 参数值为: 102024-09-15 10:30:00 DEBUG root [log4cpp_demo.cpp:59] testLogFunction: 进入测试函数2024-09-15 10:30:00 INFO root [log4cpp_demo.cpp:60] testLogFunction: 参数值为: -52024-09-15 10:30:00 WARN root [log4cpp_demo.cpp:62] testLogFunction: 参数值为负数2024-09-15 10:30:00 DEBUG root [log4cpp_demo.cpp:59] testLogFunction: 进入测试函数2024-09-15 10:30:00 INFO root [log4cpp_demo.cpp:60] testLogFunction: 参数值为: 02024-09-15 10:30:00 ERROR root [log4cpp_demo.cpp:65] testLogFunction: 参数值不能为零2024-09-15 10:30:00 INFO root [log4cpp_demo.cpp:70] main: 程序退出四、通过配置文件使用 log4cpp对于复杂项目推荐使用配置文件来管理 log4cpp 配置这样可以在不修改代码的情况下调整日志行为。1. 配置文件log4cpp.properties123456789101112131415161718192021# 根日志类别设置log4cpp.rootCategoryDEBUG, console, file# 控制台输出器配置log4cpp.appender.consoleorg.apache.log4j.ConsoleAppenderlog4cpp.appender.console.layoutorg.apache.log4j.PatternLayoutlog4cpp.appender.console.layout.ConversionPattern%d{%Y-%m-%d %H:%M:%S} %p %c %m%n# 文件输出器配置log4cpp.appender.fileorg.apache.log4j.FileAppenderlog4cpp.appender.file.fileNameapp.loglog4cpp.appender.file.layoutorg.apache.log4j.PatternLayoutlog4cpp.appender.file.layout.ConversionPattern%d{%Y-%m-%d %H:%M:%S} %p %c [%-20F:%-4L] %-20M %m%n# 模块特定日志配置例如网络模块log4cpp.category.netINFO, netfilelog4cpp.additivity.netfalselog4cpp.appender.netfileorg.apache.log4j.FileAppenderlog4cpp.appender.netfile.fileNamenet.loglog4cpp.appender.netfile.layoutorg.apache.log4j.PatternLayoutlog4cpp.appender.netfile.layout.ConversionPattern%d %p %m%n2. 使用配置文件的代码12345678910111213141516171819202122232425262728#include log4cpp/Category.hh#include log4cpp/PropertyConfigurator.hh// 日志宏定义同上// ...intmain() {try{// 通过配置文件初始化log4cpp::PropertyConfigurator::configure(log4cpp.properties);}catch(log4cpp::ConfigureFailure f) {std::cerr 配置文件加载失败: f.what() std::endl;return1;}// 获取根日志类别log4cpp::Category root log4cpp::Category::getRoot();root.info(程序启动);// 获取网络模块日志类别log4cpp::Category netCat log4cpp::Category::getInstance(net);netCat.info(网络连接建立);// ... 其他日志输出log4cpp::Category::shutdown();return0;}五、log4cpp 高级特性1. 日志滚动RollingFileAppender当日志文件达到一定大小后自动创建新文件123// 在代码中配置log4cpp::RollingFileAppender* rollingAppender newlog4cpp::RollingFileAppender(rolling,rolling.log, 1024*1024, 5);// 1MB 每个最多 5 个文件或在配置文件中1234log4cpp.appender.rollingorg.apache.log4j.RollingFileAppenderlog4cpp.appender.rolling.fileNamerolling.loglog4cpp.appender.rolling.maxFileSize1048576log4cpp.appender.rolling.maxBackupIndex52. 每日滚动日志DailyRollingFileAppender按时间自动切割日志如每天生成一个新日志文件123log4cpp.appender.dailyorg.apache.log4j.DailyRollingFileAppenderlog4cpp.appender.daily.fileNamedaily.loglog4cpp.appender.daily.datePattern.yyyy-MM-dd3. 日志级别控制可以为不同的日志类别设置不同的级别例如开发环境输出 DEBUG 级别生产环境只输出 INFO 及以上级别123// 代码中设置log4cpp::Category::getRoot().setPriority(log4cpp::Priority::INFO);log4cpp::Category::getInstance(debug.module).setPriority(log4cpp::Priority::DEBUG);六、最佳实践使用宏封装日志调用如示例中定义的LOG_DEBUG、LOG_INFO等宏自动添加文件名、函数名和行号信息。合理设置日志级别DEBUG开发调试信息生产环境通常关闭INFO正常运行状态信息WARN需要注意的异常情况但不影响程序运行ERROR错误信息可能影响部分功能FATAL致命错误程序可能无法继续运行按模块划分日志类别如net、db、ui等便于日志过滤和分析。避免在日志中输出敏感信息如密码、个人信息等。注意日志性能避免在高频调用的函数中输出大量 DEBUG 日志复杂格式化操作可以先判断日志级别再执行及时清理日志配置日志滚动或定时清理机制避免磁盘空间耗尽。