ACE日志系统(2)

 

ACE 可以将输出重新定向到 stderr (缺省)、系统日志、输出流( Output Stream )、甚至是回调函数,在 C / S 结构中, ACE 也可以实现客户端输出定向到服务器。本节将详细讨论这些内容。


ACE 的重新定向
设置或改变 ACE 日志输出目标( logging sink )可以通过 ACE_Log_Msg 的方法 open 来完成,另外可通过 set_flags clr_flags 来配合实现输出到多个目标。
open
方法的原型:   /**   * Initialize the ACE logging facility. Supplies the program name   * that is available to each logging message call. Default arguments   * set up logging to STDERR only.   *   * @param prog_name      The name of the calling program.   * @param options_flags  A bitwise-or of options flags used to set the   *                       initial behavior and logging sink(s). (see the   *                       enum above for the valid values).   * @param logger_key     The name of ACE_FIFO rendezvous point where the   *                       local client logger daemon is listening for logging   *                       messages. Only meaningful if the LOGGER bit is   *                       set in the @a flags argument.   */   int open ( const ACE_TCHAR * prog_name ,            u_long options_flags = ACE_Log_Msg :: STDERR ,             const ACE_TCHAR * logger_key = 0 );            
第一个参数 prog_name 表示程序名称,可以任意设置,可通过 ACE_Log_Msg program_name 方法获取,另外当第二个参数设置中有 ACE_Log_Msg :: VERBOSE 时,会在输出信息前加上前缀,前缀中就包含该 program_name
第二个参数可以是: STDERR         Write messages to STDERRLOGGER         Write messages to the local client logger daemonOSTREAM       Write messages to the assigned output streamMSG_CALLBACK   Write messages to the callback objectVERBOSE       Prepends program name , timestamp , host name , process ID , and message priority              to each messageVERBOSE_LITE   Prepends timestamp and message priority to each messageSILENT         Do not print messages at allSYSLOG         Write messages to the system 's event logCUSTOM        Write messages to the user-provided back end
第三个参数logger key是针对第二个参数为LOGGER(C/S结构)时需要设置的,表示客户端程序端口值,比如:ACE_DEFAULT_LOGGER_KEY。
一旦调用了该方法,其后的输出将重新定位到第二个参数所指定的sink上。
set_flags、clr_flags的原型:
// Enable the bits in the logger'
s options flags . void set_flags ( unsigned long f );
// Disable the bits in the logger's options flags.void clr_flags (unsigned long f);
参数含义同 open 函数的第二个参数 options_flags ,其中 set_flags 调用可在现有输出目标基础上增加新的输出目标(叠加), clr_flags 则从中删除指定的输出目标。
下面描述一下重定向到不同 sink 的例子。
1 .输出到 stderr
这个简单: ACE_LOG_MSG -> open ( argv [ 0 ], ACE_Log_Msg :: STDERR ); ACE_DEBUG (( LM_DEBUG , ACE_TEXT ( "test/n" )));
或者: ACE_LOG_MSG -> set_flags ( ACE_Log_Msg :: STDERR ); ACE_DEBUG (( LM_DEBUG , ACE_TEXT ( "test/n" )));
2 .输出到 System Logger
ACE_LOG_MSG
-> open ( argv [ 0 ], ACE_Log_Msg :: SYSLOG , ACE_TEXT ( "ACE log" )); ACE_DEBUG (( LM_DEBUG , ACE_TEXT ( "test/n" )));
注意重新定向到 System Logger 不能用 set_flags clr_flags 来实现。 Windows 操作系统下,会输出到系统的 Event Log 中,其中 Event Source 名称为 Open 函数第三个参数。 Unix / Linux 下会输出到 syslog facility 。另外 Windows LM_STARTUP LM_SHUTDOWN LM_TRACE LM_DEBUG LM_INFO 会对应 EVENTLOG_INFORMATION_TYPE LM_NOTICE LM_WARNING 会对应 EVENTLOG_WARNING_TYPE LM_ERROR LM_CRITICAL LM_ALERT LM_EMERGENCY 会对应 EVENTLOG_ERROR_TYPE
3 .输出到 Output Streams
下例将日志输出到文件( ofstream ):
#include < ace/Log_Msg.h >#include < ace/streams.h >
int ACE_TMAIN ( int , ACE_TCHAR * argv []){    ACE_OSTREAM_TYPE * output = new ofstream ( "test.txt" );    ACE_LOG_MSG -> msg_ostream ( output , 1 );    ACE_LOG_MSG -> set_flags ( ACE_Log_Msg :: OSTREAM );    ACE_LOG_MSG -> clr_flags ( ACE_Log_Msg :: STDERR );    ACE_DEBUG (( LM_DEBUG , ACE_TEXT ( "test/n" )));
   
return 0 ;}
上例中首先需要通过 msg_ostream assign 一个 ACE OSTREAM ,然后再指定 log sink ACE_Log_Msg :: OSTREAM ,指定 log sink 既可用 set_flags 也可用 open 方法,注意上例中 set_flags 之后紧接着又用 clr_flags 屏蔽掉先前指定的 ACE_Log_Msg :: STDERR (缺省 sink ),这样就不会同时输出到 stderr 了。
看一下 msg_ostream 的注释(解释的很明白,不赘述):
/**   * delete_stream == 1, forces Log_Msg.h to delete the stream in   * its own ~dtor (assumes control of the stream)   * use only with proper ostream (eg: fstream), not (cout, cerr)   */   void msg_ostream ( ACE_OSTREAM_TYPE *, int delete_ostream );   上例中由于设置了 delete_stream == 1 ,所以不应再显示地调用 delete output ;来删除 ofstream   全局性的 ostream 还包括 cout cerr clog 等,这里再举一个输出到 cout 的例子,其它情况类似:
    ACE_LOG_MSG
-> msg_ostream (& cout );    ACE_LOG_MSG -> open ( argv [ 0 ], ACE_Log_Msg :: OSTREAM );    ACE_DEBUG (( LM_DEBUG , ACE_TEXT ( "test/n" )));
4 .输出到 Callback
ACE 中,将日志输出重新定向到回调函数其实很简单,只需要四步:
1 )定义 ACE_Log_Msg_Callback 的派生类,实现纯虚函数 virtual void log ( ACE_Log_Record & log_record ).
2 )在 ACE_Log_Msg 中注册该派生类(比如 MyCallback ):     Callback * callback = new Callback ;    ACE_LOG_MSG -> set_flags ( ACE_Log_Msg :: MSG_CALLBACK );    ACE_LOG_MSG -> clr_flags ( ACE_Log_Msg :: STDERR );    ACE_LOG_MSG -> msg_callback ( callback );     3 )调用日志输出宏,比如 ACE_DEBUG ,就会将输出重新定向到 MyCallback log 方法中。
4 )退出前的清理工作:    ACE_LOG_MSG -> clr_flags ( ACE_Log_Msg :: MSG_CALLBACK );     delete callback ;
注意到 ACE_Log_Msg_Callback log 方法的参数类型 ACE_Log_Record 可以利用其 print 方法重新定制输出:
   
int print ( const ACE_TCHAR host_name [], u_long verbose_flag , FILE * fp );或者:     int print ( const ACE_TCHAR host_name [], u_long verbose_flag , ACE_OSTREAM_TYPE & stream );     第一个参数表示主机名,第二个参数可选 ACE_Log_Msg :: VERBOSE VERBOSE_LITE 0 (原始信息),第三个参数可以是文件指针或者是标准输出流,比如:
    log_record
. print ( ACE_TEXT ( "" ), ACE_Log_Msg :: VERBOSE , cout );       /* 输出到屏幕 */    log_record . print ( ACE_TEXT ( "" ), 0 , ofstream ( "test.txt" , ios :: app )); /* 输出到文件 */
关于 ACE_Log_Record 进一步使用,请参考以下例子:
/* main.cpp */#include < ace/Task.h >#include < ace/Log_Msg.h >#include " MyCallback.h "
int ACE_TMAIN ( int , ACE_TCHAR *[]){     MyCallback * callback = new MyCallback ;
    ACE_LOG_MSG
-> set_flags ( ACE_Log_Msg :: MSG_CALLBACK );    ACE_LOG_MSG -> clr_flags ( ACE_Log_Msg :: STDERR );    ACE_LOG_MSG -> msg_callback ( callback );
    ACE_DEBUG
(( LM_DEBUG , ACE_TEXT ( "test1/n" )));    ACE_DEBUG (( LM_INFO , ACE_TEXT ( "test2/n" )));
    ACE_LOG_MSG
-> clr_flags ( ACE_Log_Msg :: MSG_CALLBACK );     delete callback ;
   
return 0 ;}
/* MyCallback.h */#include < ace/streams.h >#include < ace/Log_Msg.h >#include < ace/Log_Msg_Callback.h >#include < ace/Log_Record.h >#include < ace/streams.h >#include < ace/Log_Msg_Callback.h >#include < ace/Log_Record.h >#include < ace/SString.h >#include < ace/OS.h >
class MyCallback : public ACE_Log_Msg_Callback { public :     void log ( ACE_Log_Record & log_record )     {        cerr << "Log Message Received:" << endl ;         unsigned long msg_severity = log_record . type ();
       
ACE_Log_Priority prio = ACE_static_cast ( ACE_Log_Priority , msg_severity );         const ACE_TCHAR * prio_name = ACE_Log_Record :: priority_name ( prio );        cerr << "/tType:        "             << ACE_TEXT_ALWAYS_CHAR ( prio_name )             << endl ;
        cerr
<< "/tLength:      " << log_record . length () << endl ;
       
const time_t epoch = log_record . time_stamp (). sec ();        cerr << "/tTime_Stamp:  "             << ACE_TEXT_ALWAYS_CHAR ( ACE_OS :: ctime (& epoch ))             << flush ;
        cerr
<< "/tPid:         " << log_record . pid () << endl ;
       
ACE_CString data ( ">> " );        data += ACE_TEXT_ALWAYS_CHAR ( log_record . msg_data ());
        cerr
<< "/tMsgData:     " << data . c_str () << endl ;     }};
输出: Log Message Received :         Type :        LM_DEBUG         Length :       32         Time_Stamp :   Mon Mar 27 17 : 03 : 06 2005         Pid :         2752         MsgData :     >> test1
Log Message Received :         Type :        LM_INFO         Length :       32         Time_Stamp :   Mon Mar 27 17 : 03 : 06 2005         Pid :         2752         MsgData :     >> test2         需要提醒的是,由于 ACE_Log_Msg 是线程相关的,而且 spawn 出来的线程没有继承性,因此 Callback 仅对单个线程有效,如果想实现多个线程的 callback ,需要分别在各个线程中调用: ACE_LOG_MSG -> msg_callback ( callback );
5 . C / S 结构中输出到服务器
可用于分布式系统的日志处理( distributed logger ), logging server 运行在某台主机,并接收来自其它主机的 logging requests . 在其它主机(也可能在本机)需要运行一个 logging client daemon 进程,相当于一个 proxy ,实现了你自己编写的程序与 logging server 的交互。自己编写的程序格式如下:
#include < ace/Log_Msg.h >
int ACE_TMAIN ( int , ACE_TCHAR * argv []){  ACE_LOG_MSG -> open ( argv [ 0 ],                     ACE_Log_Msg :: LOGGER ,                     ACE_DEFAULT_LOGGER_KEY );
  ACE_DEBUG
(( LM_DEBUG , ACE_TEXT ( "Sent to Logging Server/n" )));
 
return 0 ;}
在运行你自己编写的程序之前需要:
1 )首先运行 logging server :% ACE_ROOT %/ netsvcs / servers / main - f server . conf
2 )然后运行 logging client daemon :% ACE_ROOT %/ netsvcs / servers / main - f client . conf
其中 server . conf 内容如下: dynamic Logger Service_Object * ACE : _make_ACE_Logging_Strategy () "-s log.txt -f STDERR|OSTREAM" dynamic Server_Logging_Service Service_Object * netsvcs : _make_ACE_Server_Logging_Acceptor () active "-p 20009"
该文件每行以 dynamic 开始,第一行定义了 logging strategy ,将会把日志输出到 log . txt (- s 参数),同时输出到 STDERR 。第二行定义了 logging server 侦听( listen )端口为 20009
client
. conf 内容如下: dynamic Client_Logging_Service Service_Object * netsvcs : _make_ACE_Client_Logging_Acceptor () active "-p 20009 -h localhost"
该文件同样以 dynamic 开始,定义了 logging client daemon 的侦听端口为 2009 (与 server . conf 一致),同时- h 指定目标机器名称或 ip (这里是本机)。
运行了 logging server logging client daemon 之后,编译运行上面那个程序, logging server 会显示: Sent to Logging Server
同时在 logging server 所在目录(% ACE_ROOT %/ netsvcs / servers /)下会生成 log . txt ,内容是: starting up Logging Server at port 20009 on handle 1900Sent to Logging Server
注意到之所以如此麻烦地启动两级 logging 管理,主要是考虑到分布式处理过程中可能出现的瓶颈问题。
当然也可以直接通过 ACE_SOCK_Stream 实现与 logging server 的交互,而不用 logging client daemon ,细节以后讨论。而利用 server . conf client . conf 来配置分布式 logging 服务涉及到了 ACE Runtime Configuration ,细节同样在以后会讨论到。对其中参数的解释列举如下:
- f Specify ACE_Log_Msg flags ( OSTREAM , STDERR , LOGGER , VERBOSE , SILENT , VERBOSE_LITE ) used to   control logging .- i The interval , in seconds , at which the log file size is sampled ( default is 0 ; do not sample   by default ).- k Specify the rendezvous point for the client logger (比如 ACE_DEFAULT_LOGGER_KEY )- m The maximum log file size in Kbytes .- n Set the program name for the % n format specifier .- N The maximum number of log files to create .- o Request the standard log file ordering ( keeps multiple log files in numbered order ). Default   is not to order log files .- p Pass in the processwide priorities to either enable ( DEBUG , INFO , WARNING , NOTICE , ERROR ,   CRITICAL , ALERT , EMERGENCY ) or to disable (~ DEBUG , ~ INFO , ~ WARNING , ~ NOTICE , ~ ERROR , ~ CRITICAL ,   ~ ALERT , ~ EMERGENCY ).- s Specify the file name used when OSTREAM is specified as an output target .- t Pass in the per instance priorities to either enable ( DEBUG , INFO , WARNING , NOTICE , ERROR ,   CRITICAL , ALERT , EMERGENCY ) or to disable (~ DEBUG , ~ INFO , ~ WARNING , ~ NOTICE , ~ ERROR , ~ CRITICAL ,   ~ ALERT , ~ EMERGENCY ).- w Cause the log file to be wiped out on both start - up and reconfiguration .
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值