如何将boost::log::expressions::smessage传递给nlohmann::json构造函数?

egmofgnx  于 2023-01-18  发布在  其他
关注(0)|答案(3)|浏览(117)

我有一个类似的代码:
const auto jsonFormatter = boost::log::expressions::stream << boost::log::expressions::smessage;
我想使用nlohmann::json来转义消息,如下所示:
nlohmann::json json{boost::log::expressions::smessage};
我可以做以下转换boost::log::expressions::smessagestd::string

std::stringstream ss;
ss << boost::log::expressions::smessage;
std::string message = ss.str();
nlohmann::json json{message};

,但我需要将其放入格式化程序中,因为
const auto jsonFormatter = boost::log::expressions::stream << nlohmann::json{boost::log::expressions::smessage};无法将boost::log::expressions::smessage参数转换为任何nlohmann::json构造函数。
有什么建议吗?

ej83mcc0

ej83mcc01#

日志格式化程序看起来像普通的C++,但它们是表达式模板,组成执行相应操作的延迟可调用对象。
下面是如何创建一个知道如何执行此操作的 Package 器表达式:

namespace {
    struct as_json_t {
        template <typename E> auto operator[](E fmt) const {
            return expr::wrap_formatter(
                [fmt](logging::record_view const& rec,
                              logging::formatting_ostream& strm) {
                    logging::formatting_ostream tmp;
                    std::string text;
                    tmp.attach(text);
                    fmt(rec, tmp);

                    strm << nlohmann::json{text};
                });
        }
    };

    inline constexpr as_json_t as_json;
} // namespace

现在你可以让你的格式化程序。

logging::formatter formatter = expr::stream
    << expr::format_date_time(timestamp, "%Y-%m-%d, %H:%M:%S.%f") << " "
    << logging::trivial::severity
    << " - " << as_json[expr::stream << expr::smessage]
    ;

结果是,例如

2021-01-15, 23:34:08.489173 error - ["this is an error message"]

现场演示

    • 一个
  • 文件simpleLogger.h
#ifndef _HOME_SEHE_PROJECTS_STACKOVERFLOW_SIMPLELOGGER_H
 #define _HOME_SEHE_PROJECTS_STACKOVERFLOW_SIMPLELOGGER_H

 #pragma once
 #define BOOST_LOG_DYN_LINK \
     1 // necessary when linking the boost_log library dynamically

 #include <boost/log/sources/global_logger_storage.hpp>
 #include <boost/log/trivial.hpp>

 // the logs are also written to LOGFILE
 #define LOGFILE "logfile.log"

 // just log messages with severity >= SEVERITY_THRESHOLD are written
 #define SEVERITY_THRESHOLD logging::trivial::warning

 // register a global logger
 BOOST_LOG_GLOBAL_LOGGER(logger, boost::log::sources::severity_logger_mt<
                                     boost::log::trivial::severity_level>)

 // just a helper macro used by the macros below - don't use it in your code
 #define LOG(severity) \
     BOOST_LOG_SEV(logger::get(), boost::log::trivial::severity)

 // ===== log macros =====
 #define LOG_TRACE LOG(trace)
 #define LOG_DEBUG LOG(debug)
 #define LOG_INFO LOG(info)
 #define LOG_WARNING LOG(warning)
 #define LOG_ERROR LOG(error)
 #define LOG_FATAL LOG(fatal)

 #endif
  • 文件simpleLogger.cpp
#include "simpleLogger.h"

 #include <boost/core/null_deleter.hpp>
 #include <boost/log/core/core.hpp>
 #include <boost/log/expressions.hpp>
 #include <boost/log/expressions/formatters/char_decorator.hpp>
 #include <boost/log/expressions/formatters/date_time.hpp>
 #include <boost/log/sinks/sync_frontend.hpp>
 #include <boost/log/sinks/text_ostream_backend.hpp>
 #include <boost/log/sources/severity_logger.hpp>
 #include <boost/log/support/date_time.hpp>
 #include <boost/log/trivial.hpp>
 #include <boost/log/utility/setup/common_attributes.hpp>
 #include <nlohmann/json.hpp>
 #include <fstream>

 namespace logging = boost::log;
 namespace src     = boost::log::sources;
 namespace expr    = boost::log::expressions;
 namespace sinks   = boost::log::sinks;
 namespace attrs   = boost::log::attributes;

 BOOST_LOG_ATTRIBUTE_KEYWORD(timestamp, "TimeStamp", boost::posix_time::ptime)
 BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", logging::trivial::severity_level)

 namespace {
     struct as_json_t {
         template <typename E> auto operator[](E fmt) const {
             return expr::wrap_formatter(
                 [fmt](logging::record_view const& rec,
                               logging::formatting_ostream& strm) {
                     logging::formatting_ostream tmp;
                     std::string text;
                     tmp.attach(text);
                     fmt(rec, tmp);

                     strm << nlohmann::json{text};
                 });
         }
     };

     inline constexpr as_json_t as_json;
 } // namespace

 BOOST_LOG_GLOBAL_LOGGER_INIT(logger, src::severity_logger_mt) {
     src::severity_logger_mt<boost::log::trivial::severity_level> logger;

     // add attributes
     logger.add_attribute("TimeStamp", attrs::local_clock()); // each log line gets a timestamp

     // add a text sink
     using text_sink = sinks::synchronous_sink<sinks::text_ostream_backend>;
     boost::shared_ptr<text_sink> sink = boost::make_shared<text_sink>();

     // add a logfile stream to our sink
     sink->locked_backend()->add_stream(
         boost::make_shared<std::ofstream>(LOGFILE));

     // add "console" output stream to our sink
     sink->locked_backend()->add_stream(
         boost::shared_ptr<std::ostream>(&std::clog, boost::null_deleter()));

     // specify the format of the log message
     logging::formatter formatter = expr::stream
         << expr::format_date_time(timestamp, "%Y-%m-%d, %H:%M:%S.%f") << " "
         << logging::trivial::severity
         << " - " << as_json[expr::stream << expr::smessage]
         ;

     sink->set_formatter(formatter);
     // only messages with severity >= SEVERITY_THRESHOLD are written
     sink->set_filter(severity >= SEVERITY_THRESHOLD);

     // "register" our sink
     logging::core::get()->add_sink(sink);

     return logger;
 }
  • 文件test.cpp
#include "simpleLogger.h"

 int main() {
     LOG_TRACE << "this is a trace message";
     LOG_DEBUG << "this is a debug message";
     LOG_WARNING << "this is a warning message";
     LOG_ERROR << "this is an error message";
     LOG_FATAL << "this is a fatal error message";
     return 0;
 }

图纸

2021-01-15, 23:50:03.130250 warning - ["this is a warning message"]
2021-01-15, 23:50:03.130327 error - ["this is an error message"]
2021-01-15, 23:50:03.130354 fatal - ["this is a fatal error message"]
nfzehxib

nfzehxib2#

除了sehe的答案之外,还可以使用Boost.Log组件实现类似JSON的格式,其中最重要的部分是c_decor字符装饰器,它确保其输出可以用作C样式的字符串文字。

namespace expr = boost::log::expressions;

const auto jsonFormatter =
    expr::stream << "[\""
       << expr::c_decor[ expr::stream << expr::smessage ]
       << "\"]";

首先,c_decor将消息中的任何控制字符转义为C样式的转义序列,如\n、\t,还将转义双引号字符,然后添加括号和双引号以使输出与JSON格式兼容。
如果您的日志消息中有非ASCII字符,并且您希望格式化的日志记录为严格的ASCII,则可以使用c_ascii_decor而不是c_decor。除了c_decor的功能外,它还将对任何大于127的字节进行转义,并将其转义为十六进制转义序列,例如\x8c。

lp0sw83n

lp0sw83n3#

我真的很感谢帮助和其他答案,这可能是更好的在其他情况下,但长话短说,我尝试了很多解决方案,并与这一个在最后(我可以更新它,如果它可以改进):

#include <boost/phoenix/bind/bind_function.hpp>
..
nlohmann::json EscapeMessage(
    boost::log::value_ref<std::string, boost::log::expressions::tag::smessage> const& message)
{
    return message ? nlohmann::json(message.get()) : nlohmann::json();
}
..
const auto jsonFormatter = boost::log::expressions::stream << boost::phoenix::bind(&EscapeMessage, boost::log::expressions::smessage.or_none())
boost::log::add_console_log(std::cout, boost::log::keywords::format = jsonFormatter);

相关问题