宽字符记录
Boost.Log支持包含本地字符集字符串的日志记录。基本上有两种方式做这件事。在 UNIX 系统上通常使用一些多字节字符编码 (例如 UTF-8) 用来表示本地字符。在这种情况下,Boost.Log库可以直接以纯 ASCII 的方式记录而不需要其它额外的设置。
在Windows 上常见的做法是使用宽字符串来表示本地字符串。此外大多数系统 API 也是使用的宽字符,这需要特定于 Windows 的接收器也支持宽字符。另一方面,通用的接收器,例如 TextFile,是面向字节的,你写入文件的是字节,而不是字符。这迫使Boost.Log库进行字符编码转换时需要通过接收器。在接收器上指定合适的区域设置,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
national characters (
"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_date_time函数("%Y-%m-%d, %H:%M:%S.%f"不能是宽字符)。另外请注意,我们使用的 message 关键字来表示日志记录信息。此占位符支持非宽字符和宽字符的信息,所以格式化器将使用两者。作为格式的过程的一部分,Boost.Log库将转换为宽字符消息使用了多字节的区域编码,我们设置为UTF-8。
[提示]属性值也可以包含宽字符串。像日志记录的消息,这些字符串将被转换以imbued locale为目标的字符编码。
在这里我们缺少severity_level类型定义。类型仅仅是一个枚举,但如果我们想要其格式支持宽和非宽字符的接收器,就需要对它流的<<运算符重载模板函数进行特化了。
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;
}
现在我们可以发出消息了,但是必须要用 "w" 为前缀的记录器来撰写消息记录。
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";
}
正如你所看到的,宽字符消息组成类似于非宽字符消息。请注意,您可以在同一时间同时使用宽和非字符记录,所有记录都将通过我们文件接收器进行处理。这个例子的完整代码可以在这里找到。
必须指出的是一些接收器(主要是Windows特定的)允许指定目标的字符类型。如果期望使用本地字符写日志记录,应始终使用 wchar_t 作为目标字符类型。因为接收器将采用宽字符的操作系统API来处理日志记录。