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進行加寬。
Boost Log : Wide character logging