本文转自 http://www.cppblog.com/tx7do/articles/11721.html
经过短暂的熟悉过程,log4cplus已经被成功应用到了我的项目中去了,效果还不错,:)除了上文提及的功能之外,下面将介绍log4cplus提供的线程和套接字的使用情况。
### NDC ###
首先我们先了解一下log4cplus中嵌入诊断上下文(Nested Diagnostic Context),即NDC。对log系统而言,当输入源可能不止一个,而只有一个输出时,往往需要分辩所要输出消息的来源,比如服务器处理来自不同客户端的消息时就需要作此判断,NDC可以为交错显示的信息打上一个标记(stamp), 使得辨认工作看起来比较容易些,呵呵。这个标记是线程特有的,利用了线程局部存储机制,称为线程私有数据(Thread-specificData,或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();
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();
NDCContextCreator _first_ndc("ur ndc string"); LOG4CPLUS_DEBUG(logger, "this is a NDC test")
class TestThread : public AbstractThread { public: virtual void run(); }; void TestThread::run() { /* do sth. */ }
void log4cplus::thread::yield() { #if defined(LOG4CPLUS_USE_PTHREADS) ::sched_yield(); #elif defined(LOG4CPLUS_USE_WIN32_THREADS) ::Sleep(0); #endif }
/* 定义一个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: ")
SocketBuffer buffer = convertToBuffer(event, serverName); SocketBuffer msgBuffer(LOG4CPLUS_MAX_MESSAGE_SIZE); msgBuffer.appendSize_t(buffer.getSize()); msgBuffer.appendBuffer(buffer);
/* 定义一个ServerSocket */ServerSocket serverSocket(port); /* 调用accept函数创建一个新的socket与客户端连接 */Socket sock = serverSocket.accept();
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是按照阻塞方式实现的,意味着对其调用直到满足了所接收或发送的个数才返回。