C/C++领域速度最快的程序诊断日志库 Pantheios 介绍

来源:岁月联盟 编辑:exp 时间:2012-08-14

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
 


作者:lzy0168