log4cxx的RollingFileAppender模式可以设置MaxBackupIndex属性,来限制日志文件的数量,但是,DailyRollingFileAppender模式没有这个属性,无法限制日志文件数量,使用很不方便。所以我给DailyRollingFileAppender增加了一个属性MaxBackupDays,这个属性表示最多可以保留最近多长一段时间的日志,比如最多保留最近3天的日志,超过3天的日志自动删除。
实现的主要思想是,当log4cxx在rollover时,搜索日志目录下的所有日志文件,如果日志文件的修改时间和当前时间之差超过MaxBackupDays天数,则删除该日志文件。搜索的关键字是File属性中的文件名,因此使用者必须保证这个文件名被所有日志文件所包含,并且其他文件不能包含这个文件名。
实现的关键函数是deleteOldFiles,修改的代码如下所示,最后还有一个.properties配置文件:
-- timebasedrollingpolicy.h --
class LOG4CXX_EXPORT TimeBasedRollingPolicy : public RollingPolicyBase,
public TriggeringPolicy {
...
private:
//日志最大保存天数
int maxBackupDays; //add by pengliqing
//add by pengliqing
void deleteOldFiles(const LogString& currentActiveFile);
LogString extractFileDir(const LogString& In);
LogString extractFileName(const LogString& In);
...
public:
//add by pengliqing
void setMaxBackupDays(int newVal);
...
};
-- timebasedrollingpolicy.cpp --
TimeBasedRollingPolicy::TimeBasedRollingPolicy()
: maxBackupDays(0)
{
}
RolloverDescriptionPtr TimeBasedRollingPolicy::rollover(
const LogString& currentActiveFile,
Pool& pool) {
...
//
// if file names haven't changed, no rollover
//
if (newFileName == lastFileName) {
RolloverDescriptionPtr desc;
return desc;
}
//只保存最近MaxBackupIndex天数的日志文件
deleteOldFiles(currentActiveFile);
...
}
void TimeBasedRollingPolicy::setMaxBackupDays(int newVal)
{
maxBackupDays = newVal;
}
void TimeBasedRollingPolicy::deleteOldFiles(const LogString& currentActiveFile)
{
if (maxBackupDays <= 0)
{
return;
}
if (currentActiveFile.size() == 0)
{
return;
}
#ifdef WIN32
//将要删除的文件列表
std::vector<LogString> aryDelFiles;
//获取当前日志文件的文件名和目录名
LogString curLogFileName=extractFileName(currentActiveFile);
LogString curLogFileDir=extractFileDir(currentActiveFile);
//获取当前时间
SYSTEMTIME curTimeSys;
GetSystemTime(&curTimeSys);
FILETIME curTimeFSys;
SystemTimeToFileTime(&curTimeSys, &curTimeFSys);
ULARGE_INTEGER curTimeUL;
curTimeUL.LowPart = curTimeFSys.dwLowDateTime;
curTimeUL.HighPart = curTimeFSys.dwHighDateTime;
//生成搜索文件关键字
LogString searchKey=curLogFileDir + L"*" + curLogFileName + L"*";
WIN32_FIND_DATAW FileData;
HANDLE hSearch;
//开始搜索日志文件
hSearch = FindFirstFileW(searchKey.c_str(), &FileData);
if (hSearch != INVALID_HANDLE_VALUE)
{
do
{
LogString strFindFile = FileData.cFileName;
if (strFindFile != curLogFileName) //不包括当前的日志文件
{
LogString::size_type pos = strFindFile.find(curLogFileName.c_str());
if (pos != LogString::npos)
{
//找到一个日志文件
ULARGE_INTEGER fileTimeUL;
fileTimeUL.LowPart = FileData.ftLastWriteTime.dwLowDateTime;
fileTimeUL.HighPart = FileData.ftLastWriteTime.dwHighDateTime;
//把文件修改时间和当前时间比较, 是否超过天数maxBackupDays
if (curTimeUL.QuadPart > fileTimeUL.QuadPart &&
(curTimeUL.QuadPart-fileTimeUL.QuadPart)/10000000 > maxBackupDays*24*3600)
{
aryDelFiles.push_back(curLogFileDir+strFindFile);
}
}
}
}
while(FindNextFileW(hSearch, &FileData));
}
// Close the search handle.
FindClose(hSearch);
//删除文件
for (int i=0; i<aryDelFiles.size(); i++)
{
DeleteFileW(aryDelFiles[i].c_str());
}
#endif
}
LogString TimeBasedRollingPolicy::extractFileDir(const LogString& In)
{
LogString strtemp = In;
for (int i=strtemp.size()-1; i>=0; i--)
{
if ( strtemp[i] == L'\\' || strtemp[i] == L'/' )
{
strtemp.erase(i+1);
return(strtemp);
}
}
return (L"");
}
LogString TimeBasedRollingPolicy::extractFileName(const LogString& In)
{
const LogString& strtemp = In;
for (int i=strtemp.size()-1; i>=0; i--)
{
if ( strtemp[i] == L'\\' || strtemp[i] == L'/' )
{
return strtemp.substr(i+1);
}
}
return(strtemp);
}
-- dailyrollingfileappender.h --
class LOG4CXX_EXPORT DailyRollingFileAppender : public log4cxx::rolling::RollingFileAppenderSkeleton {
...
private:
//日志最大保存天数
int maxBackupDays; //add by pengliqing
...
};
-- dailyrollingfileappender.cpp --
DailyRollingFileAppender::DailyRollingFileAppender()
: maxBackupDays(0)
{
}
DailyRollingFileAppender::DailyRollingFileAppender(
const LayoutPtr& layout,
const LogString& filename,
const LogString& datePattern1)
: datePattern(datePattern1),
maxBackupDays(0)
{
...
}
void DailyRollingFileAppender::activateOptions(log4cxx::helpers::Pool& pool) {
...
policy->setFileNamePattern(pattern);
policy->setMaxBackupDays(maxBackupDays); //add by pengliqing
policy->activateOptions(pool);
setTriggeringPolicy(policy);
setRollingPolicy(policy);
...
}
void DailyRollingFileAppender::setOption(const LogString& option,
const LogString& value) {
if (StringHelper::equalsIgnoreCase(option,
LOG4CXX_STR("DATEPATTERN"), LOG4CXX_STR("datepattern"))) {
setDatePattern(value);
} else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("MAXBACKUPDAYS"), LOG4CXX_STR("maxbackupdays"))) { //add by pengliqing
maxBackupDays = StringHelper::toInt(value);
} else {
RollingFileAppenderSkeleton::setOption(option, value);
}
}
-- log4cxx.properties --
log4j.rootLogger=debug,S
#S
log4j.appender.S=org.apache.log4j.DailyRollingFileAppender
log4j.appender.S.File=./hello.log
log4j.appender.S.DatePattern = '.'yyyy-MM-dd
#add by pengliqing
log4j.appender.S.MaxBackupDays=4
log4j.appender.S.layout=org.apache.log4j.PatternLayout
log4j.appender.S.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss}] [%5p] [%c] - %m%n