日志库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; }
分模块日志也可以叫分文件日志,如果以前接触过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; }
关于Verbose日志的总结
本文的学习记录中,写了很多关于Verbose日志的功能和用法,其中的内容有些可能比较抽象,特别是vmodule分模块日志,这里只是尽可能详细、简单地进行说明和演示。如果想要更好地理解其中的某些概念,或者功能,还是建议自己真正动手写代码进行尝试和验证,通过编写代码来理解代码绝对是一个很好的学习方法。只有真正地理解了Verbose日志,我们才能将其更好地应用于自己的程序开发当中。