⽇志库EasyLogging++学习系列(3)——配置功能
 转载⾃:
在前⾯的⽂章《》中,我们已经初步见识到了 Easylogging++ ⽇志库强⼤的配置功能。那么配置⽂件中各个字段的意义是什么呢?我们应该如何编写⾃⼰的配置⽂件呢?⼜或者说,除了配置⽂件之外,我们还有没有别的⽅法可以完成⽇志的配置功能呢?希望各位有疑惑的⼩伙伴在看了本⽂的内容之后,都能够到⾃⼰满意的答案!
要完成 Easylogging++ ⽇志的配置功能,可以通过三种⽅法去实现,⽽且每⼀种⽅法都⾮常简单。第⼀种⽅法就是使⽤配置⽂件,这种⽅法的好处就是只要修改配置⽂件即可实现⽇志格式的重新配置,⽽不需要修改源程序代码,缺点就是发布程序时必须打包配置⽂件⼀起发布,否则程序⽆法正常运⾏。在⼀些⼩项⽬中,特别是在只有⼀个EXE运⾏⽂件的程序中,如果我们不希望程序带着⼀个多余的⽇志配置⽂件,那么我们可以使⽤另外⼀种⽅法,就是使⽤ el::Configurations 类提供的成员函数,这种⽅法和第⼀种⽅法的优缺点刚好相反。最后⼀种⽅法就是使⽤ Easylogging++ 的内联配置功能,但是并不推荐使⽤这种⽅法,因为它会显得配置⼗分凌乱。
⽅法⼀:使⽤配置⽂件
在程序运⾏时,可以通过使⽤ el::Configurations 类加载配置⽂件来完成 Easylogging++ 的配置功能,配置⽂件必须遵循下⾯的语法:
* LEVEL:
CONFIGURATION NAME  = "VALUE" ## Comment
CONFIGURATION NAME  = "VALUE"
语法简要说明如下:
*LEVEL,指的是⽇志级别,以星号符“*”开始,并以英⽂冒号“:”结束。
CONFIGURATION NAME ,指的是配置项的名称,全部名称详见下⾯的表格。
"VALUE",指的是配置项的值,各个配置项对应的值类型详见下⾯的表格。
## Comment,指的是注释,其中两个连续井号"##"表⽰注释,Comment是注释的内容。注释是可有可⽆的,但是千万不要在注释中使⽤双引号,否则可能会出现意想不到的错误。
编写配置⽂件时,强烈建议先写 Global 级别的配置,这样的好处是可以使其他任何未在配置⽂件中明确
指出的级别都将会⾃动地继承并使⽤ Global 级别的配置。⽐如,如果你想把所有级别的⽇志都保存在同⼀个⽂件⾥,你只需要在 Global 级别中设置 Filename 就可以了,其他级别的⽇志将会默认的使⽤ Global 级别中的 Filename 。下⾯的表格列举了GitHub上给出的Easylogging++在配置⽂件中⽀持的配置项:
Configuration
Name
Type Description完成字符串是什么
Enabled bool Determines whether or not corresponding level for logger is enabled. You may disable all logs by using el::Level::Global
To_File bool Whether or not to write corresponding log to log file
To_Standard_Output bool Whether or not to write logs to standard output e.g, terminal or command prompt Format char*Determines format/pattern of logging for corresponding level and logger. Filename char*Determines log file (full path) to write logs to for corresponding level and logger Milliseconds_Width uint Specifies milliseconds width. Width can be within range (1-6)
Performance_Tracking
bool Determines whether or not performance tracking is enabled. This does not depend on logger or level. Performance tracking always uses 'performance' logger unless specified
Max_Log_File_Size size_t If log file size of corresponding level is >= specified size, log file will be truncated. Log_Flush_Threshold size_t Specifies number of log entries to hold until we flush pending log data
下⾯再回顾⼀下《》这篇⽂章中给出的名称为 f 的配置⽂件:
*GLOBAL:
ENABLED                =  true
TO_FILE                =  true
TO_STANDARD_OUTPUT      =  true
FORMAT                  =  "[%level | %datetime] | %msg"
FILENAME                =  "log\\log_%datetime{%Y%M%d}.log"
MILLISECONDS_WIDTH      =  3
PERFORMANCE_TRACKING    =  false
MAX_LOG_FILE_SIZE      =  1048576
LOG_FLUSH_THRESHOLD    =  0
*TRACE:
FILENAME                =  "log\\trace_log_%datetime{%Y%M%d}.log"
*DEBUG:
FILENAME                =  "log\\debug_log_%datetime{%Y%M%d}.log"
*FATAL:
ENABLED                =  false
* ERROR:
FILENAME                =  "log\\error_log_%datetime{%Y%M%d}.log"
*WARNING:
FILENAME                =  "log\\warning_log_%datetime{%Y%M%d}.log"
*INFO:
FILENAME                =  "log\\info_log_%datetime{%Y%M%d}.log"
*VERBOSE:
ENABLED                =  false
在上⾯的⽂件中,我们以 Global 级别开始,并在 Global 级别中把 Easylogging++ ⽀持的所有的配置项都设置好了,这样 Global 级别的配置就会被后续的⽇志级别所继承,⼀直到后续的⽇志级别再次明确地设置配置项才会覆盖原有的来⾃于 Global 级别的配置。⽐如这⾥的TRACE、DEBUG、ERROR、WARNING、INFO等级别都显式地定义了 Filename ,所以这⼏个级别的⽇志记录会各⾃保存在相应的
⽂件⾥⾯。⽽FATAL、VERBOSE这两个级别则显式地定义了 ENABLE ,并将其值设置为false,所以这两个级别的⽇志记录将会被禁⽤。下⾯的代码再次演⽰如何使⽤该配置⽂件(注意注释的内容):
#include "easylogging++.h"
INITIALIZE_EASYLOGGINGPP
int main(int argc, char** argv)
{
/*/////////////////////////////////////////////////////////////////////////
必须设置标记 LoggingFlag::StrictLogFileSizeCheck
否则,配置⽂件中MAX_LOG_FILE_SIZE = 1048576不⽣效
/////////////////////////////////////////////////////////////////////////*/
el::Loggers::addFlag(el::LoggingFlag::StrictLogFileSizeCheck);
el::Configurations conf("f");
///可以单独设置某⼀个logger的配置
el::Loggers::reconfigureLogger("default", conf);
///也可以设置全部logger的配置
el::Loggers::reconfigureAllLoggers(conf);
LOG(INFO) << "***** info log  *****";
system("pause");
return0;
}
⽅法⼆:使⽤ el::Configurations 类的成员函数
在 Easylogging++ ⽇志库中,封装了配置类 el::Configurations,该类提供了完成⽇志配置功能的全部接⼝,建议参考该类的源码,可以查看
和了解更多更详细和更全⾯的功能接⼝。下⾯的代码演⽰了⼏个常⽤接⼝的⽤法:
#include "easylogging++.h"
INITIALIZE_EASYLOGGINGPP
int main(int argc, const char** argv)
{
///使⽤默认配置
el::Configurations defaultConf;
defaultConf.setToDefault();
LOG(INFO) << "Using el::Configurations class";
///重新设置INFO级别的配置项FORMAT的值
defaultConf.set(el::Level::Info,
el::ConfigurationType::Format, "%datetime %level %msg");
/
//重新设置配置
el::Loggers::reconfigureLogger("default", defaultConf);
LOG(INFO) << "Using el::Configurations class";
// 重新设置GLOBAL级别的配置项FORMAT的值
defaultConf.setGlobally(
el::ConfigurationType::Format, "%datetime %msg");
///重新设置配置
el::Loggers::reconfigureLogger("default", defaultConf);
LOG(INFO) << "Using el::Configurations class";
system("pause");
return0;
}
⽅法三:使⽤内联配置功能
所谓的内联配置功能,就是说你可以通过使⽤ std::string 字符串来完成⽇志的配置功能,但是要注意在 std::string 字符串中加上换⾏符保证字符串的格式遵循配置⽂件中的格式。⽐如,如果要使⽤内联配置功能实现和⽅法⼆中⼀样的输出格式,那么实现代码必须像下⾯这样:
#include "easylogging++.h"
INITIALIZE_EASYLOGGINGPP
int main(int argc, const char** argv)
{
///使⽤默认配置
el::Configurations defaultConf;
defaultConf.setToDefault();
LOG(INFO) << "Using inline configuration";
///重新设置INFO级别的配置项FORMAT的值
defaultConf.parseFromText("*INFO:\n FORMAT = %datetime %level %msg");
///重新设置配置
el::Loggers::reconfigureLogger("default", defaultConf);
LOG(INFO) << "Using inline configuration";
// 重新设置GLOBAL级别的配置项FORMAT的值
defaultConf.parseFromText("*INFO:\n FORMAT = %datetime %msg");
///重新设置配置
el::Loggers::reconfigureLogger("default", defaultConf);
LOG(INFO) << "Using inline configuration";
system("pause");
return0;
}
仔细看上⾯的代码,注意每⼀次调⽤函数parseFromText()的参数中都包含了⼀个换⾏符 “\n”。假如没有这个换⾏符,就不能正确的解析出配置项的内容,从⽽会导致配置⽆效。由于这个原因,当需要设置的配置项很多的时候,如果还使⽤内联配置功能完成⽇志的配置,就会使得代码变得凌乱复杂,⽽且很容易造成错误,所以尽量不要使⽤这种⽅法或者避免使⽤这种⽅法。
默认配置功能
如果你希望为现有的或者将来新建的⽇志记录器设置⼀个默认的配置,你可以使⽤下⾯的这个函数:
el::Loggers::setDefaultConfigurations(el::Configurations& configurations, bool configureExistingLoggers = false)
当你在编写⼤型程序或者调⽤同样使⽤ Easylogging++ 的第三⽅库时,默认配置功能显得⼗分有⽤。这个功能使得后续任何新建的⽇志记录器,都将会使⽤默认配置;如果你希望现有的⽇志记录器也使⽤默认配置,只需把函数的第⼆个参数设置为 true 即可。下⾯的代码演⽰了默认配置功能:
#include "easylogging++.h"
INITIALIZE_EASYLOGGINGPP
int main(void)
{
el::Configurations defaultConf;
defaultConf.setGlobally(el::ConfigurationType::Format, "[%logger] %level: %msg");
///只为新建的⽇志记录器设置默认配置
el::Loggers::setDefaultConfigurations(defaultConf);
LOG(INFO) << "Set default configuration but existing loggers not updated yet";
///新建⽇志记录器 testDefaultConf1
el::Loggers::getLogger("testDefaultConf1");
CLOG(INFO, "testDefaultConf1") << "Logging using new logger 1";
// 为现有的⽇志记录器设置默认配置
el::Loggers::setDefaultConfigurations(defaultConf, true);
LOG(INFO) << "Existing loggers updated as well";
///新建⽇志记录器 testDefaultConf2
el::Loggers::getLogger("testDefaultConf2");
CLOG(INFO, "testDefaultConf2") << "Logging using new logger 2";
system("pause");
return0;
}
全局配置功能
全局配置并不是指 Global 级别,⽽是指利⽤全局配置⽂件为全部或部分,甚⾄是为新建的⽇志记录器注册配置。全局配置⽂件必须遵循下⾯的语法:
-- LOGGER ID ## Case sensitive
## Everything else is same as configuration file
-- ANOTHER LOGGER ID
## Configuration for this logger
语法简要说明如下:
LOGGER ID ,指的是记录器 ID,⼤⼩写敏感,并以两个破折号开始。
其余部分的语法规则和本⽂中⽅法⼀的配置⽂件的语法规则完全⼀样。
⼀旦你编写好了全局配置⽂件,你仅需使⽤⼀个函数就可以完成你的⽇志记录器的配置,甚⾄是注册⼀个全新的⽇志记录器。需要注意的是,你不能使⽤空⽩的配置来注册新的⽇志记录器,也就是说在 LOGGER ID 下⾯,你⾄少得定义⼀个配置项。下⾯的代码演⽰了全局配置功能:
#include "easylogging++.h"
INITIALIZE_EASYLOGGINGPP
int main(void)
{
LOG(INFO) << "Info log before using global configuration";
///只需⼀个函数即可实现全局配置功能
el::Loggers::configureFromGlobal("f");
LOG(INFO) << "Info log AFTER using global configuration";
LOG(ERROR) << "Error log AFTER using global configuration";
///⽤全局配置⽂件中新建的⽇志记录器 testGlobalConf 来记录⽇志
CLOG(TRACE, "testGlobalConf") << "TRACE Logging using new logger";
CLOG(DEBUG, "testGlobalConf") << "DEBUG Logging using new logger";
CLOG(WARNING, "testGlobalConf") << "WARNING Logging using new logger";
CLOG(ERROR, "testGlobalConf") << "ERROR Logging using new logger";
CLOG(INFO, "testGlobalConf") << "INFO Logging using new logger";
system("pause");
return0;
}
其中全局配置⽂件 f 的内容如下:
-- default
*INFO:
FORMAT  = "%level %msg"
FILENAME = "/tmp/logs/wow.log"
*ERROR:
FORMAT  = "%levshort %fbase:%line %msg"
-- testGlobalConf
*GLOBAL:
FORMAT                  =  "[%level | %datetime] | %msg"
ENABLED                =  true
TO_FILE                =  true
TO_STANDARD_OUTPUT      =  true
MILLISECONDS_WIDTH      =  3
读取配置
在某些情况下,如果我们想要获取某⼀个⽇志记录器的当前配置,可以通过使⽤ el::Loggers 类的成员函数 typedConfigurations()来实现,建议参考该类的源码,可以查看和了解更多更详细和更全⾯的功能接⼝,下⾯的代码⽚段演⽰了该功能:
el::Logger* defaultLogger = el::Loggers::getLogger("default");
///记录器default是否被禁⽤
bool enabled = defaultLogger->typedConfigurations()->enabled(el::Level::Info);
///记录器default的INFO级别的⽇志输出格式
std::string format =  defaultLogger->typedConfigurations()->logFormat(el::Level::Info).format();
学习配置⽇志是掌握 Easylogging++ 使⽤的关键,通过灵活地运⽤配置功能,才能更好地将 Easylogging++ 的强悍之处应⽤到我们的程序开发当中。在本⽂列举了⼏个⽐较通⽤的配置⽅法,然⽽,在某些应⽤场景下,我们还需要通过其他的⼀些配置⼿段来辅助我们完成某些特殊功能,这些辅助配置⼿段包括设置命令⾏参数、设置⽇志标记、配置宏定义等,限于篇幅,后⾯的⽂章再对这些内容的学习过程逐⼀进⾏记录。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。