Log4cxx按小时滚动文件未生成对应文件夹问题求助
问题分析与解决方案
首先,你的核心问题出在对DailyRollingFileAppender的datePattern属性理解有误,再加上log4cxx的这个Appender本身不会自动创建多级目录结构,导致没有生成你期望的小时级文件夹。
错误点拆解
datePattern的用途误解:这个参数是用来定义日志文件名的时间后缀,而非路径中的目录结构。你把完整的路径模板(包含%Y%m%d\\%H\\)传给它,Appender无法识别路径中的变量,自然不会创建对应的目录。- 缺少目录预创建逻辑:log4cxx的所有Appender都不会自动递归创建多级目录,必须确保目标目录存在后,才能成功写入日志文件。
- 未触发日志写入:你的测试代码只是初始化了Appender,但没有实际输出日志,Appender只有在首次写入日志时才会尝试创建文件(前提是目录存在)。
修复步骤
下面是针对你的需求的具体解决方案:
1. 编写目录自动创建逻辑
在初始化Appender之前,先根据当前时间生成目标目录,并递归创建所有父目录。Windows下可以用CreateDirectoryW(需要包含<windows.h>),或者用C++17及以上的std::filesystem更简洁:
#include <filesystem> #include <ctime> // 生成当前时间对应的目录路径 std::wstring getCurrentLogDir() { time_t now = time(nullptr); tm localTime{}; localtime_s(&localTime, &now); // Windows下安全的本地时间获取函数 wchar_t dirBuf[100]; swprintf_s(dirBuf, L"D:\\LogFolder\\Log4cxx_2019_Test\\%04d%02d%02d\\%02d", localTime.tm_year + 1900, localTime.tm_mon + 1, localTime.tm_mday, localTime.tm_hour); return std::wstring(dirBuf); } // 递归创建目录 void createLogDir(const std::wstring& dirPath) { std::filesystem::create_directories(dirPath); // C++17及以上支持 // 如果用C++17之前的版本,可以用Windows API递归创建: // size_t pos = 0; // do { // pos = dirPath.find(L'\\', pos + 1); // CreateDirectoryW(dirPath.substr(0, pos).c_str(), nullptr); // } while (pos != std::wstring::npos); }
2. 正确配置DailyRollingFileAppender
调整datePattern为文件名后缀,将完整路径拆分为固定目录路径+文件名,确保Appender指向已创建的目录:
// 获取并创建当前小时的日志目录 std::wstring logDir = getCurrentLogDir(); createLogDir(logDir); // 拼接完整的日志文件路径 std::wstring logFilePath = logDir + L"\\test.log"; // 初始化Appender log4cxx::DailyRollingFileAppenderPtr debugRollingFileAppender1(new log4cxx::DailyRollingFileAppender()); // datePattern设置为文件名的小时后缀,每小时生成test.14.log、test.15.log等 debugRollingFileAppender1->setFile(logFilePath); debugRollingFileAppender1->setDatePattern(LOG4CXX_STR(".HH")); // 后续的Layout、Level配置保持不变 log4cxx::helpers::Pool pool; log4cxx::PatternLayoutPtr debugLayout(new log4cxx::PatternLayout()); debugLayout->setConversionPattern(LOG4CXX_STR("%d [%t] %5p %m%n")); debugRollingFileAppender1->setLayout(debugLayout); debugRollingFileAppender1->activateOptions(pool); LoggerPtr logger = Logger::getLogger(_T("LogInfo")); logger->addAppender(debugRollingFileAppender1); logger->setLevel(Level::getInfo()); // 必须写入日志才能触发文件/目录创建 LOG4CXX_INFO(logger, "First test log message");
3. 处理跨小时的日志切换(可选)
如果希望程序运行过程中跨小时时自动切换到新的小时目录,你需要定时检查当前时间,并在小时变化时重新初始化Appender。可以用一个定时器线程,每小时触发一次Appender的重建逻辑(关闭旧Appender,创建新目录和新Appender,重新绑定到Logger)。
额外注意事项
- 确保你的项目启用了C++17(如果使用
std::filesystem),或者用Windows API实现目录创建。 - Windows下log4cxx默认使用宽字符,直接使用
std::wstring传递路径能避免字符编码转换问题。 - 测试时必须写入至少一条日志,否则Appender不会触发文件创建逻辑。
内容的提问来源于stack exchange,提问作者SomGG
相关产品推荐
相关产品推荐

