【问题标题】:Simultaneous Logging to Console and File using Boost使用 Boost 同时记录到控制台和文件
【发布时间】:2014-08-01 23:05:51
【问题描述】:

我需要帮助来初始化 boost 日志框架,以同时记录到命名日志文件和控制台 - (命名日志文件不需要定期轮换或许多 boost 教程中的任何花哨设置)。

日志文本应该同时发送到两个接收器,但是我需要稍微不同地格式化控制台输出(因为它将被用户查看。)我能够使用boost example code。对于我需要做的事情来说,它过于复杂,而且就访问适当的记录器而言,它确实令人困惑。我需要做的就是将带有时间戳的消息发送到日志文件,并在没有时间戳或换行符的情况下将相同的信息发送到控制台日志(仅像我通常使用<< std::endl 那样明确地放入新行)。我真的很想继续使用 boost 的日志框架,因为它提供了未来扩展的灵活性。

在示例中,我尝试了tail -f 日志文件 - 但是日志输出似乎不会在每个日志条目后自动刷新。虽然这对文件日志来说不是很重要,但这对于控制台输出流来说至关重要,因为它代表了用户将要监控的实时活动。

非常感谢任何帮助甚至更好的一些非常简单的示例代码,以使基础工作正常。

我设置日志记录的方式(根据上面的链接)如下所示,我想用控制台记录器替换这些已注册的接收器之一 - 但我不确定如何。我希望控制台记录器会自动刷新。

// Setup the common formatter for all sinks
logging::formatter fmt = expr::stream
    << std::setw(6) << std::setfill('0') << line_id << std::setfill(' ')
    << ": <" << severity << ">\t"
    << expr::if_(expr::has_attr(tag_attr))
    [
        expr::stream << "[" << tag_attr << "] "
    ]
    << expr::smessage;

// Initialize sinks
typedef sinks::synchronous_sink<sinks::text_ostream_backend> text_sink;

boost::shared_ptr<text_sink> sink = boost::make_shared<text_sink>();
sink->locked_backend()->add_stream(boost::make_shared<std::ofstream>("full.log"));
sink->set_formatter(fmt);
// register the full log sink
logging::core::get()->add_sink(sink);

sink = boost::make_shared<text_sink>();
sink->locked_backend()->add_stream(boost::make_shared<std::ofstream>("important.log"));
// sink->set_formatter(fmt); (I removed this to not have any special formatting hopefully)
sink->set_filter(severity >= warning || (expr::has_attr(tag_attr) && tag_attr == "IMPORTANT_MESSAGE"));
// register the important log sink
logging::core::get()->add_sink(sink);

// Add attributes
logging::add_common_attributes();

【问题讨论】:

    标签: c++ logging boost boost-log boost-logging


    【解决方案1】:

    这里是一些利用 Boost-Log 的全局记录器的示例代码。我打电话给init_term() 初始化我的终端记录器和init_logfile() 初始化我的日志文件。

    注意auto_flush(true) 调用

    // Logging macro
    #define LOG(level) BOOST_LOG_SEV(global_logger::get(), level)
    // Initializing global boost::log logger
    typedef boost::log::sources::severity_channel_logger_mt<
        severity_level, std::string> global_logger_type;
    
    BOOST_LOG_INLINE_GLOBAL_LOGGER_INIT(global_logger, global_logger_type)
    {
        return global_logger_type(boost::log::keywords::channel = "global_logger");
    }
    
    // Initialize terminal logger
    void init_term()
    {
        // create sink to stdout
        boost::shared_ptr<text_sink> sink = boost::make_shared<text_sink>();
        sink->locked_backend()->add_stream(
            boost::shared_ptr<std::ostream>(&out, boost::empty_deleter()));
    
        // flush
        sink->locked_backend()->auto_flush(true);
    
        // format sink
        sink->set_formatter
        (
            /// TODO add your desired formatting
        );
    
        // filter
        // TODO add any filters
    
        // register sink
        bl::core::get()->add_sink(sink);
    }
    
    // Initialize logfile
    void init_logfile(const std::string& logfilename)
    {
        // create sink to logfile
        boost::shared_ptr<text_sink> sink = boost::make_shared<text_sink>();
        sink->locked_backend()->add_stream(
            boost::make_shared<std::ofstream>(logfilename.c_str()));
    
        // flush
        sink->locked_backend()->auto_flush(true);
    
        // format sink
        sink->set_formatter
        (
            /// TODO add your desired formatting
        );
    
        // filter
        // TODO add any filters
    
        // register sink
        bl::core::get()->add_sink(sink);
    }
    

    【讨论】:

    • Dimitris,谢谢,你有相关的#includes 和命名空间别名。另外我忘了提到我正在为 Visual Studio 2013 开发,我倾向于通过#pragma 警告(禁用:4510 4610)(包装在#pragma 警告(push/pop)中)来抑制大量警告 -但我仍然收到很多警告。
    • 实际上,我只是想出了如何通过我赞成的“Boost Log 运行时优化”来编译它。很有用。还有关于自动刷新 - 这对我的日志文件来说并不重要 - 但它适用于终端。事实上,我将有 2 个单独的日志文件(用于不同的日志记录目的 - 所以实际上 3 个日志接收器 - 2 个文件和一个控制台) - 我无法理解的是如何让 LOG("something") 指向它的输出是适当的目标输出。我认为这与过滤器有关,但并不明显,我确定我需要某种 attr 来帮助
    • @johnco3,我认为解决方案在于过滤器。如果您希望 LOG(LEVEL) 首先写入特定接收器,则需要将 severity_level 传递给您不希望它存在的所有接收器初始化函数,然后对其进行过滤,例如sink-&gt;set_filter(boost::log::expressions::attr&lt;severity_level&gt;("Severity") == LEVEL);
    • 我同意,昨天,我从头开始编写了一个 Logger 类来尝试部分成功地解决这个问题 - 使用多个 channel_loggers。记录器类 3 channel_logger 成员使用通道名称初始化。该代码非常类似于: ttps://github.com/boostorg/log/blob/master/example/doc/sources_net_connection_dynamic_chan.cpp 令我困惑的是为什么有必要调用 BOOST_LOG_ATTRIBUTE_KEYWORD(channel, "Channel",第 33 行的 std::string) - 我认为通道是与通道记录器关联的预定义属性。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-29
    • 1970-01-01
    • 1970-01-01
    • 2015-07-26
    相关资源
    最近更新 更多