当先调用 Remove_All_Sinks() 时,提升日志设置旋转和最大文件大小导致添加第二个接收器

Boost Log Setting Rotation and Max File Size Results in 2nd Sink Being Added, when Remove_All_Sinks() is called prior

使用 Boost 日志进行日志记录(废话)- 我成功初始化了:

BOOST_LOG_GLOBAL_LOGGER_INIT(logger, logger_t) {
    logger_t lg;
    logging::add_common_attributes();
    boost::shared_ptr< file_sink > sink(new file_sink(
        boost::log::keywords::file_name = "appLog_%N.log",
        boost::log::keywords::rotation_size = 2 * 1024 * 1024,
        boost::log::keywords::max_size = 10 * 1024 * 1024,
        boost::log::keywords::scan_method = 
        boost::log::sinks::file::scan_method::scan_matching,
        boost::log::keywords::open_mode = std::ios_base::app,
        boost::log::keywords::auto_flush = true
    ));

    sink->set_formatter(
        expr::stream
        << expr::format_date_time< boost::posix_time::ptime >("TimeStamp", "%Y-%m-%dT%H:%M:%S.%fz")
        << ": [" << logging::trivial::severity
        << "]\t" << expr::smessage
    );

    sink->locked_backend()->set_file_collector(boost::log::sinks::file::make_collector(
        boost::log::keywords::target = "",                      /*< the target directory >*/
        boost::log::keywords::max_size = 10 * 1024 * 1024,          /*< maximum total size of the stored files, in bytes >*/
        boost::log::keywords::min_free_space = 1 * 1024 * 1024,   /*< minimum free space on the drive, in bytes >*/
        boost::log::keywords::max_files = 10                       /*< maximum number of stored files >*/
    ));

    sink->locked_backend()->scan_for_files(boost::log::sinks::file::scan_method::scan_matching, true);

    logging::core::get()->add_sink(sink);

    logging::core::get()->set_filter
    (
        logging::trivial::severity >= logging::trivial::info
    );

    return lg;
}

但是,在读取并处理应用程序的配置文件之后,其中包含指定 rotation_sizemax_size[=34 的值=] 对于日志记录,我很难删除所有接收器,然后再创建一个具有指定值的新接收器 rotation_size 和 max_size 只是在现有接收器的顶部添加一个接收器,该接收器已全局初始化(导致每条消息被记录两次)。

更新日志大小的函数如下:

void setLoggerSizes(int rotationSize, int maxSize)
{
    //INFO << "";

    logging::core::get()->remove_all_sinks();

    logging::add_common_attributes();

    boost::shared_ptr< file_sink > sink(new file_sink(
        boost::log::keywords::file_name = "appLog_%N.log",
        boost::log::keywords::rotation_size = rotationSize * 1024 * 1024,
        boost::log::keywords::max_size = maxSize * 1024 * 1024,
        boost::log::keywords::scan_method = boost::log::sinks::file::scan_method::scan_matching,
        boost::log::keywords::open_mode = std::ios_base::app,
        boost::log::keywords::auto_flush = true
    ));

    sink->set_formatter(
        expr::stream
        << expr::format_date_time< boost::posix_time::ptime >("TimeStamp", "%Y-%m-%dT%H:%M:%S.%fz")
        << ": [" << logging::trivial::severity
        << "]\t" << expr::smessage
    );

    sink->locked_backend()->set_file_collector(
        boost::log::sinks::file::make_collector(
            boost::log::keywords::target = "",
            boost::log::keywords::max_size = maxSize * 1024 * 1024,
            boost::log::keywords::min_free_space = 1 * 1024 * 1024
        )
    );

    sink->locked_backend()->scan_for_files();   

    logging::core::get()->add_sink(sink);
}

然而,如果我在函数的开头添加 INFO << "";,这似乎会强制删除所有接收器,并且在添加具有正确文件大小的接收器时,会产生一个接收器(因此只有一份消息副本要传递到日志)。

因此,我的问题是:

  1. 为什么 INFO << ""; 会发生这种情况?对于为什么添加该行会真正强制删除下一行中调用的所有接收器并因此导致记录单个消息副本,这没有任何逻辑意义。然而,不包括 INFO 行,它就像 logging::core::get()->remove_all_sinks(); 调用被忽略,并且添加了正确文件大小的接收器被添加到初始化接收器的顶部,并导致每条消息的两个副本被记录。
  2. 如何在维护全局记录器的同时正确设置旋转和最大尺寸(如果我现在不这样做)?

供参考,这是 Logger.h 文件:

#pragma once

#include <boost/log/expressions.hpp>
#include <boost/log/sources/global_logger_storage.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/utility/setup.hpp>

#define FATAL  BOOST_LOG_SEV(logger::get(), boost::log::trivial::fatal)
#define WARNING  BOOST_LOG_SEV(logger::get(), boost::log::trivial::warning)
#define INFO BOOST_LOG_SEV(logger::get(), boost::log::trivial::info)
#define DEBUG BOOST_LOG_SEV(logger::get(), boost::log::trivial::debug)
#define TRACE BOOST_LOG_SEV(logger::get(), boost::log::trivial::trace)

typedef boost::log::sources::severity_logger_mt<boost::log::trivial::severity_level> logger_t;
typedef boost::log::sinks::synchronous_sink< boost::log::sinks::text_file_backend > file_sink;

BOOST_LOG_GLOBAL_LOGGER(logger, logger_t)

void setLoggerSizes(int rotationSize, int maxSize);

您遇到的问题很可能是因为程序中日志语句的执行顺序。

BOOST_LOG_GLOBAL_LOGGER_INIT 和类似的 BOOST_LOG_INLINE_GLOBAL_LOGGER_INIT 宏的主体在程序第一次请求全局记录器时执行一次(参见 here)。因此,由于您从 INFO 宏中请求记录器,因此在调用 remove_all_sinks 并进一步初始化日志库之前执行该主体。当您注释该行时,该初始化将推迟到您第一次执行日志记录语句时,这大概发生在 setLoggerSizes returns 之后。因此,remove_all_sinks 没有效果,因为在该调用点没有要删除的接收器。

_INIT 宏实际上是为了初始化 logger,而不是整个日志库(即接收器、过滤器等)。您可以从这些宏初始化库,但是,正如您所发现的,它的用处相当有限(基本上,它可能无法按预期工作,除非您有一个全局记录器,这也是您唯一的记录器在你的整个应用程序中使用,并且你不需要在初始化后更新日志配置)。执行此操作的正确方法是在您将在 main 的早期调用的函数中单独初始化日志记录库,并使用 _INIT 宏仅初始化记录器。