Pantheios 是目前為止 C/C++ 領域速度最快的程序診斷日志庫,功能強大,性能突出。下面做一下簡單介紹。
Pantheios的本質
1. 是用於程序診斷的日志 api 庫,不是診斷日志庫。
2. 開源,100% 免費。
3. 依賴幾個第三方庫,這幾個庫也是開源和 100% 免費的,包括:
a. xTests 一個 c/c++ 簡單的輕量級的單元/組件測試庫,這個庫只用在 pantheios 的單元測試中
b. b64 一個輕量級的、簡單的和性能卓越的 b64 編碼實現,用在 pantheios::b64 插入器中
c. shwild 是一個與 unix shell 兼容的通配符庫,這個庫也只用在 pantheios 的單元測試中
d. STLSOFT 它不是一個 stl 替換庫,而是一個 stl 擴展庫,它提供了許多系統和編譯器差異兼容屬性,使 pantheios 的實現更簡單。
4. 它的速度非常快,比其它所有重要的日志診斷庫都快。日志庫性能比較測試
5. 100% 類型安全
6. 在鏈接時刻選擇日志輸出工具(比如,後端),原因是:
日志診斷庫必須在代碼的任何位置都可以使用,而不必等待 main 來設置日志輸出。這樣做的結果是,使鏈接設置時有些難度。
7. 擴充性好。
8. 已被一些重要的商業軟件使用。
9. 可移植性好已通過各主流的 c++ 編譯器的測試。
10.Pantheios 由一個非常活躍的團隊開發和維護。
Pantheios的結構
由四個部分組成:
1. 應用層
應用程序使用的 log 表達式,比如 log_DEBUG(), log_INFORMATIONAL() 等等。
2. 核心層
高效地(經常,處理中不用申請任何內存)把各日志元素連在一塊。
3. 前端(Front-end)
提供處理表示和檢測給定級別的日志是否需要輸出。(注:前端庫用戶可以自己實現也可以使用 Pantheios 已經實現的)
4. 後端(Back-end)
輸出 Core 已經准備好的日志到輸出流(比如控制台、COM 錯誤對象、syslog、Windows 事件日志...)。(注:後端庫用戶可以自己實現,或者使用 Pantheios 已經實現的)
Patheios 應用層組成
1. 每套日志函數支持 1 至 32 個參數
2. 共提供 8 套日志函數,包括:
log_DEBUG()、log_INFORMATIONAL()、log_NOTICE()、log_WARNING()、log_ERROR()、log_CRITICAL()、 log_ALERT() 和 log_EMERGENCY()。
這些與 log() 加相應的級別參數的效果相同。
3. 2 個處理數值的插入器:integer 和 real
4. 1 個處理指針的插入器:pointer
5. 1 個處理無類型內存塊的插入器:blob (注:還有一個擴充類,b64,用來表示一個無類型的 Base-64 的內存塊。)
通過這些函數和插入器,可以寫出很簡潔的診斷日志語句,比如:
l 輸出一條異常日志
try
{
// ...
} catch ( std::exception& x){
pantheios::log_ERROR("Exception encountered: ", ex);
}
l 帶參數的日志輸出
void fun(std::string const& sq, char const* s2, struct tm const* t){
pantheios::log(pantheios::debug, "func(", s1, ", ", s2, ", ", t, ")");
}
l 混合類型參數日志輸出
int i;
flost f;
GUID guid;
pantheios::log(pantheios::notice(99)
, "int=", pantheios::integer(i)
, " float=", pantheios::real(f)
, " HWND=", hwnd
, " GUID=", guid);
應用層,只需要頭文件 pantheios/pantheios.hpp,如果使用插入器,還要使用 pantheios/inserters.hpp。
Core 層
core 層被應用層調用,在有些情況下,這些 api 對應用層是有用的。比如,
int pantheios_isSeverityLogged(pan_sev_t severity)
被用來檢測指定的日志是否需要輸出。
另外,通過直接使用 core 的 api,c 代碼也可以直接使用 pantheios,這些函數是:
pantheios_printf()和 pantheios_vprintf()
例子如下:
int i;
float f;
pantheios_printf(PANTHEIOS_SEV_INFORMATIONAL, "int=%d, float=%g", i, f);
值得注意的是,如果直接使用這兩個函數,pantheios 就不能給你提供類型安全的調用了。
Front-end(前端)
前端是一個提供 4 個函數的庫,提供日志表達和檢測時使用的進程標識,運行時,用來檢測是否指定級別的日志需要輸出:
1. PANTHEIOS_CALL(int) pantheios_fe_init(int reserved, void** ptoken);
2. PANTHEIOS_CALL(int) pantheios_fe_uninit(void* token);
3. PANTHEIOS_CALL(char const*) pantheios_fe_processIdentity(void *token);
4. PANTHEIOS_CALL(int) pantheios_fe_isSeverityLogged(void* token, int severity, int backEndId);
pantheios_fe_init()、pantheios_fe_uninit() 和 pantheios_fe_processIdentity() 在庫初始化的時候只需要調用一次。
pantheios_fe_isSeverityLogged() 在輸出日志時都被調用,用來檢查指定級別的日志是否需要輸出給 back_end。
前端的選擇在軟件鏈接時刻進行選擇。
Pantheios 提供了一個前端實現:fe.simple。
fe.simple 的使用只需要兩個簡單的步驟:
1. 鏈接這個庫
比如在 vc9 下,debug 你需要鏈接庫
pantheios.1.fe.simple.vc9.mt.debug.lib
release 你需要鏈接
pantheios.1.fe.simple.vc9.mt.lib
如果你的編譯器支持隱含鏈接(implicit linking,比如 vc),你只需要包括指定的頭文件就可以了:
#include <pantheios/implicit_link/fe.simple.h>
2. 在你的程序中添加下面語句:
PANTHEIOS_EXTERN_C const char PANTHEIOS_FE_PROCESS_IDENTITY[] = "my-process";
這個符號 fe.simple 的函數 pantheios_fe_processIdentity() 裡面需要用到。
用戶自定義前端實現指導
實現一個自定義的前端的工作是相當簡單的。最小的實現要求只是要求你實現的函數 pantheios_fe_processIdentity() 需要返回一個非 0 結尾的字符串,函數 pantheios_fe_isSeverityLogged() 返回一個非 0 值,以及實現函數 pantheios_fe_init() 和 pantheios_fe_uninit(),例子如下:
PANTHEIOS_CALL(int) pantheios_fe_init(void* reserved, void** ptoken)
{
*ptoken = NULL;
return 0;
}
PANTHEIOS_CALL(void) pantheios_fe_uninit(void* token){}
PANTHEIOS_CALL(char const*) pantheios_fe_processIdentity(void* token)
{
return "My Process";
}
PANTHEIOS_CALL(int) pantheios_fe_isSeverityLogged(void* token, int severity, int backEndId)
{
return 1; // Allow all levels
}
Back-end(後端)
後端庫通過提供三個函數來實現後端日志輸出:
1. PANTHEIOS_CALL(int) pantheios_be_init(char const* processIdentity, int reserved, void** ptoken);
2. PANTHEIOS_CALL(void) pantheios_be_uninit(void* token);
3. PANTHEIOS_CALL(int) pantheios_be_logEntry(void* feToken, void* beToken, int severity, char const* entry, size_t cchEntry);
pantheios_be_init() 和 pantheios_be_uninit() 只在庫初始化(反初始化)時調用一次,應用層要求輸出日志並且 pantheios_fe_isSeverityLogged() 返回非 0 時,pantheios_be_logEntry() 被調用一次。
後台庫的選擇在鏈接時刻實現,Pantheios 已經實現了下面幾個後端庫:
l be.ACE - 日志輸出給 ACE 日志框架
l be.COMErrorObject - 日志輸出給 COM 錯誤對象
l be.fprintf - 通過 fprintf() 輸出日志給控制台
l be.null - 什麼也不輸出
l be.syslog - 使用 unix 的 SysLog API 函數,按 Syslog 協議輸出日志
l be.Win32Console - 輸出日志給 windows 的控制台窗口,注意,日志級別不同,顏色也不同
l be.Win32Debugger - 輸出日志給 windows 調試窗口
l be.Win32syslog - 使用 windows 的 SysLog 協議輸出日志
l be.WindowsEventLog - 輸出日志給 Windows Event Log
還有一個神奇的後端庫 be.lrsplit,它采用組合模式,輸出日志到本地後端和遠程後端。
pantheios 提供的後端庫使用指導
太簡單了,處理鏈接時指定需要使用的庫,其它什麼也不用做!比如,vc9 使用 be.fprintf 後端庫,你需要指定鏈接下面這些庫:
debug
pantheios.1.be.fprintf.vc9.mt.debug.lib 和 pantheios.1.bec.fprintf.vc9.mt.debug.lib
release
pantheios.1.be.fprintf.vc9.mt.lib 和 pantheios.1.bec.fprintf.vc9.mt.lib
為什麼要使用兩個庫呢?是因為為支持 be.lrsplit,pantheios 實現的這些後端庫都由四個部分組成,列表如下:
名字
獨立使用接口庫
本地端接口庫
遠端接口庫
公共實現庫
ACE
be.ACE
bel.ACE
ber.ACE
bec.ACE
COM Error Object
be.COMErrorObject
bel.COMErrorObject
ber.COMErrorObject
bec.COMErrorObject
file
be.file
bel.file
ber.file
bec.file
fprintf
be.fprintf
bel.fprintf
ber.fprintf
bec.fprintf
null
be.null
bel.null
ber.null
bec.null
SysLog
be.syslog
bel.syslog
ber.syslog
bec.syslog
Win32 Console
be.Win32Console
bel.Win32Console
ber.Win32Console
bec.Win32Console
Win32 Debugger
be.Win32Debugger
bel.Win32Debugger
ber.Win32Debugger
bec.Win32Debugger
Win32 SysLog
be.Win32sysLog
bel.Win32sysLog
ber.Win32sysLog
bec.Win32sysLog
Windows Event Log
be.WindowsEventLog
bel.WindowsEventLog
ber.WindowsEventLog
bec.WindowsEventLog