开源日志系统log4cplus(四)

经过短暂的熟悉过程,log4cplus已经被成功应用到了我的项目中去了,效果还不错,:)除了上文提及的
功能之外,下面将介绍log4cplus提供的线程和套接字的使用情况。

### NDC ###
首先我们先了解一下log4cplus中嵌入诊断上下文(Nested Diagnostic Context),即NDC。对log系统而言,
当输入源可能不止一个,而只有一个输出时,往往需要分辩所要输出消息的来源,比如服务器处理来自不同
客户端的消息时就需要作此判断,NDC可以为交错显示的信息打上一个标记(stamp), 使得辨认工作看起来
比较容易些,呵呵。这个标记是线程特有的,利用了线程局部存储机制,称为线程私有数据(Thread-specific
 Data,或TSD)。 看了一下源代码,相关定义如下,包括定义、初始化、获取、设置和清除操作:
linux pthread
 
 
#   define LOG4CPLUS_THREAD_LOCAL_TYPE pthread_key_t *
#   define LOG4CPLUS_THREAD_LOCAL_INIT ::log4cplus::thread::createPthreadKey()
#   define LOG4CPLUS_GET_THREAD_LOCAL_VALUE( key ) pthread_getspecific(
* key)
#   define LOG4CPLUS_SET_THREAD_LOCAL_VALUE( key, value ) pthread_setspecific(
* key, value)
#   define LOG4CPLUS_THREAD_LOCAL_CLEANUP( key ) pthread_key_delete(
* key)


win32
 
 
#   define LOG4CPLUS_THREAD_LOCAL_TYPE DWORD
#   define LOG4CPLUS_THREAD_LOCAL_INIT TlsAlloc()
#   define LOG4CPLUS_GET_THREAD_LOCAL_VALUE( key ) TlsGetValue(key)
#   define LOG4CPLUS_SET_THREAD_LOCAL_VALUE( key, value ) /       TlsSetValue(key, static_cast(value))
#   define LOG4CPLUS_THREAD_LOCAL_CLEANUP( key ) TlsFree(key)

				
使用起来比较简单,在某个线程中:
 
 
    NDC &  ndc  =  log4cplus::getNDC();
    ndc.push(
" ur ndc string " );
    LOG4CPLUS_DEBUG(logger, 
" this is a NDC test " );
      
    ndc.pop();
         
    LOG4CPLUS_DEBUG(logger, 
" There should be no NDC " );
    ndc.remove();



   
当设定输出格式(Layout)为TTCCLayout时,输出如下:
10-21-04 21:32:58, [3392] DEBUG test  - this is a NDC test
10-21-04 21:32:58, [3392] DEBUG test <> - There should be no NDC...
也可以在自定义的输出格式中使用NDC(用%x) ,比如:
 
 
      
  std::
string  pattern  =   " NDC:[%x]  - %m %n " ;
  std::auto_ptr _layout(
new  PatternLayout(pattern));
      
 LOG4CPLUS_DEBUG(_logger, 
" This is the FIRST log message " )
  NDC
&  ndc  =  log4cplus::getNDC();
  ndc.push(
" ur ndc string " ); 
  LOG4CPLUS_WARN(_logger, 
" This is the SECOND log message " )
  ndc.pop();
 ndc.remove(); 
     


   
输出如下:
NDC:[]  - This is the FIRST log message...
NDC:[ur ndc string]  - This is the SECOND log message...
				
另外一种更简单的使用方法是在线程中直接用NDCContextCreator:
 
 
    NDCContextCreator _first_ndc( " ur ndc string " );
    LOG4CPLUS_DEBUG(logger, 
" this is a NDC test " )


   
不必显式地调用push/pop了,而且当出现异常时,能够确保push与pop的调用是匹配的。
    
### 线程 ###
线程是log4cplus中的副产品, 而且仅作了最基本的实现,使用起来也异常简单,只要且必须要
在派生类中重载run函数即可:
 
 
class  TestThread :  public  AbstractThread
{
public :
    
virtual   void  run();
}
;
                
void  TestThread::run()

   
/*  do sth.  */  
     
}


log4cplus的线程没有考虑同步、死锁,有互斥,实现线程切换的小函数挺别致的:
 
 
void  log4cplus::thread::yield()
{
#if  defined(LOG4CPLUS_USE_PTHREADS)
    ::sched_yield();
#elif  defined(LOG4CPLUS_USE_WIN32_THREADS)
    ::Sleep(
0 );
#endif
}

				
### 套接字 ###
套接字也是log4cplus中的副产品,在namespace log4cplus::helpers中,实现了C/S方式的日志记录。
1. 客户端程序需要做的工作:
 
 
/*  定义一个SocketAppender类型的挂接器  */ SharedAppenderPtr _append( new  SocketAppender(host,  8888 " ServerName " ));
/*  把_append加入到logger中  */ Logger::getRoot().addAppender(_append);
/*   SocketAppender类型不需要Layout, 直接调用宏就可以将信息发往loggerServer了  */ LOG4CPLUS_INFO(Logger::getRoot(),  " This is a test:  " )


【注】 这里对宏的调用其实是调用了SocketAppender::append,里面有一个数据传输约定,即先发送
一个后续数据的总长度,然后再发送实际的数据:
 
 
      
    SocketBuffer buffer 
=  convertToBuffer( event , serverName);
    SocketBuffer msgBuffer(LOG4CPLUS_MAX_MESSAGE_SIZE);
    msgBuffer.appendSize_t(buffer.getSize());
    msgBuffer.appendBuffer(buffer);         

				
2. 服务器端程序需要做的工作:
 
 
/*  定义一个ServerSocket  */ ServerSocket serverSocket(port);
 
/*  调用accept函数创建一个新的socket与客户端连接  */ Socket sock  =  serverSocket.accept();

				
此后即可用该sock进行数据read/write了,形如:
 
 
SocketBuffer msgSizeBuffer( sizeof (unsigned  int ));
if ( ! clientsock.read(msgSizeBuffer))
{
    
return ;
}

unsigned 
int  msgSize  =  msgSizeBuffer.readInt();
SocketBuffer buffer(msgSize);
if ( ! clientsock.read(buffer))
{
    
return ;
}


为了将读到的数据正常显示出来,需要将SocketBuffer存放的内容转换成InternalLoggingEvent格式:
 
 
spi::InternalLoggingEvent  event   =  readFromBuffer(buffer);

然后输出:

Logger logger  =  Logger::getInstance( event .getLoggerName());
logger.callAppenders(
event );

				
【注】 read/write是按照阻塞方式实现的,意味着对其调用直到满足了所接收或发送的个数才返回。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值