博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
开源日志系统log4cplus(五)
阅读量:6818 次
发布时间:2019-06-26

本文共 14154 字,大约阅读时间需要 47 分钟。

日志系统的另一个基本功能就是能够让使用者按照自己的意愿来控制什么时候,哪些log信息可以输出。 如果能够让用户在任意时刻设置允许输出的LogLevel的信息就好了,log4cplus通过LogLevelManager、 LogLog、Filter三种方式实现了上述功能。

 

### 优先级控制 ###
在研究LogLevelManager之前,首先介绍一下log4cplus中logger的存储机制,在log4cplus中,所有 logger都通过一个层次化的结构(其实内部是hash表)来组织的,有一个Root级别的logger,可以通 过以下方法获取:
    Logger root = Logger::getRoot();     用户定义的logger都有一个名字与之对应,比如:
    Logger test = Logger::getInstance("test");     可以定义该logger的子logger:
    Logger subTest = Logger::getInstance("test.subtest");     注意Root级别的logger只有通过getRoot方法获取,Logger::getInstance("root")获得的是它的 子对象而已。有了这些具有父子关系的logger之后可分别设置其LogLevel,比如:
root.setLogLevel( ... ); Test.setLogLevel( ... ); subTest.setLogLevel( ... );
logger的这种父子关联性会体现在优先级控制方面,log4cplus将输出的log信息按照LogLevel (从低到高)分为:
NOT_SET_LOG_LEVEL (   -1) :接受缺省的LogLevel,如果有父logger则继承它的LogLevel ALL_LOG_LEVEL     (    0) :开放所有log信息输出 TRACE_LOG_LEVEL   (    0) :开放trace信息输出(即ALL_LOG_LEVEL) DEBUG_LOG_LEVEL   (10000) :开放debug信息输出 INFO_LOG_LEVEL    (20000) :开放info信息输出 WARN_LOG_LEVEL    (30000) :开放warning信息输出 ERROR_LOG_LEVEL   (40000) :开放error信息输出 FATAL_LOG_LEVEL   (50000) :开放fatal信息输出 OFF_LOG_LEVEL     (60000) :关闭所有log信息输出
LogLevelManager负责设置logger的优先级,各个logger可以通过setLogLevel设置自己的优先级, 当某个logger的LogLevel设置成NOT_SET_LOG_LEVEL时,该logger会继承父logger的优先级,另外, 如果定义了重名的多个logger, 对其中任何一个的修改都会同时改变其它logger,我们举例说明:
〖例6〗
#include "log4cplus/logger.h" #include "log4cplus/consoleappender.h" #include "log4cplus/loglevel.h" #include 
using namespace std; using namespace log4cplus;
int main() {
    SharedAppenderPtr _append(new ConsoleAppender());     _append->setName("test");     Logger::getRoot().addAppender(_append);     Logger root = Logger::getRoot();
    Logger test = Logger::getInstance("test");     Logger subTest = Logger::getInstance("test.subtest");     LogLevelManager& llm = getLogLevelManager();
    cout << endl << "Before Setting, Default LogLevel" << endl;     LOG4CPLUS_FATAL(root, "root: " << llm.toString(root.getChainedLogLevel()))     LOG4CPLUS_FATAL(root, "test: " << llm.toString(test.getChainedLogLevel()))     LOG4CPLUS_FATAL(root, "test.subtest: " << llm.toString(subTest.getChainedLogLevel()))
    cout << endl << "Setting test.subtest to WARN" << endl;     subTest.setLogLevel(WARN_LOG_LEVEL);     LOG4CPLUS_FATAL(root, "root: " << llm.toString(root.getChainedLogLevel()))     LOG4CPLUS_FATAL(root, "test: " << llm.toString(test.getChainedLogLevel()))     LOG4CPLUS_FATAL(root, "test.subtest: " << llm.toString(subTest.getChainedLogLevel()))
    cout << endl << "Setting test.subtest to TRACE" << endl;     test.setLogLevel(TRACE_LOG_LEVEL);     LOG4CPLUS_FATAL(root, "root: " << llm.toString(root.getChainedLogLevel()))     LOG4CPLUS_FATAL(root, "test: " << llm.toString(test.getChainedLogLevel()))     LOG4CPLUS_FATAL(root, "test.subtest: " << llm.toString(subTest.getChainedLogLevel()))
    cout << endl << "Setting test.subtest to NO_LEVEL" << endl;     subTest.setLogLevel(NOT_SET_LOG_LEVEL);     LOG4CPLUS_FATAL(root, "root: " << llm.toString(root.getChainedLogLevel()))     LOG4CPLUS_FATAL(root, "test: " << llm.toString(test.getChainedLogLevel()))     LOG4CPLUS_FATAL(root, "test.subtest: " << llm.toString(subTest.getChainedLogLevel()) << '\n')
    cout << "create a logger test_bak, named \"test_\", too. " << endl;     Logger test_bak = Logger::getInstance("test");     cout << "Setting test to INFO, so test_bak also be set to INFO" << endl;     test.setLogLevel(INFO_LOG_LEVEL);     LOG4CPLUS_FATAL(root, "test: " << llm.toString(test.getChainedLogLevel()))     LOG4CPLUS_FATAL(root, "test_bak: " << llm.toString(test_bak.getChainedLogLevel()))
    return 0; }
输出结果:
Before Setting, Default LogLevel FATAL - root: DEBUG FATAL - test: DEBUG FATAL - test.subtest: DEBUG
Setting test.subtest to WARN FATAL - root: DEBUG FATAL - test: DEBUG FATAL - test.subtest: WARN
Setting test.subtest to TRACE FATAL - root: DEBUG FATAL - test: TRACE FATAL - test.subtest: WARN
Setting test.subtest to NO_LEVEL FATAL - root: DEBUG FATAL - test: TRACE FATAL - test.subtest: TRACE
create a logger test_bak, named "test_", too. Setting test to INFO, so test_bak also be set to INFO FATAL - test: INFO FATAL - test_bak: INFO
下面的例子演示了如何通过设置LogLevel来控制用户的log信息输出:
〖例7〗
#include "log4cplus/logger.h" #include "log4cplus/consoleappender.h" #include "log4cplus/loglevel.h" #include 
using namespace std; using namespace log4cplus;
void ShowMsg(void) {
    LOG4CPLUS_TRACE(Logger::getRoot(),"info")     LOG4CPLUS_DEBUG(Logger::getRoot(),"info")     LOG4CPLUS_INFO(Logger::getRoot(),"info")     LOG4CPLUS_WARN(Logger::getRoot(),"info")     LOG4CPLUS_ERROR(Logger::getRoot(),"info")     LOG4CPLUS_FATAL(Logger::getRoot(),"info") }
int main() {
    SharedAppenderPtr _append(new ConsoleAppender());     _append->setName("test");     _append->setLayout(std::auto_ptr(new TTCCLayout()));     Logger root = Logger::getRoot();     root.addAppender(_append);
    cout << endl << "all-log allowed" << endl;     root.setLogLevel(ALL_LOG_LEVEL);     ShowMsg();
    cout << endl << "trace-log and above allowed" << endl;     root.setLogLevel(TRACE_LOG_LEVEL);     ShowMsg();
    cout << endl << "debug-log and above allowed" << endl;     root.setLogLevel(DEBUG_LOG_LEVEL);     ShowMsg();
    cout << endl << "info-log and above allowed" << endl;     root.setLogLevel(INFO_LOG_LEVEL);     ShowMsg();
    cout << endl << "warn-log and above allowed" << endl;     root.setLogLevel(WARN_LOG_LEVEL);     ShowMsg();
    cout << endl << "error-log and above allowed" << endl;     root.setLogLevel(ERROR_LOG_LEVEL);     ShowMsg();
    cout << endl << "fatal-log and above allowed" << endl;     root.setLogLevel(FATAL_LOG_LEVEL);     ShowMsg();
    cout << endl << "log disabled" << endl;     root.setLogLevel(OFF_LOG_LEVEL);     ShowMsg();
    return 0; }
输出结果:
all-log allowed 10-17-04 10:11:40,587 [1075298944] TRACE root <> - info 10-17-04 10:11:40,590 [1075298944] DEBUG root <> - info 10-17-04 10:11:40,591 [1075298944] INFO root <> - info 10-17-04 10:11:40,591 [1075298944] WARN root <> - info 10-17-04 10:11:40,592 [1075298944] ERROR root <> - info 10-17-04 10:11:40,592 [1075298944] FATAL root <> - info
trace-log and above allowed 10-17-04 10:11:40,593 [1075298944] TRACE root <> - info 10-17-04 10:11:40,593 [1075298944] DEBUG root <> - info 10-17-04 10:11:40,594 [1075298944] INFO root <> - info 10-17-04 10:11:40,594 [1075298944] WARN root <> - info 10-17-04 10:11:40,594 [1075298944] ERROR root <> - info 10-17-04 10:11:40,594 [1075298944] FATAL root <> - info
debug-log and above allowed 10-17-04 10:11:40,595 [1075298944] DEBUG root <> - info 10-17-04 10:11:40,595 [1075298944] INFO root <> - info 10-17-04 10:11:40,596 [1075298944] WARN root <> - info 10-17-04 10:11:40,596 [1075298944] ERROR root <> - info 10-17-04 10:11:40,596 [1075298944] FATAL root <> - info
info-log and above allowed 10-17-04 10:11:40,597 [1075298944] INFO root <> - info 10-17-04 10:11:40,597 [1075298944] WARN root <> - info 10-17-04 10:11:40,597 [1075298944] ERROR root <> - info 10-17-04 10:11:40,598 [1075298944] FATAL root <> - info
warn-log and above allowed 10-17-04 10:11:40,598 [1075298944] WARN root <> - info 10-17-04 10:11:40,598 [1075298944] ERROR root <> - info 10-17-04 10:11:40,599 [1075298944] FATAL root <> - info
error-log and above allowed 10-17-04 10:11:40,599 [1075298944] ERROR root <> - info 10-17-04 10:11:40,600 [1075298944] FATAL root <> - info
fatal-log and above allowed 10-17-04 10:11:40,600 [1075298944] FATAL root <> - info
log disabled
 
用户也可以自行定义LogLevel,操作比较简单,首先要定义LEVEL值,比如HELLO_LOG_LEVEL定义如下:
/* DEBUG_LOG_LEVEL  < HELLO_LOG_LEVEL < INFO_LOG_LEVEL */ const LogLevel HELLO_LOG_LEVEL = 15000;
然后定义以下宏即可:
/* define MACRO LOG4CPLUS_HELLO */ #define LOG4CPLUS_HELLO(logger, logEvent) \     if(logger.isEnabledFor(HELLO_LOG_LEVEL)) { \         log4cplus::tostringstream _log4cplus_buf; \         _log4cplus_buf << logEvent; \  logger.forcedLog(HELLO_LOG_LEVEL, _log4cplus_buf.str(), __FILE__, __LINE__); \     }
不过log4cplus没有提供给用户一个接口来实现LEVEL值与字符串的转换,所以当带格式输出LogLevel字符 串时候会显示"UNKNOWN", 不够理想。比如用TTCCLayout控制输出的结果可能会如下所示:
10-17-04 11:17:51,124 [1075298944] UNKNOWN root <> - info
而不是期望的以下结果: 10-17-04 11:17:51,124 [1075298944] HELLO root <> - info
要想实现第二种结果,按照log4cplus现有的接口机制,只能改其源代码后重新编译,方法是在loglevel.cxx 中加入:
#define _HELLO_STRING LOG4CPLUS_TEXT("HELLO")
然后修改log4cplus::tstring  defaultLogLevelToStringMethod(LogLevel ll)函数,增加一个判断:
case HELLO_LOG_LEVEL:    return _HELLO_STRING;
重新编译log4cplus源代码后生成库文件,再使用时即可实现满意效果。
### 调试模式 ###
即通过loglog来控制输出调试、警告或错误信息,见例4,这里不再赘述。
 
### 基于脚本配置来过滤log信息 ###
除了通过程序实现对log环境的配置之外,log4cplus通过PropertyConfigurator类实现了基于脚本配置的功能。 通过脚本可以完成对logger、appender和layout的配置,因此可以解决怎样输出,输出到哪里的问题,我将在 全文的最后一部分中提到多线程环境中如何利用脚本配置来配合实现性能测试,本节将重点介绍基脚本实现过 滤log信息的功能。
首先简单介绍一下脚本的语法规则:
包括Appender的配置语法和logger的配置语法,其中:
1.Appender的配置语法:
(1)设置名称:
/*设置方法*/ log4cplus.appender.appenderName=fully.qualified.name.of.appender.class
例如(列举了所有可能的Appender,其中SocketAppender后面会讲到): log4cplus.appender.append_1=log4cplus::ConsoleAppender log4cplus.appender.append_2=log4cplus::FileAppender log4cplus.appender.append_3=log4cplus::RollingFileAppender log4cplus.appender.append_4=log4cplus::DailyRollingFileAppender log4cplus.appender.append_4=log4cplus::SocketAppender
(2)设置Filter:
包括选择过滤器和设置过滤条件,可选择的过滤器包括:LogLevelMatchFilter、LogLevelRangeFilter、 和StringMatchFilter:
对LogLevelMatchFilter来说,过滤条件包括LogLevelToMatch和AcceptOnMatch(true|false), 只有 当log信息的LogLevel值与LogLevelToMatch相同,且AcceptOnMatch为true时才会匹配。
LogLevelRangeFilter来说,过滤条件包括LogLevelMin、LogLevelMax和AcceptOnMatch,只有当log信息 的LogLevel在LogLevelMin、LogLevelMax之间同时AcceptOnMatch为true时才会匹配。
对StringMatchFilter来说,过滤条件包括StringToMatch和AcceptOnMatch,只有当log信息的LogLevel值 与StringToMatch对应的LogLevel值与相同, 且AcceptOnMatch为true时会匹配。
过滤条件处理机制类似于IPTABLE的Responsibility chain,(即先deny、再allow)不过执行顺序刚好相反, 后写的条件会被先执行,比如:
log4cplus.appender.append_1.filters.1=log4cplus::spi::LogLevelMatchFilter log4cplus.appender.append_1.filters.1.LogLevelToMatch=TRACE log4cplus.appender.append_1.filters.1.AcceptOnMatch=true #log4cplus.appender.append_1.filters.2=log4cplus::spi::DenyAllFilter
会首先执行filters.2的过滤条件,关闭所有过滤器,然后执行filters.1,仅匹配TRACE信息。
(3)设置Layout
可以选择不设置、TTCCLayout、或PatternLayout
如果不设置,会输出简单格式的log信息。
设置TTCCLayout如下所示: log4cplus.appender.ALL_MSGS.layout=log4cplus::TTCCLayout
设置PatternLayout如下所示: log4cplus.appender.append_1.layout=log4cplus::PatternLayout log4cplus.appender.append_1.layout.ConversionPattern=%d{%m/%d/%y %H:%M:%S,%Q} [%t] %-5p - %m%n
2.logger的配置语法
包括rootLogger和non-root logger。
对于rootLogger来说: log4cplus.rootLogger=[LogLevel], appenderName, appenderName, ...
对于non-root logger来说: log4cplus.logger.logger_name=[LogLevel|INHERITED], appenderName, appenderName, ...
脚本方式使用起来非常简单,只要首先加载配置即可(urconfig.properties是自行定义的配置文件):
PropertyConfigurator::doConfigure("urconfig.properties");
下面我们通过例子体会一下log4cplus强大的基于脚本过滤log信息的功能。
〖例8〗
/*  *    urconfig.properties  */ log4cplus.rootLogger=TRACE, ALL_MSGS, TRACE_MSGS, DEBUG_INFO_MSGS, FATAL_MSGS
log4cplus.appender.ALL_MSGS=log4cplus::RollingFileAppender log4cplus.appender.ALL_MSGS.File=all_msgs.log log4cplus.appender.ALL_MSGS.layout=log4cplus::TTCCLayout
log4cplus.appender.TRACE_MSGS=log4cplus::RollingFileAppender log4cplus.appender.TRACE_MSGS.File=trace_msgs.log log4cplus.appender.TRACE_MSGS.layout=log4cplus::TTCCLayout log4cplus.appender.TRACE_MSGS.filters.1=log4cplus::spi::LogLevelMatchFilter log4cplus.appender.TRACE_MSGS.filters.1.LogLevelToMatch=TRACE log4cplus.appender.TRACE_MSGS.filters.1.AcceptOnMatch=true log4cplus.appender.TRACE_MSGS.filters.2=log4cplus::spi::DenyAllFilter
log4cplus.appender.DEBUG_INFO_MSGS=log4cplus::RollingFileAppender log4cplus.appender.DEBUG_INFO_MSGS.File=debug_info_msgs.log log4cplus.appender.DEBUG_INFO_MSGS.layout=log4cplus::TTCCLayout log4cplus.appender.DEBUG_INFO_MSGS.filters.1=log4cplus::spi::LogLevelRangeFilter log4cplus.appender.DEBUG_INFO_MSGS.filters.1.LogLevelMin=DEBUG log4cplus.appender.DEBUG_INFO_MSGS.filters.1.LogLevelMax=INFO log4cplus.appender.DEBUG_INFO_MSGS.filters.1.AcceptOnMatch=true log4cplus.appender.DEBUG_INFO_MSGS.filters.2=log4cplus::spi::DenyAllFilter
log4cplus.appender.FATAL_MSGS=log4cplus::RollingFileAppender log4cplus.appender.FATAL_MSGS.File=fatal_msgs.log log4cplus.appender.FATAL_MSGS.layout=log4cplus::TTCCLayout log4cplus.appender.FATAL_MSGS.filters.1=log4cplus::spi::StringMatchFilter log4cplus.appender.FATAL_MSGS.filters.1.StringToMatch=FATAL log4cplus.appender.FATAL_MSGS.filters.1.AcceptOnMatch=true log4cplus.appender.FATAL_MSGS.filters.2=log4cplus::spi::DenyAllFilter
/*  *    main.cpp  */ #include 
#include
#include
using namespace log4cplus;
static Logger logger = Logger::getInstance("log");
void printDebug() {
    LOG4CPLUS_TRACE_METHOD(logger, "::printDebug()");     LOG4CPLUS_DEBUG(logger, "This is a DEBUG message");     LOG4CPLUS_INFO(logger, "This is a INFO message");     LOG4CPLUS_WARN(logger, "This is a WARN message");     LOG4CPLUS_ERROR(logger, "This is a ERROR message");     LOG4CPLUS_FATAL(logger, "This is a FATAL message"); } int main() {
    Logger root = Logger::getRoot();     PropertyConfigurator::doConfigure("urconfig.properties");     printDebug();
    return 0; }
运行结果:
1. all_msgs.log 10-17-04 14:55:25,858 [1075298944] TRACE log <> - ENTER: ::printDebug() 10-17-04 14:55:25,871 [1075298944] DEBUG log <> - This is a DEBUG message 10-17-04 14:55:25,873 [1075298944] INFO log <> - This is a INFO message 10-17-04 14:55:25,873 [1075298944] WARN log <> - This is a WARN message 10-17-04 14:55:25,874 [1075298944] ERROR log <> - This is a ERROR message 10-17-04 14:55:25,874 [1075298944] FATAL log <> - This is a FATAL message 10-17-04 14:55:25,875 [1075298944] TRACE log <> - EXIT:  ::printDebug()
2. trace_msgs.log 10-17-04 14:55:25,858 [1075298944] TRACE log <> - ENTER: ::printDebug() 10-17-04 14:55:25,875 [1075298944] TRACE log <> - EXIT:  ::printDebug()
3. debug_info_msgs.log 10-17-04 14:55:25,871 [1075298944] DEBUG log <> - This is a DEBUG message 10-17-04 14:55:25,873 [1075298944] INFO log <> - This is a INFO message
4. fatal_msgs.log 10-17-04 14:55:25,874 [1075298944] FATAL log <> - This is a FATAL message
 
本部分详细介绍了如何有选择地控制log信息的输出,最后一部分我们将介绍一下多线程、 和C/S模式下该如何操作,顺便提一下NDC的概念。

转载地址:http://goszl.baihongyu.com/

你可能感兴趣的文章
Silverlight 4简体中文正式版脱机帮助文档下载
查看>>
chenzi.exe的分析及解决方法
查看>>
Top 13 SQL Scaners
查看>>
AWS上的MongoDB:如果为你的MongoDB服务器选择正确的EC2实例类型?
查看>>
OSPF和RIP综合实验 有点难度!
查看>>
js实现tooltips
查看>>
轻松拥有个性化Windows安装光盘
查看>>
如何彻底删除已经损坏或不用的DC
查看>>
Windows 2008 R2 安装 SQL Server 2008群集故障的解决
查看>>
Hyper-V 2016 系列教程22 比较 Windows Server 2016 服务器不同版本的特征
查看>>
SQL Server 进阶 01 数据库的设计
查看>>
.NET多线程编程(4)——线程池
查看>>
Redis 参数
查看>>
[windows server 2008 站点系列一]AD的站点建立与子网的管理
查看>>
你不得不知道的Visual Studio 2012(2)- 全新调试功能
查看>>
GDB技巧:使用checkpoint解决难以复现的Bug
查看>>
C++字符换行 .
查看>>
《矩阵》——稀疏矩阵(Java)
查看>>
彻底学会使用epoll(二)——ET和LT的触发方式
查看>>
Mocha BSM产品亮点——策略管理
查看>>