zoukankan      html  css  js  c++  java
  • c++ 日志输出库 spdlog 简介(2)

    继续上一篇,example.cpp解析。

    1、set_pattern 自定义日志格式

    官方参考:https://github.com/gabime/spdlog/wiki/3.-Custom-formatting

    可以为所有的log制定格式,也可以为指定的log制定格式,注意下面代码中rotating_logger为指针变量。

    auto rotating_logger = spd::rotating_logger_mt("some_logger_name", "logs/rotating.txt", 256, 2);
    // Customize msg format for all messages
            spd::set_pattern("*** [%H:%M:%S %z] [thread %t] %v ***");
            rotating_logger->info("This is another message with custom format");
            //Customize msg format for a specific logger object:
            rotating_logger->set_pattern("[%H:%M:%S %f] [thread %t] %v ***");

    详细的格式说明在github上有,在此截图如下:

    image

    image

    2、set_level 设置日志级别

    低于设置级别的日志将不会被输出。各level排序,数值越大级别越高:

    // Runtime log levels
            spd::set_level(spd::level::info); //Set global log level to info
            console->debug("This message should not be displayed!");
            console->set_level(spd::level::debug); // Set specific logger's log level
            console->debug("This message should be displayed..");

    第一行日志debug级别低于设定的级别info,在level为info时不会被输出。

    第二行日志debug级别与设定的级别相同,所以可以显示出来。

    image

    typedef enum
    {
        trace = 0,
        debug = 1,
        info = 2,
        warn = 3,
        err = 4,
        critical = 5,
        off = 6
    } level_enum;

    3、编译阶段修改日志输出级别 SPDLOG_TRACE 和 SPDLOG_DEBUG

    官方参考:https://github.com/gabime/spdlog/wiki/8.-Tweaking

    当定义了宏定义 SPDLOG_TRACE_ON 时,可以用SPDLOG_TRACE语句输出trace级别的log,SPDLOG_DEBUG_ON也是同理。

    #define SPDLOG_TRACE_ON
    #define SPDLOG_DEBUG_ON
    // Compile time log levels
            // define SPDLOG_DEBUG_ON or SPDLOG_TRACE_ON
            SPDLOG_TRACE(console, "Enabled only #ifdef SPDLOG_TRACE_ON..{} ,{}", 1, 3.23);
            SPDLOG_DEBUG(console, "Enabled only #ifdef SPDLOG_DEBUG_ON.. {} ,{}", 1, 3.23);

    需要注意的是,如果不使用set_level命令设置log的输出级别,默认级别就是info级别,此时即使定义了这两个宏,debug和trace信息也不会输出。所以使用时需要先用set_level把级别设为trace才可以。

    console->set_level(spd::level::trace); // Set specific logger's log level
            // Compile time log levels
            // define SPDLOG_DEBUG_ON or SPDLOG_TRACE_ON
            SPDLOG_TRACE(console, "Enabled only #ifdef SPDLOG_TRACE_ON..{} ,{}", 1, 3.23);
            SPDLOG_DEBUG(console, "Enabled only #ifdef SPDLOG_DEBUG_ON.. {} ,{}", 1, 3.23);

    以下是输出结果:

    image

    注意trace和debug的输出不太一样,打开spdlog.h,查看SPDLOG_TRACE的定义,可以发现trace中还输出了文件的位置(“__FILE__”)。

    #ifdef SPDLOG_TRACE_ON
    #  define SPDLOG_STR_H(x) #x
    #  define SPDLOG_STR_HELPER(x) SPDLOG_STR_H(x)
    #  ifdef _MSC_VER
    #    define SPDLOG_TRACE(logger, ...) logger->trace("[ " __FILE__ "(" SPDLOG_STR_HELPER(__LINE__) ") ] " __VA_ARGS__)
    #  else
    #    define SPDLOG_TRACE(logger, ...) logger->trace("[ " __FILE__ ":" SPDLOG_STR_HELPER(__LINE__) " ] " __VA_ARGS__)
    #  endif
    #else
    #  define SPDLOG_TRACE(logger, ...) (void)0
    #endif
    
    #ifdef SPDLOG_DEBUG_ON
    #  define SPDLOG_DEBUG(logger, ...) logger->debug(__VA_ARGS__)
    #else
    #  define SPDLOG_DEBUG(logger, ...) (void)0
    #endif

    4、同步和异步设置  Asynchronous logging

    官方说明:https://github.com/gabime/spdlog/wiki/6.-Asynchronous-logging

    默认情况下是不开启异步模式的,开启异步模式方式如下:

    size_t q_size = 4096; //queue size must be power of 2
        spdlog::set_async_mode(q_size);

    队列大小:

    队列占用的内存 = 设置的队列大小 * slot的大小, 64位系统下slot大小为104字节。由此可根据系统的log输出总量来确定队列大小。

    image

    队列机制:

    异步模式下,所有输出的日志将先存入队列,再由工作者线程从队列中取出日志并输出。当队列存满时,需要根据设置好的队列存满策略来处置新来的日志(阻塞消息或者丢弃消息)。如果工作者线程中抛出了异常,向队列写入下一条日志时异常会再次抛出,可以在写入队列时捕捉工作者线程的异常。

    image

    队列存满时(Full queue policy)两种应对方式:

    (1)阻塞新来的日志,直到队列中有剩余空间。这是默认的处理方式。

    (2)丢弃新来的日志。如下:

    spdlog::set_async_mode(q_size, spdlog::async_overflow_policy::discard_log_msg)

    两种应对方式如下:

    // Async overflow policy - block by default.
    //
    enum class async_overflow_policy
    {
        block_retry, // Block / yield / sleep until message can be enqueued
        discard_log_msg // Discard the message it enqueue fails
    };

    5、处理spdlog的异常  set_error_handler

    官方说明:https://github.com/gabime/spdlog/wiki/Error-handling

    当输出日志时发生异常时,spdlog会向std::err 打印一条语句,为了避免输出的异常语句刷屏,打印频率被限制在每分钟一条。

    下面函数执行时,由于最后一条输出log的语句中四个参数只给了一个,所以spdlog调用了异常处理函数,输出异常。

    void err_handler_example()
    {
        //can be set globaly or per logger(logger->set_error_handler(..))
        spdlog::set_error_handler([](const std::string& msg)
        {
            std::cerr << "my err handler: " << msg << std::endl;
        });
        spd::get("console")->info("some invalid message to trigger an error {}{}{}{}", 3);
    }

    image

    6、apply_all 使所有的logger同时输出

    所有注册过的logger都会输出End of example 这句话,代表程序结束。

    // Apply a function on all registered loggers
            spd::apply_all([&](std::shared_ptr<spdlog::logger> l)
            {
                l->info("End of example.");
            });

    7、drop -- 释放logger

    在程序结束时,应该调用drop_all() 释放所有logger。

    There is a bug in VS runtime that cause the application dead lock when it exits. If you use async logging, please make sure to call spdlog::drop_all() before main() exit. If some loggers are not in the registry, those should be released manually as well. stackoverflow: std::thread join hangs if called after main exits when using vs2012 rc

    // Release and close all loggers
            spdlog::drop_all();

    或者单独drop某个logger

    spd::drop("console");
            spd::drop("basic_logger");
  • 相关阅读:
    3
    2
    1
    11
    12
    8888888888
    99999999999
    88888888888
    77777777
    10.23
  • 原文地址:https://www.cnblogs.com/oucsheep/p/8433918.html
Copyright © 2011-2022 走看看