Boost Log : Wide character logging

Wide character logging

Log库支持记录包含不同national characters的字符串。基本上有两种方法可以做到这一点。在类unix系统中,通常使用多字节字符编码(例如UTF-8)来表示national characters。在这种情况下,Log库可以像普通ASCII日志记录那样使用,不需要任何额外设置。

在Windows上,常见的做法是使用宽字符串表示national characters。而且,大多数系统API都是面向宽字符的,这就要求特定于windows的sink也支持宽字符串。另一方面,通用sinks,比如文本文件sink,是面向字节的(因为,你将在文件中存储字节,而不是字符)。这将强制Log库在sink需要时执行字符代码转换。要为Log做这样的设置,必须使用带有适当codecvt方面的语言环境来设置sink。Boost.Locale可以用于生成这样的语言环境。让我们看一个例子:

// Declare attribute keywords
BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", severity_level)
BOOST_LOG_ATTRIBUTE_KEYWORD(timestamp, "TimeStamp", boost::posix_time::ptime)

void init_logging()
{
    boost::shared_ptr< sinks::synchronous_sink< sinks::text_file_backend > > sink = logging::add_file_log
    (
        "sample.log",
        keywords::format = expr::stream
            << expr::format_date_time(timestamp, "%Y-%m-%d, %H:%M:%S.%f")
            << " <" << severity.or_default(normal)
            << "> " << expr::message
    );

    // The sink will perform character code conversion as needed, according to the locale set with imbue()
    std::locale loc = boost::locale::generator()("en_US.UTF-8");
    sink->imbue(loc);

    // Let's add some commonly used attributes, like timestamp and record counter.
    logging::add_common_attributes();
}

首先,让我们看一下传入format参数的formatter。我们使用窄字符formatter初始化sink,因为文本文件sink处理字节。可以在formatter中使用宽字符串,但不能在格式字符串中使用,就像我们在format_date_time函数中使用的一样。还要注意,我们使用message关键字来表示log record消息。这个占位符支持窄字符和宽字符消息,所以formatter可以同时使用这两种消息。作为格式化过程的一部分,Log库将使用输入的语言环境(我们将其设置为UTF-8)将宽字符消息转换为多字节编码。

Tip
Attribute values也可以包含宽字符串。Log record消息一样,这些字符串将使用设置的语言环境转换为目标字符编码。

这里缺少的一点是我们的severity_level类型定义。该类型只是一个枚举,但如果我们想要支持其窄格式和宽字符格式的sink,其stream操作符必须是模板。如果我们使用不同的字符类型创建多个sinks,这可能会很有用。

enum severity_level
{
    normal,
    notification,
    warning,
    error,
    critical
};

template< typename CharT, typename TraitsT >
inline std::basic_ostream< CharT, TraitsT >& operator<< (
    std::basic_ostream< CharT, TraitsT >& strm, severity_level lvl)
{
    static const char* const str[] =
    {
        "normal",
        "notification",
        "warning",
        "error",
        "critical"
    };
    if (static_cast< std::size_t >(lvl) < (sizeof(str) / sizeof(*str)))
        strm << str[lvl];
    else
        strm << static_cast< int >(lvl);
    return strm;
}

现在我们可以发出log records。我们可以使用带有w前缀的loggers来组成宽字符消息。

void test_narrow_char_logging()
{
    // Narrow character logging still works
    src::logger lg;
    BOOST_LOG(lg) << "Hello, World! This is a narrow character message.";
}

void test_wide_char_logging()
{
    src::wlogger lg;
    BOOST_LOG(lg) << L"Hello, World! This is a wide character message.";

    // National characters are also supported
    const wchar_t national_chars[] = { 0x041f, 0x0440, 0x0438, 0x0432, 0x0435, 0x0442, L',', L' ', 0x043c, 0x0438, 0x0440, L'!', 0 };
    BOOST_LOG(lg) << national_chars;

    // Now, let's try logging with severity
    src::wseverity_logger< severity_level > slg;
    BOOST_LOG_SEV(slg, normal) << L"A normal severity message, will not pass to the file";
    BOOST_LOG_SEV(slg, warning) << L"A warning severity message, will pass to the file";
    BOOST_LOG_SEV(slg, error) << L"An error severity message, will pass to the file";
}

如您所见,宽字符消息组合类似于窄日志记录。注意,您可以同时使用窄字符和宽字符日志;所有记录将由我们的文件sink处理。这个示例的完整代码可以在这里找到。

必须注意的是,有些sinks(大部分是特定于windows的)允许指定目标字符类型。当日志记录中需要使用national characters时,应该始终使用wchar_t作为目标字符类型,因为sink将使用宽字符OS API来处理log records。在这种情况下,当执行格式化时,所有窄字符字符串都将使用嵌入到sink中的locale进行加宽。

原文地址:https://www.cnblogs.com/kohlrabi/p/9160494.html