Easylogging++ 日志文件滚动

按大小滚动文件

    在Easylogging++中,已经实现了按照日志文件大小来滚动日志记录。有一个配置项:MAX_LOG_FILE_SIZE,这个配置项的值(以字节为单位)表示的就是日志文件的最大大小。一旦日志文件的大小达到这个配置项设置的值,日志文件就会自动清空文件中所有的日志记录,并重新开始写入。不过配置项MAX_LOG_FILE_SIZE在默认情况下是不生效的,需要设置标记:LoggingFlag::StrictLogFileSizeCheck来激活。另外,如果我们想要保留之前的日志记录,那么我们可以注册一个回调函数,这个回调函数将会允许我们在清空日志文件之前对日志文件进行一次处理。下面的代码演示了按大小滚动日志文件,并通过回调函数保留了所有的日志记录:

#include "easylogging++.h"  
  
INITIALIZE_EASYLOGGINGPP  
  
static unsigned int idx;  
  
void rolloutHandler(const char* filename, std::size_t size)   
{  
    /// 备份日志  
    system("mkdir bin");  
    std::stringstream ss;  
    ss << "move " << filename << " bin\\log_backup_" << ++idx;  
    system(ss.str().c_str());  
}  
  
int main(int, char**)  
{  
    idx = 0;  
    el::Loggers::addFlag(el::LoggingFlag::StrictLogFileSizeCheck);  
    el::Loggers::reconfigureAllLoggers(el::ConfigurationType::MaxLogFileSize, "100");  
  
    /// 注册回调函数  
    el::Helpers::installPreRollOutCallback(rolloutHandler);  
  
    for (int i = 0; i < 100; ++i)  
    {  
        LOG(INFO) << "Test";  
    }  
  
    /// 注销回调函数  
    el::Helpers::uninstallPreRollOutCallback();  
    return 0;  
}  

   通过配置文件来设置配置项 MAX_LOG_FILE_SIZE 的大小也可以实现上述演示代码的效果,另外我们还可以设置不同级别的日志文件按照不同的文件大小来滚动。如果不小心忘记了设置标记:LoggingFlag::StrictLogFileSizeCheck ,我们还可以通过调用函数 el::Helpers::validateFileRolling(el::Logger*, const el::Level&) 以手动的方式来检查日志滚动,建议各位小伙伴可以自己尝试一下。

 

按时间滚动文件

   在Easylogging++中是没有实现按时间滚动日志文件的,不过既然是开源的日志库,我们可以参考着按大小滚动日志文件的实现方式,根据自己的需求去实现一个按时间滚动日志文件的功能。下面说一下具体的实现步骤:

   ·在按大小滚动日志文件中有配置项MAX_LOG_FILE_SIZE,所以我们也增加一个配置项LOG_FILE_ROLLING_TIME,新增配置项的值类型为char *型,其值只能是以下四个:"MONTH","DAY","HOUR","MINUTE",其中"MONTH"表示按月份滚动日志文件,“DAY”表示按天数滚动日志文件,“HOUR”表示按小时滚动日志文件,“MINUTE”表示按分钟滚动日志文件。

   ·在按大小滚动日志文件中有标记LoggingFlag::StrictLogFileSizeCheck来激活滚动功能,所以我们在实现按时间滚动日志文件的功能中也增加一个标记LoggingFlag::StrictLogFileTimeCheck来激活滚动功能。

   ·在按大小滚动日志文件中,允许我们在清空文件重写写入之前通过回调函数对日志文件进行处理,所以我们在按时间滚动日志文件的功能实现中,也同样保留该回调函数的功能,但是在回调函数中增加了一个参数,用来区分是按大小滚动日志文件还是按时间滚动日志文件。

   下面的代码演示了如何使用新增的按时间滚动日志文件的功能:

#include "easylogging++.h"  
  
INITIALIZE_EASYLOGGINGPP  
  
void rolloutHandler(const char* filename, std::size_t size, el::base::RollingLogFileBasis rollingbasis)  
{  
    switch (rollingbasis)  
    {  
    case el::base::RollingLogFileBasis::RollLog_FileSize:  
        /// 按大小滚动日志文件  
        break;  
    case el::base::RollingLogFileBasis::RollLog_DateTime:  
        /// 按时间滚动日志文件  
    {  
        time_t cuurenttime = time(NULL);  
        cuurenttime -= 60;  
  
        struct::tm oneMinuteAgo;  
        localtime_s(&oneMinuteAgo, &cuurenttime);  
  
        std::string filenameTemp = filename;  
        int pos = filenameTemp.rfind('.');  
        filenameTemp = filenameTemp.substr(0, pos);  
        char backupFile[MAX_PATH] = { 0 };  
        sprintf_s(backupFile, MAX_PATH, "%s_%04d%02d%02d%02d%02d.log", filenameTemp.c_str(), oneMinuteAgo.tm_year + 1900  
            , oneMinuteAgo.tm_mon + 1, oneMinuteAgo.tm_mday, oneMinuteAgo.tm_hour, oneMinuteAgo.tm_min);  
  
        /// 自定义日志备份  
        std::stringstream ss;  
        ss << "move " << filename << " " << backupFile;  
        system(ss.str().c_str());  
    }  
        break;  
    default:  
        break;  
    }  
}  
  
int main(int, char**)  
{  
    el::Loggers::addFlag(el::LoggingFlag::DisableApplicationAbortOnFatalLog);  
    el::Loggers::addFlag(el::LoggingFlag::StrictLogFileTimeCheck);  
    el::Loggers::reconfigureAllLoggers(el::ConfigurationType::LogFileRollingTime, "minute");    /// 按分钟滚动日志文件  
  
    /// 注册回调函数  
    el::Helpers::installPreRollOutCallback(rolloutHandler);  
  
    for (int i = 0; i < 100000; ++i)  
    {  
        LOG(DEBUG) << "DEBUG";  
        LOG(INFO) << "INFO";  
        DLOG(INFO) << "DEBUG";  
        LOG(WARNING) << "WARNING";  
        LOG(ERROR) << "ERROR";  
        LOG(FATAL) << "FATAL";  
        LOG(TRACE) << "TRACE";  
  
        VLOG(0) << "VERBOSE";  
        Sleep(1000);  
    }  
  
    /// 注销回调函数  
    el::Helpers::uninstallPreRollOutCallback();  
    return 0;  
}  


特别提醒:

 

    因为在新增按时间滚动日志文件的功能中修改了回调函数,所以如果使用按大小滚动日志文件功能,也需要使用修改后的回调函数。

    因为只有在有日志写入的时候才判断是否需要更新文件,所以如果无日志记录,日志文件是无法按时间滚动的。

  

    在实际应用中,如果日志按时间滚动,我们的日志文件基本上都会以时间来命名,所以为了更加方便地使用,我们可以在实现了按时间滚动功能的代码上再增加一个宏定义ELPP_NAME_LOG_FILE_AFTER_TIME。通过定义这个宏,我们实现了这样一个功能:当按时间滚动日志时,可以自动地创建新的日志文件,并且会以滚动时间命名新建文件。不过这个功能目前并不是很完善,使用起来有以下几个限制条件:

   不同级别的日志必须保存在不同的日志文件中,否则无法实现日志滚动。

   ·按月份滚动的日志文件名中日期格式须配置:%datetime{%Y%M},如FILENAME = "log\\test_%datetime{%Y%M}.log"。

   ·按天数滚动的日志文件名中日期格式须配置:%datetime{%Y%M%d},如FILENAME = "log\\test_%datetime{%Y%M%d}.log"。

 ·按小时滚动的日志文件名中日期格式须配置:%datetime{%Y%M%d%H},如FILENAME = "log\\test_%datetime{%Y%M%d%H}.log"。

 ·按分钟滚动的日志文件名中日期格式须配置:%datetime{%Y%M%d%H%m},如FILENAM="log\\test_%datetime{%Y%M%d%H%m}.log"。

    虽然使用这个功能有些限制条件,但是这些条件基本符合我平时的使用习惯,因为不同级别的日志在实际应用中我肯定是会保存在不同的文件中,而且文件名中的日期格式也和滚动的时间间隔一致,所以我也就没有去完善这个功能。下面通过配置文件的方式演示了这个功能:

#define ELPP_NAME_LOG_FILE_AFTER_TIME  
#define ELPP_NO_DEFAULT_LOG_FILE  
#include "easylogging++.h"  
  
INITIALIZE_EASYLOGGINGPP  
  
int main(int, char**)  
{  
    el::Loggers::addFlag(el::LoggingFlag::DisableApplicationAbortOnFatalLog);  
    el::Loggers::addFlag(el::LoggingFlag::StrictLogFileTimeCheck);  
  
    el::Configurations conf("log.conf");  
    el::Loggers::reconfigureAllLoggers(conf);  
  
    for (int i = 0; i < 100000; ++i)  
    {  
        LOG(DEBUG) << "DEBUG";  
        LOG(INFO) << "INFO";  
        LOG(WARNING) << "WARNING";  
        LOG(ERROR) << "ERROR";  
        LOG(FATAL) << "FATAL";  
        LOG(TRACE) << "TRACE";  
  
        VLOG(0) << "VERBOSE";  
        Sleep(1000);  
    }  
  
    return 0;  

  其中配置文件log.conf内容如下:

* GLOBAL:  
    FORMAT                  =   "[%level | %datetime] | %msg"  
    ENABLED                 =   true  
    TO_FILE                 =   true  
    TO_STANDARD_OUTPUT      =   true  
    LOG_FLUSH_THRESHOLD     =   0  
    MILLISECONDS_WIDTH      =   3  
    PERFORMANCE_TRACKING    =   false  
    MAX_LOG_FILE_SIZE       =   2097152 ## Throw log files away after 2097152 2MB / 209715200 200MB / 4398046511104 1GB  
    LOG_FILE_ROLLING_TIME   =   minute  
* INFO:  
    FILENAME                =   "log\\test_%datetime{%Y%M%d%H%m}_info.log"  
* DEBUG:  
    FILENAME                =   "log\\test_%datetime{%Y%M%d%H%m}_debug.log"  
* WARNING:  
    FILENAME                =   "log\\test_%datetime{%Y%M%d%H%m}_warning.log"  
* TRACE:  
    FILENAME                =   "log\\test_%datetime{%Y%M%d%H%m}_trace.log"  
* VERBOSE:  
    FILENAME                =   "log\\test_%datetime{%Y%M%d%H%m}_verbose.log"  
* ERROR:  
    FILENAME                =   "log\\test_%datetime{%Y%M%d%H%m}_error.log"  
* FATAL:  
    FILENAME                =   "log\\test_%datetime{%Y%M%d%H%m}_fatal.log"  


   按时间滚动日志文件之所以写了这么多,最主要的原因就是为了说明在开源的日志库中,我们可以完全自主地按照自己的想法来实现一些符合自己需求的功能。比如上面介绍的宏定义ELPP_NAME_LOG_FILE_AFTER_TIME功能,虽然还不完善,但是只要严格按照限制条件来使用,完全可以达到我们想要的效果。对于开源代码,能够直接使用还并不是我们最终的目的,能够在开源的基础上加以修改完善并应用于实际编程当中才是我们学习开源代码的初衷。

 

参考:

https://www.yuque.com/docs/share/5bdb4728-98f9-475c-a403-b39e113fbeb2

 

你可能感兴趣的:(C++,easylogging,Easylogging,日志文件滚动)