日志库EasyLogging++学习系列(8)—— Verbose日志详解

转载自:

  http://blog.csdn.net/Fish_55_66/article/details/49508961

 

这里之所以把Verbose日志单独拿出来讲,是因为最初接触 Easylogging++ 的时候,对Verbose级别的日志感到有点迷惑,并不是十分清楚其用法。不过后来发现,在不扩展日志级别的情况下,其实Verbose日志可以让我们更轻松地记录更多更详细的信息,特别是在排错的日志记录中,没有哪个级别的日志比使用Verbose级别的日志更为合适了。

 

正如如前面文章提到的一样,Verbose日志并不适用于划分级别的日志记录,意思就是说在设置了标记:LoggingFlag::HierarchicalLogging 的日志记录中,即使门阀值设置大于Verbose级别,甚至是设置成Unknown,也无法关闭Verbose级别日志的输出。同时,Verbose日志拥有专属的宏定义来记录日志,而不支持类似于 LOG(VERBOSE) 等宏定义。下面列出Verbose日志专属的宏定义:

 

  • VLOG(verbose-level)
  • CVLOG(verbose-level, logger ID)
  • VLOG_IF(condition, verbose-level)
  • CVLOG_IF(condition, verbose-level, loggerID)
  • VLOG_EVERY_N(n, verbose-level)
  • CVLOG_EVERY_N(n, verbose-level, loggerID)
  • VLOG_AFTER_N(n, verbose-level)
  • CVLOG_AFTER_N(n, verbose-level, loggerID)
  • VLOG_N_TIMES(n, verbose-level)
  • CVLOG_N_TIMES(n, verbose-level, loggerID)
提示:Verbose日志同样支持DEBUG模式,上述所有宏定义都有与之对应的DEBUG模式的宏定义,在前面加上大写字母 D 即可。
 
 
理解Verbose日志的级别
 
Verbose日志可以分为 1 ~ 9 共九个级别,而这九个级别最初是处于未激活状态的。所谓的未激活状态就是说在默认的情况下,这九个级别的Verbose日志是不会输出日志信息的,除非我们设置程序参数来激活它。而VLOG(0)虽然也可以记录Verbose日志,但是它在默认的情况下是可以输出日志信息的,所以 0 并不属于Verbose日志的级别。不过实践发现,即使把 0 理解成Verbose日志的级别也可以,即可以认为Verbose日志分为 0 ~ 9 共十个级别,只是 0 级别的日志是无法被禁止输出的而已,但是在vmodule分模块日志部分内容演示代码中有一种方法可以把 VLOG(0) 的输出也禁用了。
 
 
设置Verbose日志的级别
 
在前面《日志库EasyLogging++学习系列(5)—— 辅助配置功能》这篇文章中,其实已经演示了一种设置Verbose日志级别的方法,即通过命令行参数来设置。在命令行参数中, -v 、 --verbose 、--v 、 -vmodule 都是用来设置Verbose日志的,这四个参数只能有一个生效,优先级高的会覆盖优先级低的(优先级: -v   >  --verbose  >  --v  >  -vmodule )。但是,在效果上 -v 和 --verbose 是一样的。在这里介绍另外一种可以动态设置Verbose日志级别的方法,就是利用函数 Loggers::setVerboseLevel(base::type::VerboseLevel) 来设置,其中的 base::type::VerboseLevel 实际上是个 int 整型。不过需要特别注意的是,该函数不适应于 -vmodule。关于 -vmodule 的级别设置请参考本文中下面的vmodule分模块日志部分内容。
 
 
判断Verbose日志的级别
 
我们可以通过函数 Loggers::verboseLevel() 来获取当前Verbose日志的级别,也可以利用宏 VLOG_IS_ON(verbose-level) 来判断某个级别是否已被激活。下面的代码演示了设置和判断Verbose日志级别的用法:
#include "easylogging++.h"  
  
INITIALIZE_EASYLOGGINGPP  
  
int main(int argc, char** argv)  
{  
    int verboseLevel = 0;  
    /// 获取Verbose日志级别  
    verboseLevel = el::Loggers::verboseLevel();  
    LOG(INFO) << "Verbose Level = " << verboseLevel;  
  
    VLOG(0);  
    VLOG(1);    //该行不会输出  
  
    /// 动态设置Verbose日志级别  
    el::Loggers::setVerboseLevel(3);  
    /// 获取Verbose日志级别  
    verboseLevel = el::Loggers::verboseLevel();  
    LOG(INFO) << "Verbose Level = " << verboseLevel;  
      
    VLOG(1);  
    VLOG(2);  
    VLOG(3);  
    VLOG(4);    //该行不会输出  
  
    /// 动态设置Verbose日志级别  
    el::Loggers::setVerboseLevel(9);  
    /// 获取Verbose日志级别  
    verboseLevel = el::Loggers::verboseLevel();  
    LOG(INFO) << "Verbose Level = " << verboseLevel;  
  
    VLOG(4);  
    VLOG(5);  
    VLOG(6);  
    VLOG(7);  
    VLOG(8);  
    VLOG(9);  
    VLOG(10);   //该行不会输出  
  
    /// 尝试将Verbose日志级别设置为10  
    el::Loggers::setVerboseLevel(10);  
    /// 获取Verbose日志级别  
    verboseLevel = el::Loggers::verboseLevel();  
    LOG(INFO) << "Verbose Level = " << verboseLevel;  
  
    VLOG(10);   //该行不会输出  
  
    system("pause");  
    return 0;  
}  

 

vmodule分模块日志
 
分模块日志也可以叫分文件日志,如果以前接触过GLOG日志库的小伙伴会对这个概念比较好理解,因为GLOG日志库也有这个功能。简单来说,分模块日志就是可以指定哪些文件中的日志允许输出,哪些文件中的日志不允许输出。因为分模块日志本身就是Verbose日志,所以在指定文件的同时,还必须指定Verbose日志的级别,而 -vmodule 就是用来指定文件和级别的,必须遵循下面的格式:
-vmodule=<module name>=<verboser level>,<module name>=<verboser level>,···
在格式中,多个模块之间用英文逗号“,”隔开;而<verbose level>表示Verbose日志的级别,<module name>则表示文件的名称,文件名称中支持通配符“*”和“?”。在默认情况下,Easylogging++ 会自动在文件名称后加上文件扩展名(.h, .c, .cpp, .cc, .cxx, -inl.h, .hxx, .hpp),请看下面的例子:
  • 命令行参数 -vmodule=main=3 ,表示只有以下所列文件会输出日志,并且只能输出Verbose级别不大于 3 的日志。
main.h、main.c、main.cpp、main.cc、main.cxx、main.-inl.h、main.hxx、main.hpp
  • 命令行参数 -vmodule=main=5,parse*=6 ,表示名称为 main 的文件能够输出Verbose级别不大于 5 的日志,而名称为 parse* 的文件能够输出Verbose级别不大于 6 的日志(注意 main 文件 和 parse* 文件会自动加上文件扩展名)。
但是如果设置了标记:LoggingFlag::DisableVModulesExtensions,那么<module name>表示的文件名称就不会在后面加上扩展名了。另外还有一个与 Verbose 日志相关的标记 LoggingFlag::AllowVerboseIfModuleNotSpecified ,如果设置了该标记并且使用 -vmodule 来指定文件和级别,那么除了指定的文件会按照指定的Verbose级别输出日志之外,其他所有的文件中全部的 Verbose 日志都会输出。当我们在初始化日志库的宏定义中就已经默认设置了标记 LoggingFlag::AllowVerboseIfModuleNotSpecified ,这一点需要特别注意,所以如果希望在程序中使用 -vmodule 来指定文件和级别控制日志输出,必须先用 el::Loggers::removeFlag 将标记 LoggingFlag::AllowVerboseIfModuleNotSpecified 删除才行,否则可能达不到预期的效果。最后,还有一个比较有用的标记LoggingFlag::DisableVModules ,这个标记可以用来完全关闭 vmodule 分模块日志。
 
除了可以用命令行参数设置 vmodule 分模块日志之外,还可以利用函数 Loggers::setVModules(const char*) 来动态设置,只是函数中的参数就不需要用“-vmodule=<module name>=<verboser level>”的格式了,只需直接指定文件名和级别就行了。比如直接传入参数“main=3”就行了。需要注意的是,除了第一次调用函数 Loggers::setVModules(const char*) 之外,如果其他的地方想要再次调用该函数来实现动态设置,都必须先调用 Loggers::clearVModules() 来清除之前设置过的参数,否则,后面设置的参数都将无法覆盖第一次设置的参数。下面给出关于分模块日志的部分功能的演示代码:
#include "easylogging++.h"  
  
INITIALIZE_EASYLOGGINGPP  
  
int main(int argc, char** argv)  
{  
    VLOG(0);  
  
    /// 特别注意这里的参数"*main=3",如果传入"main=3",将达不到预期的效果  
    el::Loggers::setVModules("*main=3");  
      
    VLOG(1);  
    VLOG(2);  
    VLOG(3);  
    VLOG(4);    //这一行不会输出  
  
    /// 一定要先clear,否则重新设置参数不生效  
    el::Loggers::clearVModules();  
    el::Loggers::setVModules("*main=6");  
    VLOG(4);  
    VLOG(5);  
    VLOG(6);  
    VLOG(7);    //这一行不会输出  
  
    /// 一定要先clear,否则重新设置参数不生效  
    el::Loggers::clearVModules();  
    el::Loggers::setVModules("main=6");  
    VLOG(7);  
    VLOG(8);  
    VLOG(9);  
  
    /// 取消标记AllowVerboseIfModuleNotSpecified  
    el::Loggers::removeFlag(el::LoggingFlag::AllowVerboseIfModuleNotSpecified);  
  
    /// 以下所有Verbose日志都被禁止输出,包括VLOG(0)  
    VLOG(0);  
    VLOG(1);  
    VLOG(2);  
    VLOG(3);  
    VLOG(4);      
    VLOG(5);  
    VLOG(6);  
    VLOG(7);      
    VLOG(8);      
    VLOG(9);      
  
    system("pause");  
    return 0;  
}  

 

在上面的演示代码中,可以看到参数“*main=6”和参数“main=6”会有不同的日志输出。按照上面描述的分模块日志参数设置格式定义我们知道,参数“*mian=6”表示的是允许文件“*main.cpp”输出级别不大于6的Verbose日志,在前面的星号“*”是个通配符;而参数“main=6”表示的是允许文件“main.cpp”输出级别不大于6的Verbose日志。该演示代码中main.cpp文件的完整路径是“F:\SvnCode\EasyLoggingTest\main.cpp”,在分模块日志匹配文件的时候会使用该完整路径和参数中指定的文件进行比较,所以会出现参数“*main=6”能匹配上,而参数“main=6”匹配不上的现象。
 
 
关于Verbose日志的总结
 
本文的学习记录中,写了很多关于Verbose日志的功能和用法,其中的内容有些可能比较抽象,特别是vmodule分模块日志,这里只是尽可能详细、简单地进行说明和演示。如果想要更好地理解其中的某些概念,或者功能,还是建议自己真正动手写代码进行尝试和验证,通过编写代码来理解代码绝对是一个很好的学习方法。只有真正地理解了Verbose日志,我们才能将其更好地应用于自己的程序开发当中。
posted @ 2020-12-18 18:04  阳光下的小土豆  阅读(594)  评论(0编辑  收藏  举报