log4cpp进阶指南
📝 log4cpp进阶指南
1. 按天切割日志
log4cpp 默认是按文件大小来切割日志的。为了按天切割日志,通常需要自己进行时间判断并手动处理日志文件的切割。
1.1 解决方案
虽然 RollingFileAppender
只支持按大小切割,但你可以使用以下策略:
- 每天检查当前日期
- 如果日期变化了,重新生成新的日志文件
- 使用
log4cpp
来管理日志文件的输出
1.2 代码示例
#include <log4cpp/RollingFileAppender.hh>
#include <log4cpp/PatternLayout.hh>
#include <log4cpp/Category.hh>
#include <ctime>
#include <sstream>std::string getLogFileName() {time_t now = time(0);tm *ltm = localtime(&now);std::ostringstream oss;oss << "logs/mylog_" << 1900 + ltm->tm_year << "-"<< 1 + ltm->tm_mon << "-"<< ltm->tm_mday << ".log";return oss.str();
}int main() {auto layout = new log4cpp::PatternLayout();layout->setConversionPattern("[%d{%Y-%m-%d %H:%M:%S}] [%p] %c: %m%n");// 每天生成一个新的日志文件auto rollingFileAppender = new log4cpp::RollingFileAppender("RollingAppender",getLogFileName(), // 每天生成新文件5 * 1024 * 1024, // 最大5MB5 // 最多保留5个备份);rollingFileAppender->setLayout(layout);log4cpp::Category& root = log4cpp::Category::getRoot();root.setAppender(rollingFileAppender);root.setPriority(log4cpp::Priority::DEBUG);// 模拟日志记录for (int i = 0; i < 10000; ++i) {root.info("This is a test log message #" + std::to_string(i));}log4cpp::Category::shutdown();
}
说明:
getLogFileName()
函数使用当前日期来生成日志文件名,每天一个新的文件,例如:mylog_2025-04-27.log
。RollingFileAppender
管理按大小切割的文件,但它的文件名每次都会随着日期变化,因此实现了按天切割。
2. 保留最近7天的日志
如果你希望只保留最近7天的日志,可以在日志文件管理上进行一些额外操作。log4cpp 本身不支持直接按时间删除文件,但可以通过代码或系统脚本自动清理旧日志。
2.1 解决方案
- 让日志文件按天切割。
- 每次启动时检查日志文件夹,删除超过7天的日志。
2.2 代码示例
#include <log4cpp/RollingFileAppender.hh>
#include <log4cpp/PatternLayout.hh>
#include <log4cpp/Category.hh>
#include <ctime>
#include <sstream>
#include <dirent.h>
#include <unistd.h>
#include <iostream>// 获取日志文件名
std::string getLogFileName() {time_t now = time(0);tm *ltm = localtime(&now);std::ostringstream oss;oss << "logs/mylog_" << 1900 + ltm->tm_year << "-"<< 1 + ltm->tm_mon << "-"<< ltm->tm_mday << ".log";return oss.str();
}// 删除超过7天的日志文件
void cleanOldLogs() {DIR *dir = opendir("logs/");if (dir == nullptr) {std::cerr << "Failed to open logs directory." << std::endl;return;}struct dirent *entry;while ((entry = readdir(dir)) != nullptr) {std::string filename = entry->d_name;if (filename.find("mylog_") != std::string::npos) {// 假设日志文件名格式为 mylog_2025-04-27.log// 提取日期并检查是否超过7天std::string dateStr = filename.substr(6, 10); // 提取日期部分int year, month, day;sscanf(dateStr.c_str(), "%d-%d-%d", &year, &month, &day);// 检查文件日期与当前日期的差值time_t now = time(0);tm *ltm = localtime(&now);tm fileTime = {0};fileTime.tm_year = year - 1900;fileTime.tm_mon = month - 1;fileTime.tm_mday = day;time_t fileTimeT = mktime(&fileTime);double secondsDiff = difftime(now, fileTimeT);if (secondsDiff > 7 * 24 * 3600) { // 超过7天std::string filepath = "logs/" + filename;unlink(filepath.c_str()); // 删除文件std::cout << "Deleted old log: " << filename << std::endl;}}}closedir(dir);
}int main() {cleanOldLogs(); // 删除超过7天的日志auto layout = new log4cpp::PatternLayout();layout->setConversionPattern("[%d{%Y-%m-%d %H:%M:%S}] [%p] %c: %m%n");auto rollingFileAppender = new log4cpp::RollingFileAppender("RollingAppender",getLogFileName(), // 每天生成新文件5 * 1024 * 1024, // 最大5MB5 // 最多保留5个备份);rollingFileAppender->setLayout(layout);log4cpp::Category& root = log4cpp::Category::getRoot();root.setAppender(rollingFileAppender);root.setPriority(log4cpp::Priority::DEBUG);// 模拟日志记录for (int i = 0; i < 10000; ++i) {root.info("This is a test log message #" + std::to_string(i));}log4cpp::Category::shutdown();
}
说明:
cleanOldLogs()
函数会检查日志目录下的文件,如果文件日期超过7天,则删除该文件。- 可以根据实际需求调整删除规则,比如删除超过一定天数的日志。
3. 使用异步日志提升性能
在高负载情况下,日志写入可能会拖慢程序的速度。log4cpp 本身支持异步日志输出。你可以使用 AsyncAppender
来提升性能。
3.1 代码示例(异步Appender)
#include <log4cpp/AsyncAppender.hh>
#include <log4cpp/PatternLayout.hh>
#include <log4cpp/Category.hh>int main() {// 创建异步Appenderauto layout = new log4cpp::PatternLayout();layout->setConversionPattern("[%d{%Y-%m-%d %H:%M:%S}] [%p] %c: %m%n");auto asyncAppender = new log4cpp::AsyncAppender("AsyncAppender");asyncAppender->setLayout(layout);asyncAppender->setPriority(log4cpp::Priority::DEBUG);log4cpp::Category& root = log4cpp::Category::getRoot();root.setAppender(asyncAppender);root.setPriority(log4cpp::Priority::DEBUG);// 模拟日志记录for (int i = 0; i < 10000; ++i) {root.info("This is a test log message #" + std::to_string(i));}log4cpp::Category::shutdown();
}
说明:
AsyncAppender
会异步地将日志写入后台线程,从而避免阻塞主线程。
小结
- 按天切割日志:通过日期来决定日志文件名,每天生成一个新的日志文件。
- 只保留最近7天的日志:在日志文件夹中删除超过7天的日志。
- 异步日志:通过
AsyncAppender
提升日志写入性能,避免主线程被阻塞。