Logging records
logging record中的所有信息,包括message text,都會被filters, formatters 和 sinks處理。
logging record特性:
- 不能複製,只能被移動boost::move()。它由logging core在filter之後創建,此時內容爲空,隨後attribute value會由attribute生成並添加到log record
- logging record可在formatting和sink時繼續添加attributes
- 多線程環境中,logging record與創建它的線程綁定,所以logging record不能在線程中移動。
讀取這些信息的方式有幾種:
通過 logging::visit
和 logging::value_ref
更詳細參見網頁
enum severity_level { ... };
std::ostream& operator<< (std::ostream& strm, severity_level level);
struct print_visitor
{
typedef void result_type;
result_type operator() (severity_level level) const
{
std::cout << level << std::endl;
};
};
// Prints severity level through visitation API
void print_severity_visitation(logging::record const& rec)
{
logging::visit< severity_level >("Severity", rec, print_visitor());
}
// Prints severity level through extraction API
void print_severity_extraction(logging::record const& rec)
{
logging::value_ref< severity_level > level = logging::extract< severity_level >("Severity", rec);
std::cout << level << std::endl;
}
通過 attribute_values
訪問所有屬性
更詳細參見網頁
// Prints severity level by searching the attribute values
void print_severity_lookup(logging::record const& rec)
{
logging::attribute_value_set const& values = rec.attribute_values();
logging::attribute_value_set::const_iterator it = values.find("Severity");
if (it != values.end())
{
logging::attribute_value const& value = it->second;
// A single attribute value can also be visited or extracted
std::cout << value.extract< severity_level >() << std::endl;
}
}
直接通過下標方式訪問
BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", severity_level)
// Prints severity level by using the subscript operator
void print_severity_subscript(logging::record const& rec)
{
// Use the attribute keyword to communicate the name and type of the value
logging::value_ref< severity_level, tag::severity > level = rec[severity];
std::cout << level << std::endl;
}
Record view
與logging record相似, record用來填充信息,record view用來後續處理:
- record view不可變,可防止formatter及sink修改它
- record view可複製,因爲內容不可改,使用淺複製成本很低
boost會自動在lock函數被調用時,爲record創建record view:
- record view不會綁定到線程
- record 會在lock結束後變空值,因爲record只被處理一次
Logging core
logging core是庫的核心,提供:
- 維護全局和各線程的attribute sets
- 處理log record的全局過濾
- 應用sink的filter在sink間傳遞log record
- 提供全局的exception handler
- 提供全局的log record輸入口
- 提供flush強制輸出
訪問方式
boost::shared_ptr< logging::core > core = logging::core::get();
Attribute sets
添加/刪除全局屬性add_global_attribute
和remove_global_attribute
添加/刪除線程屬性add_thread_attribute
和remove_thread_attribute
void foo()
{
boost::shared_ptr< logging::core > core = logging::core::get();
// Add a global attribute
// 返回值第一個參數是其被添加後的索引,bool代表是否添加成功
std::pair< logging::attribute_set::iterator, bool > res =
core->add_global_attribute("LineID", attrs::counter< unsigned int >());
// Do something ...
// Remove the added attribute
core->remove_global_attribute(res.first);
}
logging::core的所有方法都是線程安全的,但索引不能保證線程安全
獲取/設置全局屬性get_global_attributes
和set_global_attributes
獲取/設置線程屬性get_thread_attributes
和set_thread_attributes
Global filtering
filter讀入一組參數,返回此record是否通過
設置/清除filter的函數set_filter
/ reset_filter
,filter沒有設置,相當於所有log record可通過
通過set_logging_enabled
,可設置filter是否生效,比較設置filter更高效。
Sink management
添加/刪除sink的函數,add_sink
和remove_sink
。添加的sink會保存到logging core中,但sink的執行順序是不確定的。
void foo()
{
boost::shared_ptr< logging::core > core = logging::core::get();
// Set a sink that will write log records to the console
boost::shared_ptr< sinks::text_ostream_backend > backend =
boost::make_shared< sinks::text_ostream_backend >();
backend->add_stream(
boost::shared_ptr< std::ostream >(&std::clog, boost::null_deleter()));
typedef sinks::unlocked_sink< sinks::text_ostream_backend > sink_t;
boost::shared_ptr< sink_t > sink = boost::make_shared< sink_t >(backend);
core->add_sink(sink);
// ...
// Remove the sink
core->remove_sink(sink);
}
Exception handling
添加異常處理類,通過set_exception_handler
設置,其參數是無參數函數,在catch語句中被調用。
logging core中的異常處理類只應該處理通用錯誤。
Logging sinks 和 sources 可做更細緻的異常處理,參見
sink異常處理和source異常處理
struct my_handler
{
typedef void result_type;
void operator() (std::runtime_error const& e) const
{
std::cout << "std::runtime_error: " << e.what() << std::endl;
}
void operator() (std::logic_error const& e) const
{
std::cout << "std::logic_error: " << e.what() << std::endl;
throw;
}
};
void init_exception_handler()
{
// Setup a global exception handler that will call my_handler::operator()
// for the specified exception types
logging::core::get()->set_exception_handler(logging::make_exception_handler<
std::runtime_error, /*處理的錯誤類型*/
std::logic_error
>(my_handler()));
}
Feeding log records
logging core最重要的功能之一就是創建和推送log record,實現函數分別爲open_record
和push_record
.
open_record
收集global, thread-specific 和 source-specific的屬性,判斷是否會被filter掉,如果沒有被filter掉(至少有一個sink接收這個record),函數會返回一個log record對象push_record
在由open_record
獲得的record對象填寫完內容後調用。之後record view對象會從record對象中生成,並傳給接收它的多個sink,這個過程中會發生formatting及保存到文件等操作,視情況而不同。隨後record對象被銷燬。
void logging_function(logging::attribute_set const& attrs)
{
boost::shared_ptr< logging::core > core = logging::core::get();
// Attempt to open a log record
logging::record rec = core->open_record(attrs);
if (rec)
{
// Ok, the record is accepted. Compose the message now.
logging::record_ostream strm(rec);
strm << "Hello, World!";
strm.flush();
// Deliver the record to the sinks.
core->push_record(boost::move(rec));
}
}