C++ Boost log日志庫超詳細(xì)講解
一、說明
應(yīng)用程序庫是指通常專門用于獨立應(yīng)用程序開發(fā)而不用于庫開發(fā)的庫。
- Boost.Log 是一個日志庫。
- Boost.ProgramOptions 是一個用于定義和解析命令行選項的庫。
- Boost.Serialization 允許您序列化對象,例如,將它們保存到文件或從文件加載它們。
- Boost.Uuid 支持使用 UUID。
具體內(nèi)容
二、庫Boost.Log
Boost.Log 是 Boost 中的日志記錄庫。它支持眾多后端以各種格式記錄數(shù)據(jù)。通過以不同方式捆綁服務(wù)和轉(zhuǎn)發(fā)日志條目的前端訪問后端。例如,有一個前端使用線程異步轉(zhuǎn)發(fā)日志條目。前端可以有過濾器來忽略某些日志條目。他們定義了如何將日志條目格式化為字符串。所有這些功能都是可擴(kuò)展的,這使得 Boost.Log 成為一個強大的庫。
示例 62.1。后端、前端、核心和記錄器
#include <boost/log/common.hpp> #include <boost/log/sinks.hpp> #include <boost/log/sources/logger.hpp> #include <boost/utility/empty_deleter.hpp> #include <boost/shared_ptr.hpp> #include <iostream> using namespace boost::log; int main() { typedef sinks::asynchronous_sink<sinks::text_ostream_backend> text_sink; boost::shared_ptr<text_sink> sink = boost::make_shared<text_sink>(); boost::shared_ptr<std::ostream> stream{&std::clog, boost::empty_deleter{}}; sink->locked_backend()->add_stream(stream); core::get()->add_sink(sink); sources::logger lg; BOOST_LOG(lg) << "note"; sink->flush(); }
示例 62.1 介紹了 Boost.Log 的基本組件。 Boost.Log 使您可以訪問后端、前端、核心和記錄器:
后端決定數(shù)據(jù)寫入的位置。 boost::log::sinks::text_ostream_backend 使用 std::ostream 類型的流進(jìn)行初始化,并將日志條目寫入其中。
前端是核心和后端之間的連接。它們實現(xiàn)了不需要由每個單獨的后端實現(xiàn)的各種功能。例如,可以將過濾器添加到前端以選擇將哪些日志條目轉(zhuǎn)發(fā)到后端,哪些不轉(zhuǎn)發(fā)。
示例 62.1 使用前端 boost::log::sinks::asynchronous_sink。即使不使用過濾器,也必須使用前端。 boost::log::sinks::asynchronous_sink 使用一個線程將日志條目異步轉(zhuǎn)發(fā)到后端。這可以提高性能但會延遲寫入操作。
核心是所有日志條目路由通過的中央組件。它是作為單例實現(xiàn)的。要獲取指向核心的指針,請調(diào)用 boost::log::core::get()。
必須將前端添加到核心才能接收日志條目。日志條目是否轉(zhuǎn)發(fā)到前端取決于核心中的過濾器。過濾器可以在前端或核心中注冊。在核心注冊的過濾器是全局的,在前端注冊的過濾器是本地的。如果日志條目被核心過濾掉,則不會轉(zhuǎn)發(fā)到任何前端。如果它被一個前端過濾了,它仍然可以被其他前端處理并轉(zhuǎn)發(fā)給它們的后端。
記錄器是 Boost.Log 中您最常使用的組件。雖然只有在初始化日志庫時才能訪問后端、前端和核心,但每次寫入日志條目時都會使用一個記錄器。記錄器將條目轉(zhuǎn)發(fā)給核心。
示例 62.1 中的記錄器屬于 boost::log::sources::logger 類型。這是最簡單的記錄器。當(dāng)你想寫一個日志條目時,使用宏 BOOST_LOG 并將記錄器作為參數(shù)傳遞。日志條目是通過將數(shù)據(jù)寫入宏來創(chuàng)建的,就好像它是 std::ostream 類型的流一樣。
后端、前端、核心和記錄器協(xié)同工作。 boost::log::sinks::asynchronous_sink 是一個前端,它是一個接收后端 boost::log::sinks::text_ostream_backend 作為參數(shù)的模板。之后,前端使用 boost::shared_ptr 實例化。智能指針需要在核心中注冊前端:對 boost::log::core::add_sink() 的調(diào)用需要一個 boost::shared_ptr。
因為后端是前端的模板參數(shù),所以只能在前端實例化后配置。后端決定這是如何完成的。后端 boost::log::sinks::text_ostream_backend 提供成員函數(shù) add_stream() 添加流。您可以向 boost::log::sinks::text_ostream_backend 添加多個流。其他后端提供不同的成員函數(shù)進(jìn)行配置。有關(guān)詳細(xì)信息,請參閱文檔。
為了訪問后端,所有前端都提供成員函數(shù) locked_backend()。此成員函數(shù)稱為 locked_backend(),因為它返回一個指針,只要該指針存在,該指針就會提供對后端的同步訪問。您可以通過 locked_backend() 返回的指針從多個線程訪問后端,而無需自己同步訪問。
您可以使用默認(rèn)構(gòu)造函數(shù)實例化一個記錄器,例如 boost::log::sources::logger。記錄器自動調(diào)用 boost::log::core::get() 將日志條目轉(zhuǎn)發(fā)到核心。
您可以在沒有宏的情況下訪問記錄器。記錄器是具有您可以調(diào)用的成員函數(shù)的對象。但是,像 BOOST_LOG 這樣的宏可以更輕松地編寫日志條目。如果沒有宏,就不可能用一行代碼編寫日志條目。
示例 62.1 在 main() 的末尾調(diào)用 boost::log::sinks::asynchronous_sink::flush()。此調(diào)用是必需的,因為前端是異步的并且使用線程來轉(zhuǎn)發(fā)日志條目。該調(diào)用確保所有緩沖的日志條目都傳遞到后端并被寫入。如果不調(diào)用 flush(),該示例可能會在不顯示注釋的情況下終止。
示例 62.2。帶有過濾器的 boost::sources::severity_logger
#include <boost/log/common.hpp> #include <boost/log/sinks.hpp> #include <boost/log/sources/severity_logger.hpp> #include <boost/utility/empty_deleter.hpp> #include <boost/shared_ptr.hpp> #include <iostream> using namespace boost::log; bool only_warnings(const attribute_value_set &set) { return set["Severity"].extract<int>() > 0; } int main() { typedef sinks::asynchronous_sink<sinks::text_ostream_backend> text_sink; boost::shared_ptr<text_sink> sink = boost::make_shared<text_sink>(); boost::shared_ptr<std::ostream> stream{&std::clog, boost::empty_deleter{}}; sink->locked_backend()->add_stream(stream); sink->set_filter(&only_warnings); core::get()->add_sink(sink); sources::severity_logger<int> lg; BOOST_LOG(lg) << "note"; BOOST_LOG_SEV(lg, 0) << "another note"; BOOST_LOG_SEV(lg, 1) << "warning"; sink->flush(); }
示例 62.2 基于示例 62.1,但它用記錄器 boost::sources::severity_logger 替換了 boost::sources::logger。此記錄器將日志級別的屬性添加到每個日志條目。您可以使用宏 BOOST_LOG_SEV 來設(shè)置日志級別。
日志級別的類型取決于傳遞給 boost::sources::severity_logger 的模板參數(shù)。示例 62.2 使用 int。這就是將 0 和 1 之類的數(shù)字傳遞給 BOOST_LOG_SEV 的原因。如果使用 BOOST_LOG,日志級別設(shè)置為 0。
示例 62.2 還調(diào)用 set_filter() 在前端注冊過濾器。為每個日志條目調(diào)用過濾器函數(shù)。如果該函數(shù)返回 true,日志條目將轉(zhuǎn)發(fā)到后端。示例 62.2 定義了函數(shù) only_warnings(),其返回值為 bool 類型。
only_warnings() 需要一個類型為 boost::log::attribute_value_set 的參數(shù)。此類型表示在日志記錄框架中傳遞的日志條目。 boost::log::r??ecord 是另一種日志條目類型,類似于 boost::log::attribute_value_set 的包裝器。此類型提供成員函數(shù) attribute_values(),它檢索對 boost::log::attribute_value_set 的引用。過濾器函數(shù)直接接收 boost::log::attribute_value_set 而沒有 boost::log::r??ecord。 boost::log::attribute_value_set 存儲鍵/值對。將其視為 std::unordered_map。
日志條目由屬性組成。屬性有名稱和值。您可以自己創(chuàng)建屬性。它們也可以自動創(chuàng)建——例如由記錄器創(chuàng)建。事實上,這就是 Boost.Log 提供多個記錄器的原因。 boost::log::sources::severity_logger 向每個日志條目添加一個名為 Severity 的屬性。該屬性存儲日志級別。這樣過濾器就可以檢查日志條目的日志級別是否大于 0。
boost::log::attribute_value_set 提供了幾個成員函數(shù)來訪問屬性。成員函數(shù)類似于 std::unordered_map 提供的成員函數(shù)。例如,boost::log::attribute_value_set 重載運算符 operator[]。此運算符返回其名稱作為參數(shù)傳遞的屬性的值。如果該屬性不存在,則會創(chuàng)建它。
屬性名稱的類型是 boost::log::attribute_name。此類提供了一個接受字符串的構(gòu)造函數(shù),因此您可以將字符串直接傳遞給 operator[],如示例 62.2 所示。
屬性值的類型是 boost::log::attribute_value。此類提供成員函數(shù)來接收屬性原始類型的值。因為日志級別是一個 int 值,所以 int 作為模板參數(shù)傳遞給 extract()。
boost::log::attribute_value 還定義了成員函數(shù) extract_or_default() 和 extract_or_throw()。如果類型轉(zhuǎn)換失敗,extract() 會返回一個使用默認(rèn)構(gòu)造函數(shù)創(chuàng)建的值——例如,如果是 int,則為 0。 extract_or_default() 返回一個默認(rèn)值,該值作為另一個參數(shù)傳遞給該成員函數(shù)。 extract_or_throw() 在發(fā)生錯誤時拋出類型為 boost::log::r??untime_error 的異常。
對于類型安全的轉(zhuǎn)換,Boost.Log 提供訪問者函數(shù) boost::log::visit(),您可以使用它代替 extract()。
示例 62.2 顯示警告。此日志條目的日志級別大于 0,因此未被過濾。
示例 62.3。使用 set_formatter() 更改日志條目的格式
#include <boost/log/common.hpp> #include <boost/log/sinks.hpp> #include <boost/log/sources/severity_logger.hpp> #include <boost/utility/empty_deleter.hpp> #include <boost/shared_ptr.hpp> #include <iostream> using namespace boost::log; void severity_and_message(const record_view &view, formatting_ostream &os) { os << view.attribute_values()["Severity"].extract<int>() << ": " << view.attribute_values()["Message"].extract<std::string>(); } int main() { typedef sinks::asynchronous_sink<sinks::text_ostream_backend> text_sink; boost::shared_ptr<text_sink> sink = boost::make_shared<text_sink>(); boost::shared_ptr<std::ostream> stream{&std::clog, boost::empty_deleter{}}; sink->locked_backend()->add_stream(stream); sink->set_formatter(&severity_and_message); core::get()->add_sink(sink); sources::severity_logger<int> lg; BOOST_LOG_SEV(lg, 0) << "note"; BOOST_LOG_SEV(lg, 1) << "warning"; sink->flush(); }
日志條目由屬性組成。屬性有名稱和值。您可以自己創(chuàng)建屬性。它們也可以自動創(chuàng)建——例如由記錄器創(chuàng)建。事實上,這就是 Boost.Log 提供多個記錄器的原因。 boost::log::sources::severity_logger 向每個日志條目添加一個名為 Severity 的屬性。該屬性存儲日志級別。這樣過濾器就可以檢查日志條目的日志級別是否大于 0。
boost::log::attribute_value_set 提供了幾個成員函數(shù)來訪問屬性。成員函數(shù)類似于 std::unordered_map 提供的成員函數(shù)。例如,boost::log::attribute_value_set 重載運算符 operator[]。此運算符返回其名稱作為參數(shù)傳遞的屬性的值。如果該屬性不存在,則會創(chuàng)建它。
屬性名稱的類型是 boost::log::attribute_name。此類提供了一個接受字符串的構(gòu)造函數(shù),因此您可以將字符串直接傳遞給 operator[],如示例 62.2 所示。
屬性值的類型是 boost::log::attribute_value。此類提供成員函數(shù)來接收屬性原始類型的值。因為日志級別是一個 int 值,所以 int 作為模板參數(shù)傳遞給 extract()。
boost::log::attribute_value 還定義了成員函數(shù) extract_or_default() 和 extract_or_throw()。如果類型轉(zhuǎn)換失敗,extract() 會返回一個使用默認(rèn)構(gòu)造函數(shù)創(chuàng)建的值——例如,如果是 int,則為 0。 extract_or_default() 返回一個默認(rèn)值,該值作為另一個參數(shù)傳遞給該成員函數(shù)。 extract_or_throw() 在發(fā)生錯誤時拋出類型為 boost::log::r??untime_error 的異常。
對于類型安全的轉(zhuǎn)換,Boost.Log 提供訪問者函數(shù) boost::log::visit(),您可以使用它代替 extract()。
示例 62.2 顯示警告。此日志條目的日志級別大于 0,因此未被過濾。
示例 62.3。使用 set_formatter() 更改日志條目的格式
#include <boost/log/common.hpp> #include <boost/log/sinks.hpp> #include <boost/log/sources/severity_logger.hpp> #include <boost/log/expressions.hpp> #include <boost/utility/empty_deleter.hpp> #include <boost/shared_ptr.hpp> #include <iostream> using namespace boost::log; int main() { typedef sinks::asynchronous_sink<sinks::text_ostream_backend> text_sink; boost::shared_ptr<text_sink> sink = boost::make_shared<text_sink>(); boost::shared_ptr<std::ostream> stream{&std::clog, boost::empty_deleter{}}; sink->locked_backend()->add_stream(stream); sink->set_filter(expressions::attr<int>("Severity") > 0); sink->set_formatter(expressions::stream << expressions::attr<int>("Severity") << ": " << expressions::smessage); core::get()->add_sink(sink); sources::severity_logger<int> lg; BOOST_LOG_SEV(lg, 0) << "note"; BOOST_LOG_SEV(lg, 1) << "warning"; BOOST_LOG_SEV(lg, 2) << "error"; sink->flush(); }
示例 62.4 同時使用了過濾器和格式化函數(shù)。這次函數(shù)作為 lambda 函數(shù)實現(xiàn)——不是 C++11 lambda 函數(shù),而是 Boost.Phoenix lambda 函數(shù)。
Boost.Log 為命名空間 boost::log::expressions 中的 lambda 函數(shù)提供助手。例如,boost::log::expressions::stream 代表流。 boost::log::expressions::smessage 提供對 BOOST_LOG 等宏右側(cè)所有內(nèi)容的訪問。您可以使用 boost::log::expressions::attr() 來訪問任何屬性。示例 62.4 可以使用 attr<std::string>("Message") 而不是消息。
示例 62.4 顯示 1:警告和 2:錯誤。
示例 62.5。為屬性定義關(guān)鍵字
#include <boost/log/common.hpp> #include <boost/log/sinks.hpp> #include <boost/log/sources/severity_logger.hpp> #include <boost/log/expressions.hpp> #include <boost/utility/empty_deleter.hpp> #include <boost/shared_ptr.hpp> #include <iostream> using namespace boost::log; BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", int) int main() { typedef sinks::asynchronous_sink<sinks::text_ostream_backend> text_sink; boost::shared_ptr<text_sink> sink = boost::make_shared<text_sink>(); boost::shared_ptr<std::ostream> stream{&std::clog, boost::empty_deleter{}}; sink->locked_backend()->add_stream(stream); sink->set_filter(severity > 0); sink->set_formatter(expressions::stream << severity << ": " << expressions::smessage); core::get()->add_sink(sink); sources::severity_logger<int> lg; BOOST_LOG_SEV(lg, 0) << "note"; BOOST_LOG_SEV(lg, 1) << "warning"; BOOST_LOG_SEV(lg, 2) << "error"; sink->flush(); }
Boost.Log 支持用戶定義的關(guān)鍵字。您可以使用宏 BOOST_LOG_ATTRIBUTE_KEYWORD 定義關(guān)鍵字來訪問屬性,而不必將屬性名稱作為字符串重復(fù)傳遞給 boost::log::expressions::attr()。
示例 62.5 使用宏 BOOST_LOG_ATTRIBUTE_KEYWORD 來定義關(guān)鍵字嚴(yán)重性。該宏需要三個參數(shù):關(guān)鍵字名稱、字符串形式的屬性名稱和屬性類型。 new 關(guān)鍵字可用于過濾和格式化 lambda 函數(shù)。這意味著您不限于使用由 Boost.Log 提供的關(guān)鍵字,例如 boost::log::expressions::smessage – 您還可以定義新的關(guān)鍵字。
到目前為止,在所有示例中,使用的屬性都是在 Boost.Log 中定義的。示例 62.6 顯示了如何創(chuàng)建用戶定義的屬性。
示例 62.6。定義屬性
#include <boost/log/common.hpp> #include <boost/log/sinks.hpp> #include <boost/log/sources/severity_logger.hpp> #include <boost/log/expressions.hpp> #include <boost/log/attributes.hpp> #include <boost/log/support/date_time.hpp> #include <boost/utility/empty_deleter.hpp> #include <boost/shared_ptr.hpp> #include <iostream> using namespace boost::log; BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", int) BOOST_LOG_ATTRIBUTE_KEYWORD(counter, "LineCounter", int) BOOST_LOG_ATTRIBUTE_KEYWORD(timestamp, "Timestamp", boost::posix_time::ptime) int main() { typedef sinks::asynchronous_sink<sinks::text_ostream_backend> text_sink; boost::shared_ptr<text_sink> sink = boost::make_shared<text_sink>(); boost::shared_ptr<std::ostream> stream{&std::clog, boost::empty_deleter{}}; sink->locked_backend()->add_stream(stream); sink->set_filter(severity > 0); sink->set_formatter(expressions::stream << counter << " - " << severity << ": " << expressions::smessage << " (" << timestamp << ")"); core::get()->add_sink(sink); core::get()->add_global_attribute("LineCounter", attributes::counter<int>{}); sources::severity_logger<int> lg; BOOST_LOG_SEV(lg, 0) << "note"; BOOST_LOG_SEV(lg, 1) << "warning"; { BOOST_LOG_SCOPED_LOGGER_ATTR(lg, "Timestamp", attributes::local_clock{}) BOOST_LOG_SEV(lg, 2) << "error"; } BOOST_LOG_SEV(lg, 2) << "another error"; sink->flush(); }
您可以通過在核心上調(diào)用 add_global_attribute() 來創(chuàng)建全局屬性。該屬性是全局的,因為它會自動添加到每個日志條目中。
add_global_attribute() 需要兩個參數(shù):新屬性的名稱和類型。名稱作為字符串傳遞。對于您使用命名空間 boost::log::attributes 中的類的類型,它提供類來定義不同的屬性。示例 62.6 使用 boost::log::attributes::counter 來定義屬性 LineCounter,它為每個日志條目添加一個行號。此屬性將從 1 開始對日志條目進(jìn)行編號。
add_global_attribute() 不是函數(shù)模板。 boost::log::attributes::counter 不作為模板參數(shù)傳遞。屬性類型必須實例化并作為對象傳遞。
示例 62.6 使用名為時間戳的第二個屬性。這是一個使用 BOOST_LOG_SCOPED_LOGGER_ATTR 創(chuàng)建的范圍屬性。此宏將屬性添加到記錄器。第一個參數(shù)是logger,第二個是屬性名,第三個是屬性對象。屬性對象的類型是 boost::log::attribute::local_clock。該屬性設(shè)置為每個日志條目的當(dāng)前時間。
屬性時間戳僅添加到日志條目“錯誤”。時間戳僅存在于使用 BOOST_LOG_SCOPED_LOGGER_ATTR 的范圍內(nèi)。當(dāng)范圍結(jié)束時,該屬性將被刪除。 BOOST_LOG_SCOPED_LOGGER_ATTR 類似于對 add_attribute() 和 remove_attribute() 的調(diào)用。
與示例 62.5 一樣,示例 62.6 使用宏 BOOST_LOG_ATTRIBUTE_KEYWORD 為新屬性定義關(guān)鍵字。 format 函數(shù)訪問關(guān)鍵字以寫入行號和當(dāng)前時間。對于那些未定義屬性時間戳的日志條目,時間戳的值將為空字符串。
示例 62.7。過濾器和格式的輔助函數(shù)
#include <boost/log/common.hpp> #include <boost/log/sinks.hpp> #include <boost/log/sources/severity_logger.hpp> #include <boost/log/expressions.hpp> #include <boost/log/attributes.hpp> #include <boost/log/support/date_time.hpp> #include <boost/utility/empty_deleter.hpp> #include <boost/shared_ptr.hpp> #include <iostream> #include <iomanip> using namespace boost::log; BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", int) BOOST_LOG_ATTRIBUTE_KEYWORD(counter, "LineCounter", int) BOOST_LOG_ATTRIBUTE_KEYWORD(timestamp, "Timestamp", boost::posix_time::ptime) int main() { typedef sinks::asynchronous_sink<sinks::text_ostream_backend> text_sink; boost::shared_ptr<text_sink> sink = boost::make_shared<text_sink>(); boost::shared_ptr<std::ostream> stream{&std::clog, boost::empty_deleter{}}; sink->locked_backend()->add_stream(stream); sink->set_filter(expressions::is_in_range(severity, 1, 3)); sink->set_formatter(expressions::stream << std::setw(5) << counter << " - " << severity << ": " << expressions::smessage << " (" << expressions::format_date_time(timestamp, "%H:%M:%S") << ")"); core::get()->add_sink(sink); core::get()->add_global_attribute("LineCounter", attributes::counter<int>{}); sources::severity_logger<int> lg; BOOST_LOG_SEV(lg, 0) << "note"; BOOST_LOG_SEV(lg, 1) << "warning"; { BOOST_LOG_SCOPED_LOGGER_ATTR(lg, "Timestamp", attributes::local_clock{}) BOOST_LOG_SEV(lg, 2) << "error"; } BOOST_LOG_SEV(lg, 2) << "another error"; sink->flush(); }
Boost.Log 為過濾器和格式提供了大量的輔助函數(shù)。示例 62.7 調(diào)用助手 boost::log::expressions::is_in_range() 來過濾日志級別超出范圍的日志條目。 boost::log::expressions::is_in_range() 期望屬性作為它的第一個參數(shù),下限和上限作為它的第二和第三個參數(shù)。與迭代器一樣,上限是唯一的,不屬于范圍。
boost::log::expressions::format_date_time() 在格式函數(shù)中被調(diào)用。它用于格式化時間點。示例 62.7 使用 boost::log::expressions::format_date_time() 來寫入沒有日期的時間。您還可以在格式函數(shù)中使用標(biāo)準(zhǔn)庫中的操縱器。示例 62.7 使用 std::setw() 設(shè)置計數(shù)器的寬度。
示例 62.8。幾個記錄器、前端和后端
#include <boost/log/common.hpp> #include <boost/log/sinks.hpp> #include <boost/log/sources/severity_logger.hpp> #include <boost/log/sources/channel_logger.hpp> #include <boost/log/expressions.hpp> #include <boost/log/attributes.hpp> #include <boost/log/utility/string_literal.hpp> #include <boost/utility/empty_deleter.hpp> #include <boost/shared_ptr.hpp> #include <iostream> #include <string> using namespace boost::log; BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", int) BOOST_LOG_ATTRIBUTE_KEYWORD(channel, "Channel", std::string) int main() { typedef sinks::asynchronous_sink<sinks::text_ostream_backend> ostream_sink; boost::shared_ptr<ostream_sink> ostream = boost::make_shared<ostream_sink>(); boost::shared_ptr<std::ostream> clog{&std::clog, boost::empty_deleter{}}; ostream->locked_backend()->add_stream(clog); core::get()->add_sink(ostream); typedef sinks::synchronous_sink<sinks::text_multifile_backend> multifile_sink; boost::shared_ptr<multifile_sink> multifile = boost::make_shared<multifile_sink>(); multifile->locked_backend()->set_file_name_composer( sinks::file::as_file_name_composer(expressions::stream << channel.or_default<std::string>("None") << "-" << severity.or_default(0) << ".log")); core::get()->add_sink(multifile); sources::severity_logger<int> severity_lg; sources::channel_logger<> channel_lg{keywords::channel = "Main"}; BOOST_LOG_SEV(severity_lg, 1) << "severity message"; BOOST_LOG(channel_lg) << "channel message"; ostream->flush(); }
示例 62.8 使用了多個記錄器、前端和后端。除了使用類 boost::log::sinks::asynchronous_sink、boost::log::sinks::text_ostream_backend 和 boost::log::sources::severity_logger,該示例還使用了前端 boost:: log::sinks::synchronous_sink、后端 boost::log::sinks::text_multifile_backend 和記錄器 boost::log::sources::channel_logger。
前端 boost::log::sinks::synchronous_sink 提供對后端的同步訪問,即使后端不是線程安全的,它也允許您在多線程應(yīng)用程序中使用后端。
boost::log::sinks::asynchronous_sink 和 boost::log::sinks::synchronous_sink 這兩個前端的區(qū)別在于后者不基于線程。日志條目在同一線程中傳遞到后端。
示例 62.8 使用前端 boost::log::sinks::synchronous_sink 和后端 boost::log::sinks::text_multifile_backend。該后端將日志條目寫入一個或多個文件。文件名是根據(jù) set_file_name_composer() 傳遞給后端的規(guī)則創(chuàng)建的。如果您使用獨立函數(shù) boost::log::sinks::file::as_file_name_composer(),如示例中所示,則可以將規(guī)則創(chuàng)建為 lambda 函數(shù),并使用與格式函數(shù)相同的構(gòu)建塊。但是,這些屬性不用于創(chuàng)建寫入后端的字符串。相反,該字符串將是日志條目將寫入的文件的名稱。
示例 62.8 使用關(guān)鍵字 channel 和 severity,它們是用宏 BOOST_LOG_ATTRIBUTE_KEYWORD 定義的。它們指的是屬性 Channel 和 Severity。如果未設(shè)置屬性,則對關(guān)鍵字調(diào)用成員函數(shù) or_default() 以傳遞默認(rèn)值。如果寫入日志條目但未設(shè)置通道和嚴(yán)重性,則該條目將寫入文件 None-0.log。如果日志條目以日志級別 1 寫入,它將存儲在文件 None-1.log 中。如果日志級別為 1 且通道名為 Main,則日志條目將保存在文件 Main-1.log 中。
屬性 Channel 由記錄器 boost::log::sources::channel_logger 定義。構(gòu)造函數(shù)需要一個通道名稱。名稱不能作為字符串直接傳遞。相反,它必須作為命名參數(shù)傳遞。這就是為什么該示例使用 keywords::channel = "Main",即使 boost::log::sources::channel_logger 不接受任何其他參數(shù)。
請注意,命名參數(shù) boost::log::keywords::channel 與您使用宏 BOOST_LOG_ATTRIBUTE_KEYWORD 創(chuàng)建的關(guān)鍵字無關(guān)。
boost::log::sources::channel_logger 識別來自程序不同組件的日志條目。組件可以使用它們自己的 boost::log::sources::channel_logger 類型的對象,為它們指定唯一的名稱。如果組件只訪問它們自己的記錄器,那么特定日志條目來自哪個組件就很清楚了。
示例 62.9。集中處理異常
#include <boost/log/common.hpp> #include <boost/log/sinks.hpp> #include <boost/log/sources/logger.hpp> #include <boost/log/utility/exception_handler.hpp> #include <boost/log/exceptions.hpp> #include <boost/utility/empty_deleter.hpp> #include <boost/shared_ptr.hpp> #include <iostream> #include <exception> using namespace boost::log; struct handler { void operator()(const runtime_error &ex) const { std::cerr << "boost::log::runtime_error: " << ex.what() << '\n'; } void operator()(const std::exception &ex) const { std::cerr << "std::exception: " << ex.what() << '\n'; } }; int main() { typedef sinks::synchronous_sink<sinks::text_ostream_backend> text_sink; boost::shared_ptr<text_sink> sink = boost::make_shared<text_sink>(); boost::shared_ptr<std::ostream> stream{&std::clog, boost::empty_deleter{}}; sink->locked_backend()->add_stream(stream); core::get()->add_sink(sink); core::get()->set_exception_handler( make_exception_handler<runtime_error, std::exception>(handler{})); sources::logger lg; BOOST_LOG(lg) << "note"; }
Boost.Log 提供了在日志框架中集中處理異常的選項。這意味著您不需要將每個 BOOST_LOG 包裝在一個 try 塊中來處理 catch 中的異常。
示例 62.9 調(diào)用成員函數(shù) set_exception_handler()。核心提供此成員函數(shù)來注冊處理程序。日志框架中的所有異常都將傳遞給該處理程序。處理程序作為函數(shù)對象實現(xiàn)。它必須為每個預(yù)期的異常類型重載 operator()。該函數(shù)對象的實例通過函數(shù)模板 boost::log::make_exception_handler() 傳遞給 set_exception_handler()。您要處理的所有異常類型都必須作為模板參數(shù)傳遞給 boost::log::make_exception_handler()。
函數(shù) boost::log::make_exception_suppressor() 讓您丟棄日志框架中的所有異常。您調(diào)用此函數(shù)而不是 boost::log::make_exception_handler()。
示例 62.10。定義全局記錄器的宏
#include <boost/log/common.hpp> #include <boost/log/sinks.hpp> #include <boost/log/sources/logger.hpp> #include <boost/utility/empty_deleter.hpp> #include <boost/shared_ptr.hpp> #include <iostream> #include <exception> using namespace boost::log; BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(lg, sources::wlogger_mt) int main() { typedef sinks::synchronous_sink<sinks::text_ostream_backend> text_sink; boost::shared_ptr<text_sink> sink = boost::make_shared<text_sink>(); boost::shared_ptr<std::ostream> stream{&std::clog, boost::empty_deleter{}}; sink->locked_backend()->add_stream(stream); core::get()->add_sink(sink); BOOST_LOG(lg::get()) << L"note"; }
本章中的所有示例都使用本地記錄器。如果要定義全局記錄器,請使用宏 BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT,如示例 62.10 所示。您將記錄器的名稱作為第一個參數(shù)傳遞,將類型作為第二個參數(shù)傳遞。您不通過其名稱訪問記錄器。相反,您調(diào)用 get(),它返回一個指向單例的指針。
Boost.Log 提供了額外的宏,例如 BOOST_LOG_INLINE_GLOBAL_LOGGER_CTOR_ARGS。它們讓您初始化全局記錄器。 BOOST_LOG_INLINE_GLOBAL_LOGGER_CTOR_ARGS 允許您將參數(shù)傳遞給全局記錄器的構(gòu)造函數(shù)。所有這些宏都保證全局記錄器將被正確初始化。
Boost.Log 提供了更多值得一看的功能。例如,您可以通過將鍵/值對作為字符串的容器來配置日志記錄框架。然后,您不需要實例化類和調(diào)用成員函數(shù)。例如,可以將一個關(guān)鍵的 Destination 設(shè)置為 Console,這將自動使日志記錄框架使用后端 boost::log::sinks::text_ostream_backend。后端可以通過額外的鍵/值對進(jìn)行配置。因為容器也可以在 INI 文件中序列化,所以可以將配置存儲在文本文件中并使用該文件初始化日志記錄框架。
到此這篇關(guān)于C++ Boost log日志庫超詳細(xì)講解的文章就介紹到這了,更多相關(guān)C++ Boost log內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++異步操作future和aysnc與function和bind
這篇文章主要介紹了C++異步操作future和aysnc與function和bind,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下2022-09-09C語言函數(shù)聲明以及函數(shù)原型超詳細(xì)講解示例
這篇文章主要介紹了C語言函數(shù)聲明以及函數(shù)原型超詳細(xì)講解,C語言代碼由上到下依次執(zhí)行,原則上函數(shù)定義要出現(xiàn)在函數(shù)調(diào)用之前,否則就會報錯。但在實際開發(fā)中,經(jīng)常會在函數(shù)定義之前使用它們,這個時候就需要提前聲明2023-02-02