• 开源日志系统log4cplus(五)


    日志系统的另一个基本功能就是能够让使用者按照自己的意愿来控制什么时候,哪些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 <iostream>
    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 <iostream>
    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 <log4cplus/logger.h>
    #include <log4cplus/configurator.h>
    #include <log4cplus/helpers/stringhelper.h>
    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的概念。
  • 相关阅读:
    vue跨域代理配置
    vue中引入jquery
    vue中使用特殊字体
    vue中使用mockjs
    vue中使用动态echart图表
    解决win10休眠后无法唤醒
    nvm-windows的安装配置
    黑苹果快捷键
    python基础知识
    如何高效的学习python
  • 原文地址:https://www.cnblogs.com/rosesmall/p/2469276.html
Copyright © 2020-2023  润新知