﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-牵着老婆满街逛-文章分类-Linux编程</title><link>http://www.cppblog.com/tx7do/category/1516.html</link><description>严以律己,宽以待人. 三思而后行.&lt;/br&gt;
GMail/GTalk: yanglinbo#google.com;&lt;/br&gt;
MSN/Email: tx7do#yahoo.com.cn;&lt;/br&gt;
QQ: 3 0 3 3 9 6 9 2 0 .</description><language>zh-cn</language><lastBuildDate>Thu, 10 Jun 2010 08:32:14 GMT</lastBuildDate><pubDate>Thu, 10 Jun 2010 08:32:14 GMT</pubDate><ttl>60</ttl><item><title>开源日志系统log4cplus(七)</title><link>http://www.cppblog.com/tx7do/articles/11721.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Fri, 25 Aug 2006 20:51:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/articles/11721.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/11721.html</wfw:comment><comments>http://www.cppblog.com/tx7do/articles/11721.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/11721.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/11721.html</trackback:ping><description><![CDATA[<p>&#160;</p>
<p>经过短暂的熟悉过程，log4cplus已经被成功应用到了我的项目中去了，效果还不错，：）除了上文提及的<br>功能之外，下面将介绍log4cplus提供的线程和套接字的使用情况。<br></p>
<pre>### NDC ###</pre>
<pre>首先我们先了解一下log4cplus中嵌入诊断上下文（Nested Diagnostic Context），即NDC。对log系统而言，<br>当输入源可能不止一个，而只有一个输出时，往往需要分辩所要输出消息的来源，比如服务器处理来自不同<br>客户端的消息时就需要作此判断，NDC可以为交错显示的信息打上一个标记(stamp)， 使得辨认工作看起来<br>比较容易些，呵呵。这个标记是线程特有的，利用了线程局部存储机制，称为线程私有数据（Thread-specific<br>&nbsp;Data，或TSD）。 看了一下源代码，相关定义如下，包括定义、初始化、获取、设置和清除操作：</pre>
<pre>linux pthread</pre>
<pre>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">#&nbsp;&nbsp;&nbsp;define&nbsp;LOG4CPLUS_THREAD_LOCAL_TYPE&nbsp;pthread_key_t</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>#&nbsp;&nbsp;&nbsp;define&nbsp;LOG4CPLUS_THREAD_LOCAL_INIT&nbsp;::log4cplus::thread::createPthreadKey()<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>#&nbsp;&nbsp;&nbsp;define&nbsp;LOG4CPLUS_GET_THREAD_LOCAL_VALUE(&nbsp;key&nbsp;)&nbsp;pthread_getspecific(</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">key)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>#&nbsp;&nbsp;&nbsp;define&nbsp;LOG4CPLUS_SET_THREAD_LOCAL_VALUE(&nbsp;key,&nbsp;value&nbsp;)&nbsp;pthread_setspecific(</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">key,&nbsp;value)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>#&nbsp;&nbsp;&nbsp;define&nbsp;LOG4CPLUS_THREAD_LOCAL_CLEANUP(&nbsp;key&nbsp;)&nbsp;pthread_key_delete(</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">key)</span></div>
<br></pre>
<pre>win32</pre>
<pre>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">#&nbsp;&nbsp;&nbsp;define&nbsp;LOG4CPLUS_THREAD_LOCAL_TYPE&nbsp;DWORD<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>#&nbsp;&nbsp;&nbsp;define&nbsp;LOG4CPLUS_THREAD_LOCAL_INIT&nbsp;TlsAlloc()<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>#&nbsp;&nbsp;&nbsp;define&nbsp;LOG4CPLUS_GET_THREAD_LOCAL_VALUE(&nbsp;key&nbsp;)&nbsp;TlsGetValue(key)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>#&nbsp;&nbsp;&nbsp;define&nbsp;LOG4CPLUS_SET_THREAD_LOCAL_VALUE(&nbsp;key,&nbsp;value&nbsp;)&nbsp;\&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TlsSetValue(key,&nbsp;static_cast(value))<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>#&nbsp;&nbsp;&nbsp;define&nbsp;LOG4CPLUS_THREAD_LOCAL_CLEANUP(&nbsp;key&nbsp;)&nbsp;TlsFree(key)</span></div>
</pre>
<pre>				<br>使用起来比较简单，在某个线程中：</pre>
<pre>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;NDC</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;ndc&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;log4cplus::getNDC();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;ndc.push(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">ur&nbsp;ndc&nbsp;string</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;LOG4CPLUS_DEBUG(logger,&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">this&nbsp;is&nbsp;a&nbsp;NDC&nbsp;test</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.cppblog.com/Images/dot.gif">&nbsp;<img src="http://www.cppblog.com/Images/dot.gif"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;ndc.pop();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.cppblog.com/Images/dot.gif">&nbsp;<img src="http://www.cppblog.com/Images/dot.gif"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;LOG4CPLUS_DEBUG(logger,&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">There&nbsp;should&nbsp;be&nbsp;no&nbsp;NDC<img src="http://www.cppblog.com/Images/dot.gif"></span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;ndc.remove();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<br><br>&nbsp;&nbsp;&nbsp; <br>当设定输出格式(Layout)为TTCCLayout时，输出如下：</pre>
<pre>10-21-04 21:32:58, [3392] DEBUG test <ur ndc="" string="" /> - this is a NDC test<br>10-21-04 21:32:58, [3392] DEBUG test &lt;&gt; - There should be no NDC...</pre>
<pre>也可以在自定义的输出格式中使用NDC(用%x) ，比如：</pre>
<pre>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.cppblog.com/Images/dot.gif">&nbsp;<img src="http://www.cppblog.com/Images/dot.gif"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;std::</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&nbsp;pattern&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">NDC:[%x]&nbsp;&nbsp;-&nbsp;%m&nbsp;%n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;std::auto_ptr&nbsp;_layout(</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;PatternLayout(pattern));<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.cppblog.com/Images/dot.gif">&nbsp;<img src="http://www.cppblog.com/Images/dot.gif"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;LOG4CPLUS_DEBUG(_logger,&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">This&nbsp;is&nbsp;the&nbsp;FIRST&nbsp;log&nbsp;message<img src="http://www.cppblog.com/Images/dot.gif"></span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;NDC</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;ndc&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;log4cplus::getNDC();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;ndc.push(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">ur&nbsp;ndc&nbsp;string</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;LOG4CPLUS_WARN(_logger,&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">This&nbsp;is&nbsp;the&nbsp;SECOND&nbsp;log&nbsp;message<img src="http://www.cppblog.com/Images/dot.gif"></span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;ndc.pop();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;ndc.remove();&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;<img src="http://www.cppblog.com/Images/dot.gif">&nbsp;<img src="http://www.cppblog.com/Images/dot.gif"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<br>&nbsp;&nbsp;&nbsp; <br>输出如下：</pre>
<pre>NDC:[]&nbsp; - This is the FIRST log message...<br>NDC:[ur ndc string]&nbsp; - This is the SECOND log message...</pre>
<pre>				<br>另外一种更简单的使用方法是在线程中直接用NDCContextCreator：</pre>
<pre>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;NDCContextCreator&nbsp;_first_ndc(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">ur&nbsp;ndc&nbsp;string</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;LOG4CPLUS_DEBUG(logger,&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">this&nbsp;is&nbsp;a&nbsp;NDC&nbsp;test</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">)</span></div>
<br>&nbsp;&nbsp;&nbsp; <br>不必显式地调用push/pop了，而且当出现异常时，能够确保push与pop的调用是匹配的。</pre>
<pre>&nbsp;&nbsp;&nbsp; <br>### 线程 ###</pre>
<pre>线程是log4cplus中的副产品， 而且仅作了最基本的实现，使用起来也异常简单，只要且必须要<br>在派生类中重载run函数即可：</pre>
<pre>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;TestThread&nbsp;:&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;AbstractThread<br><img id=Codehighlighter1_41_75_Open_Image onclick="this.style.display='none'; Codehighlighter1_41_75_Open_Text.style.display='none'; Codehighlighter1_41_75_Closed_Image.style.display='inline'; Codehighlighter1_41_75_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_41_75_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_41_75_Closed_Text.style.display='none'; Codehighlighter1_41_75_Open_Image.style.display='inline'; Codehighlighter1_41_75_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_41_75_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_41_75_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">virtual</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;run();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;TestThread::run()<br><img id=Codehighlighter1_106_138_Open_Image onclick="this.style.display='none'; Codehighlighter1_106_138_Open_Text.style.display='none'; Codehighlighter1_106_138_Closed_Image.style.display='inline'; Codehighlighter1_106_138_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_106_138_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_106_138_Closed_Text.style.display='none'; Codehighlighter1_106_138_Open_Image.style.display='inline'; Codehighlighter1_106_138_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_106_138_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_106_138_Open_Text><span style="COLOR: #000000">{&nbsp;<br><img id=Codehighlighter1_112_124_Open_Image onclick="this.style.display='none'; Codehighlighter1_112_124_Open_Text.style.display='none'; Codehighlighter1_112_124_Closed_Image.style.display='inline'; Codehighlighter1_112_124_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_112_124_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_112_124_Closed_Text.style.display='none'; Codehighlighter1_112_124_Open_Image.style.display='inline'; Codehighlighter1_112_124_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_112_124_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/**/</span><span id=Codehighlighter1_112_124_Open_Text><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;do&nbsp;sth.&nbsp;</span><span style="COLOR: #008000">*/</span></span><span style="COLOR: #000000">&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;<img src="http://www.cppblog.com/Images/dot.gif">&nbsp;<img src="http://www.cppblog.com/Images/dot.gif"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
</pre>
<pre>log4cplus的线程没有考虑同步、死锁，有互斥，实现线程切换的小函数挺别致的：</pre>
<pre>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;log4cplus::thread::yield()<br><img id=Codehighlighter1_32_157_Open_Image onclick="this.style.display='none'; Codehighlighter1_32_157_Open_Text.style.display='none'; Codehighlighter1_32_157_Closed_Image.style.display='inline'; Codehighlighter1_32_157_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_32_157_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_32_157_Closed_Text.style.display='none'; Codehighlighter1_32_157_Open_Image.style.display='inline'; Codehighlighter1_32_157_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_32_157_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_32_157_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #0000ff">#if</span><span style="COLOR: #000000">&nbsp;defined(LOG4CPLUS_USE_PTHREADS)</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;::sched_yield();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #0000ff">#elif</span><span style="COLOR: #000000">&nbsp;defined(LOG4CPLUS_USE_WIN32_THREADS)</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;::Sleep(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #0000ff">#endif</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span></div>
</pre>
<pre>				<br>### 套接字 ###</pre>
<pre>套接字也是log4cplus中的副产品，在namespace log4cplus::helpers中，实现了C/S方式的日志记录。</pre>
<pre>1. 客户端程序需要做的工作：</pre>
<pre>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img id=Codehighlighter1_0_29_Open_Image onclick="this.style.display='none'; Codehighlighter1_0_29_Open_Text.style.display='none'; Codehighlighter1_0_29_Closed_Image.style.display='inline'; Codehighlighter1_0_29_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_0_29_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_0_29_Closed_Text.style.display='none'; Codehighlighter1_0_29_Open_Image.style.display='inline'; Codehighlighter1_0_29_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top><span id=Codehighlighter1_0_29_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/**/</span><span id=Codehighlighter1_0_29_Open_Text><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;定义一个SocketAppender类型的挂接器&nbsp;</span><span style="COLOR: #008000">*/</span></span><span style="COLOR: #000000">SharedAppenderPtr&nbsp;_append(</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;SocketAppender(host,&nbsp;</span><span style="COLOR: #000000">8888</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">ServerName</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">));<br><img id=Codehighlighter1_103_126_Open_Image onclick="this.style.display='none'; Codehighlighter1_103_126_Open_Text.style.display='none'; Codehighlighter1_103_126_Closed_Image.style.display='inline'; Codehighlighter1_103_126_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_103_126_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_103_126_Closed_Text.style.display='none'; Codehighlighter1_103_126_Open_Image.style.display='inline'; Codehighlighter1_103_126_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_103_126_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/**/</span><span id=Codehighlighter1_103_126_Open_Text><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;把_append加入到logger中&nbsp;</span><span style="COLOR: #008000">*/</span></span><span style="COLOR: #000000">Logger::getRoot().addAppender(_append);<br><img id=Codehighlighter1_167_226_Open_Image onclick="this.style.display='none'; Codehighlighter1_167_226_Open_Text.style.display='none'; Codehighlighter1_167_226_Closed_Image.style.display='inline'; Codehighlighter1_167_226_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_167_226_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_167_226_Closed_Text.style.display='none'; Codehighlighter1_167_226_Open_Image.style.display='inline'; Codehighlighter1_167_226_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_167_226_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/**/</span><span id=Codehighlighter1_167_226_Open_Text><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;&nbsp;SocketAppender类型不需要Layout,&nbsp;直接调用宏就可以将信息发往loggerServer了&nbsp;</span><span style="COLOR: #008000">*/</span></span><span style="COLOR: #000000">LOG4CPLUS_INFO(Logger::getRoot(),&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">This&nbsp;is&nbsp;a&nbsp;test:&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<br>【注】 这里对宏的调用其实是调用了SocketAppender::append，里面有一个数据传输约定，即先发送<br>一个后续数据的总长度，然后再发送实际的数据：</pre>
<pre>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.cppblog.com/Images/dot.gif">&nbsp;<img src="http://www.cppblog.com/Images/dot.gif"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;SocketBuffer&nbsp;buffer&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;convertToBuffer(</span><span style="COLOR: #0000ff">event</span><span style="COLOR: #000000">,&nbsp;serverName);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;SocketBuffer&nbsp;msgBuffer(LOG4CPLUS_MAX_MESSAGE_SIZE);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;msgBuffer.appendSize_t(buffer.getSize());<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;msgBuffer.appendBuffer(buffer);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.cppblog.com/Images/dot.gif">&nbsp;<img src="http://www.cppblog.com/Images/dot.gif"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
</pre>
<pre>				<br>2. 服务器端程序需要做的工作：</pre>
<pre>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img id=Codehighlighter1_0_21_Open_Image onclick="this.style.display='none'; Codehighlighter1_0_21_Open_Text.style.display='none'; Codehighlighter1_0_21_Closed_Image.style.display='inline'; Codehighlighter1_0_21_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_0_21_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_0_21_Closed_Text.style.display='none'; Codehighlighter1_0_21_Open_Image.style.display='inline'; Codehighlighter1_0_21_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top><span id=Codehighlighter1_0_21_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/**/</span><span id=Codehighlighter1_0_21_Open_Text><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;定义一个ServerSocket&nbsp;</span><span style="COLOR: #008000">*/</span></span><span style="COLOR: #000000">ServerSocket&nbsp;serverSocket(port);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;<br><img id=Codehighlighter1_57_90_Open_Image onclick="this.style.display='none'; Codehighlighter1_57_90_Open_Text.style.display='none'; Codehighlighter1_57_90_Closed_Image.style.display='inline'; Codehighlighter1_57_90_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_57_90_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_57_90_Closed_Text.style.display='none'; Codehighlighter1_57_90_Open_Image.style.display='inline'; Codehighlighter1_57_90_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_57_90_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/**/</span><span id=Codehighlighter1_57_90_Open_Text><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;调用accept函数创建一个新的socket与客户端连接&nbsp;</span><span style="COLOR: #008000">*/</span></span><span style="COLOR: #000000">Socket&nbsp;sock&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;serverSocket.accept();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
</pre>
<pre>				<br>此后即可用该sock进行数据read/write了,形如：</pre>
<pre>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">SocketBuffer&nbsp;msgSizeBuffer(</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(unsigned&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">));<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">clientsock.read(msgSizeBuffer))<br><img id=Codehighlighter1_86_100_Open_Image onclick="this.style.display='none'; Codehighlighter1_86_100_Open_Text.style.display='none'; Codehighlighter1_86_100_Closed_Image.style.display='inline'; Codehighlighter1_86_100_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_86_100_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_86_100_Closed_Text.style.display='none'; Codehighlighter1_86_100_Open_Image.style.display='inline'; Codehighlighter1_86_100_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_86_100_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_86_100_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>unsigned&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;msgSize&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;msgSizeBuffer.readInt();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>SocketBuffer&nbsp;buffer(msgSize);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">clientsock.read(buffer))<br><img id=Codehighlighter1_209_223_Open_Image onclick="this.style.display='none'; Codehighlighter1_209_223_Open_Text.style.display='none'; Codehighlighter1_209_223_Closed_Image.style.display='inline'; Codehighlighter1_209_223_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_209_223_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_209_223_Closed_Text.style.display='none'; Codehighlighter1_209_223_Open_Image.style.display='inline'; Codehighlighter1_209_223_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_209_223_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_209_223_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
</pre>
<pre>为了将读到的数据正常显示出来，需要将SocketBuffer存放的内容转换成InternalLoggingEvent格式：</pre>
<pre>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">spi::InternalLoggingEvent&nbsp;</span><span style="COLOR: #0000ff">event</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;readFromBuffer(buffer);</span></div>
</pre>
<pre>然后输出：<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">Logger&nbsp;logger&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;Logger::getInstance(</span><span style="COLOR: #0000ff">event</span><span style="COLOR: #000000">.getLoggerName());<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>logger.callAppenders(</span><span style="COLOR: #0000ff">event</span><span style="COLOR: #000000">);</span></div>
</pre>
<pre>				<br>【注】 read/write是按照阻塞方式实现的，意味着对其调用直到满足了所接收或发送的个数才返回。</pre>
<img src ="http://www.cppblog.com/tx7do/aggbug/11721.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2006-08-26 04:51 <a href="http://www.cppblog.com/tx7do/articles/11721.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>开源日志系统log4cplus(四)</title><link>http://www.cppblog.com/tx7do/articles/11718.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Fri, 25 Aug 2006 20:50:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/articles/11718.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/11718.html</wfw:comment><comments>http://www.cppblog.com/tx7do/articles/11718.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/11718.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/11718.html</trackback:ping><description><![CDATA[
		<p>将log信息记录到文件应该说是日志系统的一个基本功能，log4cplus在此基础上，提供了更多的功能，可以按照你预先设定的大小来决定是否转储，当超过该大小，后续log信息会另存到新文件中，依次类推；或者按照日期来决定是否转储。本文将详细介绍这些用法。</p>
		<br />
		<pre>
				<br />### 如何将log记录到文件 ###</pre>
		<pre>我们在例5中给出了一个将log记录到文件的例子，用的是FileAppender类实现的，log4cplus提供了三个类用于<br />文件操作，它们是FileAppender类、RollingFileAppender类、DailyRollingFileAppender类。</pre>
		<pre>1. FileAppender类</pre>
		<pre>实现了基本的文件操作功能，构造函数如下：</pre>
		<pre>FileAppender(const log4cplus::tstring&amp; filename,<br />                     LOG4CPLUS_OPEN_MODE_TYPE mode = LOG4CPLUS_FSTREAM_NAMESPACE::ios::trunc,<br />                     bool immediateFlush = true);<br />                     <br />filename       : 文件名<br />mode           : 文件类型，可选择的文件类型包括app、ate、binary、in、out、trunc，因为实际上只是对<br />                 stl的一个简单包装，呵呵，这里就不多讲了。缺省是trunc，表示将先前文件删除。<br />immediateFlush ：缓冲刷新标志，如果为true表示每向文件写一条记录就刷新一次缓存，否则直到FileAppender<br />                 被关闭或文件缓存已满才更新文件，一般是要设置true的，比如你往文件写的过程中出现<br />                 了错误（如程序非正常退出），即使文件没有正常关闭也可以保证程序终止时刻之前的所有<br />                 记录都会被正常保存。</pre>
		<pre>FileAppender类的使用情况请参考例5，这里不再赘述。</pre>
		<pre>
				<br />2. RollingFileAppender类</pre>
		<pre>构造函数如下：<br />log4cplus::RollingFileAppender::RollingFileAppender(const log4cplus::tstring&amp; filename,<br />                                                    long maxFileSize,<br />                                                    int maxBackupIndex,<br />                                                    bool immediateFlush)</pre>
		<pre>filename       : 文件名<br />maxFileSize    : 文件的最大尺寸<br />maxBackupIndex : 最大记录文件数<br />immediateFlush : 缓冲刷新标志<br />                                                    <br />RollingFileAppender类可以根据你预先设定的大小来决定是否转储，当超过该大小，后续log信息会另存到新<br />文件中，除了定义每个记录文件的大小之外，你还要确定在RollingFileAppender类对象构造时最多需要多少个<br />这样的记录文件(maxBackupIndex+1)，当存储的文件数目超过maxBackupIndex+1时，会删除最早生成的文件，<br />保证整个文件数目等于maxBackupIndex+1。然后继续记录，比如以下代码片段：</pre>
		<pre>    ... ...<br />    <br />    #define LOOP_COUNT 200000<br />    <br />    SharedAppenderPtr _append(new RollingFileAppender("Test.log", 5*1024, 5));<br />    _append-&gt;setName("file test");<br />    _append-&gt;setLayout( std::auto_ptr<layout />(new TTCCLayout()) );<br />    Logger::getRoot().addAppender(_append);</pre>
		<pre>    Logger root = Logger::getRoot();<br />    Logger test = Logger::getInstance("test");<br />    Logger subTest = Logger::getInstance("test.subtest");</pre>
		<pre>    for(int i=0; i<loop_count; />    {<br />        NDCContextCreator _context("loop");<br />        LOG4CPLUS_DEBUG(subTest, "Entering loop #" &lt;&lt; i)<br />    }<br />    <br />    ... ...<br />    </pre>
		<pre>运行结果：</pre>
		<pre>运行后会产生6个输出文件，Test.log、Test.log.1、Test.log.2、Test.log.3、Test.log.4、Test.log.5<br />其中Test.log存放着最新写入的信息，而最后一个文件中并不包含第一个写入信息，说明已经被不断更新了。<br />需要指出的是，这里除了Test.log之外，每个文件的大小都是200K,而不是我们想像中的5K，这是因为<br />log4cplus中隐含定义了文件的最小尺寸是200K，只有大于200K的设置才生效，&lt;= 200k的设置都会被认为是<br />200K.</pre>
		<pre>
				<br />3. DailyRollingFileAppender类</pre>
		<pre>构造函数如下：<br />DailyRollingFileAppender::DailyRollingFileAppender(const log4cplus::tstring&amp; filename,<br />                                                   DailyRollingFileSchedule schedule,<br />                                                   bool immediateFlush,<br />                                                   int maxBackupIndex)<br />                                                   <br />filename       : 文件名<br />schedule       : 存储频度<br />immediateFlush : 缓冲刷新标志<br />maxBackupIndex : 最大记录文件数</pre>
		<pre>DailyRollingFileAppender类可以根据你预先设定的频度来决定是否转储，当超过该频度，后续log信息会另存<br />到新文件中，这里的频度包括：MONTHLY（每月）、WEEKLY（每周）、DAILY（每日）、TWICE_DAILY（每两天）、<br />HOURLY（每时）、MINUTELY（每分）。maxBackupIndex的含义同上所述，比如以下代码片段：</pre>
		<pre>    ... ...<br />    <br />    SharedAppenderPtr _append(new DailyRollingFileAppender("Test.log", MINUTELY, true, 5));<br />    _append-&gt;setName("file test");<br />    _append-&gt;setLayout( std::auto_ptr<layout />(new TTCCLayout()) );<br />    Logger::getRoot().addAppender(_append);</pre>
		<pre>    Logger root = Logger::getRoot();<br />    Logger test = Logger::getInstance("test");<br />    Logger subTest = Logger::getInstance("test.subtest");</pre>
		<pre>    for(int i=0; i<loop_count; />    {<br />        NDCContextCreator _context("loop");<br />        LOG4CPLUS_DEBUG(subTest, "Entering loop #" &lt;&lt; i)<br />    }<br />    <br />    ... ...</pre>
		<pre>
				<br />运行结果：</pre>
		<pre>运行后会以分钟为单位，分别生成名为Test.log.2004-10-17-03-03、Test.log.2004-10-17-03-04和<br />Test.log.2004-10-17-03-05这样的文件。</pre>
		<pre>需要指出的是，刚看到按照频度（如HOURLY、MINUTELY）转储这样的概念，以为log4cplus提供了内部定时器，<br />感觉很奇怪，因为日志系统不应该主动记录，而loging事件总是应该被动触发的啊。仔细看了源代码后才知道<br />这里的"频度"并不是你写入文件的速度，其实是否转储的标准并不依赖你写入文件的速度，而是依赖于写入<br />的那一时刻是否满足了频度条件，即是否超过了以分钟、小时、周、月为单位的时间刻度，如果超过了就另存。</pre>
		<pre>本部分详细介绍log信息的几种文件操作方式，下面将重点介绍一下如何有选择地控制log信息的输出。</pre>
<img src ="http://www.cppblog.com/tx7do/aggbug/11718.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2006-08-26 04:50 <a href="http://www.cppblog.com/tx7do/articles/11718.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>开源日志系统log4cplus(五)</title><link>http://www.cppblog.com/tx7do/articles/11719.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Fri, 25 Aug 2006 20:50:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/articles/11719.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/11719.html</wfw:comment><comments>http://www.cppblog.com/tx7do/articles/11719.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/11719.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/11719.html</trackback:ping><description><![CDATA[
		<pre>日志系统的另一个基本功能就是能够让使用者按照自己的意愿来控制什么时候，哪些log信息可以输出。<br />如果能够让用户在任意时刻设置允许输出的LogLevel的信息就好了，log4cplus通过LogLevelManager、<br />LogLog、Filter三种方式实现了上述功能。</pre>
		<br />
		<pre>
				<br />### 优先级控制 ###</pre>
		<pre>在研究LogLevelManager之前，首先介绍一下log4cplus中logger的存储机制，在log4cplus中，所有<br />logger都通过一个层次化的结构（其实内部是hash表）来组织的，有一个Root级别的logger,可以通<br />过以下方法获取：</pre>
		<pre>    Logger root = Logger::getRoot();<br />    <br />用户定义的logger都有一个名字与之对应，比如：</pre>
		<pre>    Logger test = Logger::getInstance("test");<br />    <br />可以定义该logger的子logger:</pre>
		<pre>    Logger subTest = Logger::getInstance("test.subtest");<br />    <br />注意Root级别的logger只有通过getRoot方法获取，Logger::getInstance("root")获得的是它的<br />子对象而已。有了这些具有父子关系的logger之后可分别设置其LogLevel,比如：</pre>
		<pre>root.setLogLevel( ... );<br />Test.setLogLevel( ... );<br />subTest.setLogLevel( ... );</pre>
		<pre>
				<br />logger的这种父子关联性会体现在优先级控制方面，log4cplus将输出的log信息按照LogLevel<br />（从低到高）分为：</pre>
		<pre>NOT_SET_LOG_LEVEL (   -1) ：接受缺省的LogLevel，如果有父logger则继承它的LogLevel<br />ALL_LOG_LEVEL     (    0) ：开放所有log信息输出<br />TRACE_LOG_LEVEL   (    0) ：开放trace信息输出(即ALL_LOG_LEVEL)<br />DEBUG_LOG_LEVEL   (10000) ：开放debug信息输出<br />INFO_LOG_LEVEL    (20000) ：开放info信息输出<br />WARN_LOG_LEVEL    (30000) ：开放warning信息输出<br />ERROR_LOG_LEVEL   (40000) ：开放error信息输出<br />FATAL_LOG_LEVEL   (50000) ：开放fatal信息输出<br />OFF_LOG_LEVEL     (60000) ：关闭所有log信息输出</pre>
		<pre>LogLevelManager负责设置logger的优先级，各个logger可以通过setLogLevel设置自己的优先级，<br />当某个logger的LogLevel设置成NOT_SET_LOG_LEVEL时，该logger会继承父logger的优先级，另外，<br />如果定义了重名的多个logger, 对其中任何一个的修改都会同时改变其它logger,我们举例说明：</pre>
		<pre>〖例6〗</pre>
		<pre>#include "log4cplus/logger.h"<br />#include "log4cplus/consoleappender.h"<br />#include "log4cplus/loglevel.h"<br />#include &lt;iostream&gt;<iostream /></pre>
		<pre>using namespace std;<br />using namespace log4cplus;</pre>
		<pre>int main()<br />{<br />    SharedAppenderPtr _append(new ConsoleAppender());<br />    _append-&gt;setName("test");<br />    Logger::getRoot().addAppender(_append);<br />    Logger root = Logger::getRoot();</pre>
		<pre>    Logger test = Logger::getInstance("test");<br />    Logger subTest = Logger::getInstance("test.subtest");<br />    LogLevelManager&amp; llm = getLogLevelManager();</pre>
		<pre>    cout &lt;&lt; endl &lt;&lt; "Before Setting, Default LogLevel" &lt;&lt; endl;<br />    LOG4CPLUS_FATAL(root, "root: " &lt;&lt; llm.toString(root.getChainedLogLevel()))<br />    LOG4CPLUS_FATAL(root, "test: " &lt;&lt; llm.toString(test.getChainedLogLevel()))<br />    LOG4CPLUS_FATAL(root, "test.subtest: " &lt;&lt; llm.toString(subTest.getChainedLogLevel()))</pre>
		<pre>    cout &lt;&lt; endl &lt;&lt; "Setting test.subtest to WARN" &lt;&lt; endl;<br />    subTest.setLogLevel(WARN_LOG_LEVEL);<br />    LOG4CPLUS_FATAL(root, "root: " &lt;&lt; llm.toString(root.getChainedLogLevel()))<br />    LOG4CPLUS_FATAL(root, "test: " &lt;&lt; llm.toString(test.getChainedLogLevel()))<br />    LOG4CPLUS_FATAL(root, "test.subtest: " &lt;&lt; llm.toString(subTest.getChainedLogLevel()))</pre>
		<pre>    cout &lt;&lt; endl &lt;&lt; "Setting test.subtest to TRACE" &lt;&lt; endl;<br />    test.setLogLevel(TRACE_LOG_LEVEL);<br />    LOG4CPLUS_FATAL(root, "root: " &lt;&lt; llm.toString(root.getChainedLogLevel()))<br />    LOG4CPLUS_FATAL(root, "test: " &lt;&lt; llm.toString(test.getChainedLogLevel()))<br />    LOG4CPLUS_FATAL(root, "test.subtest: " &lt;&lt; llm.toString(subTest.getChainedLogLevel()))</pre>
		<pre>    cout &lt;&lt; endl &lt;&lt; "Setting test.subtest to NO_LEVEL" &lt;&lt; endl;<br />    subTest.setLogLevel(NOT_SET_LOG_LEVEL);<br />    LOG4CPLUS_FATAL(root, "root: " &lt;&lt; llm.toString(root.getChainedLogLevel()))<br />    LOG4CPLUS_FATAL(root, "test: " &lt;&lt; llm.toString(test.getChainedLogLevel()))<br />    LOG4CPLUS_FATAL(root, "test.subtest: " &lt;&lt; llm.toString(subTest.getChainedLogLevel()) &lt;&lt; '\n')</pre>
		<pre>    cout &lt;&lt; "create a logger test_bak, named \"test_\", too. " &lt;&lt; endl;<br />    Logger test_bak = Logger::getInstance("test");<br />    cout &lt;&lt; "Setting test to INFO, so test_bak also be set to INFO" &lt;&lt; endl;<br />    test.setLogLevel(INFO_LOG_LEVEL);<br />    LOG4CPLUS_FATAL(root, "test: " &lt;&lt; llm.toString(test.getChainedLogLevel()))<br />    LOG4CPLUS_FATAL(root, "test_bak: " &lt;&lt; llm.toString(test_bak.getChainedLogLevel()))</pre>
		<pre>    return 0;<br />}</pre>
		<pre>输出结果：</pre>
		<pre>Before Setting, Default LogLevel<br />FATAL - root: DEBUG<br />FATAL - test: DEBUG<br />FATAL - test.subtest: DEBUG</pre>
		<pre>Setting test.subtest to WARN<br />FATAL - root: DEBUG<br />FATAL - test: DEBUG<br />FATAL - test.subtest: WARN</pre>
		<pre>Setting test.subtest to TRACE<br />FATAL - root: DEBUG<br />FATAL - test: TRACE<br />FATAL - test.subtest: WARN</pre>
		<pre>Setting test.subtest to NO_LEVEL<br />FATAL - root: DEBUG<br />FATAL - test: TRACE<br />FATAL - test.subtest: TRACE</pre>
		<pre>create a logger test_bak, named "test_", too.<br />Setting test to INFO, so test_bak also be set to INFO<br />FATAL - test: INFO<br />FATAL - test_bak: INFO</pre>
		<pre>
				<br />下面的例子演示了如何通过设置LogLevel来控制用户的log信息输出：</pre>
		<pre>〖例7〗</pre>
		<pre>#include "log4cplus/logger.h"<br />#include "log4cplus/consoleappender.h"<br />#include "log4cplus/loglevel.h"<br />#include &lt;iostream&gt;<iostream /></pre>
		<pre>using namespace std;<br />using namespace log4cplus;</pre>
		<pre>void ShowMsg(void)<br />{<br />    LOG4CPLUS_TRACE(Logger::getRoot(),"info")<br />    LOG4CPLUS_DEBUG(Logger::getRoot(),"info")<br />    LOG4CPLUS_INFO(Logger::getRoot(),"info")<br />    LOG4CPLUS_WARN(Logger::getRoot(),"info")<br />    LOG4CPLUS_ERROR(Logger::getRoot(),"info")<br />    LOG4CPLUS_FATAL(Logger::getRoot(),"info")<br />}</pre>
		<pre>int main()<br />{<br />    SharedAppenderPtr _append(new ConsoleAppender());<br />    _append-&gt;setName("test");<br />    _append-&gt;setLayout(std::auto_ptr<layout />(new TTCCLayout()));<br />    Logger root = Logger::getRoot();<br />    root.addAppender(_append);</pre>
		<pre>    cout &lt;&lt; endl &lt;&lt; "all-log allowed" &lt;&lt; endl;<br />    root.setLogLevel(ALL_LOG_LEVEL);<br />    ShowMsg();</pre>
		<pre>    cout &lt;&lt; endl &lt;&lt; "trace-log and above allowed" &lt;&lt; endl;<br />    root.setLogLevel(TRACE_LOG_LEVEL);<br />    ShowMsg();</pre>
		<pre>    cout &lt;&lt; endl &lt;&lt; "debug-log and above allowed" &lt;&lt; endl;<br />    root.setLogLevel(DEBUG_LOG_LEVEL);<br />    ShowMsg();</pre>
		<pre>    cout &lt;&lt; endl &lt;&lt; "info-log and above allowed" &lt;&lt; endl;<br />    root.setLogLevel(INFO_LOG_LEVEL);<br />    ShowMsg();</pre>
		<pre>    cout &lt;&lt; endl &lt;&lt; "warn-log and above allowed" &lt;&lt; endl;<br />    root.setLogLevel(WARN_LOG_LEVEL);<br />    ShowMsg();</pre>
		<pre>    cout &lt;&lt; endl &lt;&lt; "error-log and above allowed" &lt;&lt; endl;<br />    root.setLogLevel(ERROR_LOG_LEVEL);<br />    ShowMsg();</pre>
		<pre>    cout &lt;&lt; endl &lt;&lt; "fatal-log and above allowed" &lt;&lt; endl;<br />    root.setLogLevel(FATAL_LOG_LEVEL);<br />    ShowMsg();</pre>
		<pre>    cout &lt;&lt; endl &lt;&lt; "log disabled" &lt;&lt; endl;<br />    root.setLogLevel(OFF_LOG_LEVEL);<br />    ShowMsg();</pre>
		<pre>    return 0;<br />}</pre>
		<pre>输出结果：</pre>
		<pre>all-log allowed<br />10-17-04 10:11:40,587 [1075298944] TRACE root &lt;&gt; - info<br />10-17-04 10:11:40,590 [1075298944] DEBUG root &lt;&gt; - info<br />10-17-04 10:11:40,591 [1075298944] INFO root &lt;&gt; - info<br />10-17-04 10:11:40,591 [1075298944] WARN root &lt;&gt; - info<br />10-17-04 10:11:40,592 [1075298944] ERROR root &lt;&gt; - info<br />10-17-04 10:11:40,592 [1075298944] FATAL root &lt;&gt; - info</pre>
		<pre>trace-log and above allowed<br />10-17-04 10:11:40,593 [1075298944] TRACE root &lt;&gt; - info<br />10-17-04 10:11:40,593 [1075298944] DEBUG root &lt;&gt; - info<br />10-17-04 10:11:40,594 [1075298944] INFO root &lt;&gt; - info<br />10-17-04 10:11:40,594 [1075298944] WARN root &lt;&gt; - info<br />10-17-04 10:11:40,594 [1075298944] ERROR root &lt;&gt; - info<br />10-17-04 10:11:40,594 [1075298944] FATAL root &lt;&gt; - info</pre>
		<pre>debug-log and above allowed<br />10-17-04 10:11:40,595 [1075298944] DEBUG root &lt;&gt; - info<br />10-17-04 10:11:40,595 [1075298944] INFO root &lt;&gt; - info<br />10-17-04 10:11:40,596 [1075298944] WARN root &lt;&gt; - info<br />10-17-04 10:11:40,596 [1075298944] ERROR root &lt;&gt; - info<br />10-17-04 10:11:40,596 [1075298944] FATAL root &lt;&gt; - info</pre>
		<pre>info-log and above allowed<br />10-17-04 10:11:40,597 [1075298944] INFO root &lt;&gt; - info<br />10-17-04 10:11:40,597 [1075298944] WARN root &lt;&gt; - info<br />10-17-04 10:11:40,597 [1075298944] ERROR root &lt;&gt; - info<br />10-17-04 10:11:40,598 [1075298944] FATAL root &lt;&gt; - info</pre>
		<pre>warn-log and above allowed<br />10-17-04 10:11:40,598 [1075298944] WARN root &lt;&gt; - info<br />10-17-04 10:11:40,598 [1075298944] ERROR root &lt;&gt; - info<br />10-17-04 10:11:40,599 [1075298944] FATAL root &lt;&gt; - info</pre>
		<pre>error-log and above allowed<br />10-17-04 10:11:40,599 [1075298944] ERROR root &lt;&gt; - info<br />10-17-04 10:11:40,600 [1075298944] FATAL root &lt;&gt; - info</pre>
		<pre>fatal-log and above allowed<br />10-17-04 10:11:40,600 [1075298944] FATAL root &lt;&gt; - info</pre>
		<pre>log disabled</pre>
		<pre> </pre>
		<pre>用户也可以自行定义LogLevel，操作比较简单，首先要定义LEVEL值，比如HELLO_LOG_LEVEL定义如下：</pre>
		<pre>/* DEBUG_LOG_LEVEL  &lt; HELLO_LOG_LEVEL &lt; INFO_LOG_LEVEL */<br />const LogLevel HELLO_LOG_LEVEL = 15000;</pre>
		<pre>然后定义以下宏即可：</pre>
		<pre>/* define MACRO LOG4CPLUS_HELLO */<br />#define LOG4CPLUS_HELLO(logger, logEvent) \<br />    if(logger.isEnabledFor(HELLO_LOG_LEVEL)) { \<br />        log4cplus::tostringstream _log4cplus_buf; \<br />        _log4cplus_buf &lt;&lt; logEvent; \<br /> logger.forcedLog(HELLO_LOG_LEVEL, _log4cplus_buf.str(), __FILE__, __LINE__); \<br />    }</pre>
		<pre>不过log4cplus没有提供给用户一个接口来实现LEVEL值与字符串的转换，所以当带格式输出LogLevel字符<br />串时候会显示"UNKNOWN"， 不够理想。比如用TTCCLayout控制输出的结果可能会如下所示：</pre>
		<pre>10-17-04 11:17:51,124 [1075298944] UNKNOWN root &lt;&gt; - info</pre>
		<pre>而不是期望的以下结果：<br />10-17-04 11:17:51,124 [1075298944] HELLO root &lt;&gt; - info</pre>
		<pre>要想实现第二种结果，按照log4cplus现有的接口机制，只能改其源代码后重新编译，方法是在loglevel.cxx<br />中加入：</pre>
		<pre>#define _HELLO_STRING LOG4CPLUS_TEXT("HELLO")</pre>
		<pre>然后修改log4cplus::tstring  defaultLogLevelToStringMethod(LogLevel ll)函数，增加一个判断：</pre>
		<pre>case HELLO_LOG_LEVEL:    return _HELLO_STRING;</pre>
		<pre>重新编译log4cplus源代码后生成库文件，再使用时即可实现满意效果。</pre>
		<pre>
				<br />### 调试模式 ###</pre>
		<pre>即通过loglog来控制输出调试、警告或错误信息，见例4，这里不再赘述。</pre>
		<pre> </pre>
		<pre>### 基于脚本配置来过滤log信息 ###</pre>
		<pre>除了通过程序实现对log环境的配置之外，log4cplus通过PropertyConfigurator类实现了基于脚本配置的功能。<br />通过脚本可以完成对logger、appender和layout的配置，因此可以解决怎样输出，输出到哪里的问题，我将在<br />全文的最后一部分中提到多线程环境中如何利用脚本配置来配合实现性能测试，本节将重点介绍基脚本实现过<br />滤log信息的功能。</pre>
		<pre>首先简单介绍一下脚本的语法规则：</pre>
		<pre>包括Appender的配置语法和logger的配置语法，其中：</pre>
		<pre>1.Appender的配置语法:</pre>
		<pre>（1）设置名称：</pre>
		<pre>/*设置方法*/<br />log4cplus.appender.appenderName=fully.qualified.name.of.appender.class</pre>
		<pre>例如（列举了所有可能的Appender，其中SocketAppender后面会讲到）：<br />log4cplus.appender.append_1=log4cplus::ConsoleAppender<br />log4cplus.appender.append_2=log4cplus::FileAppender<br />log4cplus.appender.append_3=log4cplus::RollingFileAppender<br />log4cplus.appender.append_4=log4cplus::DailyRollingFileAppender<br />log4cplus.appender.append_4=log4cplus::SocketAppender</pre>
		<pre>（2）设置Filter：</pre>
		<pre>包括选择过滤器和设置过滤条件，可选择的过滤器包括：LogLevelMatchFilter、LogLevelRangeFilter、<br />和StringMatchFilter：</pre>
		<pre>对LogLevelMatchFilter来说，过滤条件包括LogLevelToMatch和AcceptOnMatch（true|false）， 只有<br />当log信息的LogLevel值与LogLevelToMatch相同，且AcceptOnMatch为true时才会匹配。</pre>
		<pre>LogLevelRangeFilter来说，过滤条件包括LogLevelMin、LogLevelMax和AcceptOnMatch，只有当log信息<br />的LogLevel在LogLevelMin、LogLevelMax之间同时AcceptOnMatch为true时才会匹配。</pre>
		<pre>对StringMatchFilter来说，过滤条件包括StringToMatch和AcceptOnMatch，只有当log信息的LogLevel值<br />与StringToMatch对应的LogLevel值与相同， 且AcceptOnMatch为true时会匹配。</pre>
		<pre>
				<br />过滤条件处理机制类似于IPTABLE的Responsibility chain，（即先deny、再allow）不过执行顺序刚好相反，<br />后写的条件会被先执行，比如：</pre>
		<pre>log4cplus.appender.append_1.filters.1=log4cplus::spi::LogLevelMatchFilter<br />log4cplus.appender.append_1.filters.1.LogLevelToMatch=TRACE<br />log4cplus.appender.append_1.filters.1.AcceptOnMatch=true<br />#log4cplus.appender.append_1.filters.2=log4cplus::spi::DenyAllFilter</pre>
		<pre>会首先执行filters.2的过滤条件，关闭所有过滤器，然后执行filters.1，仅匹配TRACE信息。</pre>
		<pre>（3）设置Layout</pre>
		<pre>可以选择不设置、TTCCLayout、或PatternLayout</pre>
		<pre>如果不设置，会输出简单格式的log信息。</pre>
		<pre>设置TTCCLayout如下所示：<br />log4cplus.appender.ALL_MSGS.layout=log4cplus::TTCCLayout</pre>
		<pre>设置PatternLayout如下所示：<br />log4cplus.appender.append_1.layout=log4cplus::PatternLayout<br />log4cplus.appender.append_1.layout.ConversionPattern=%d{%m/%d/%y %H:%M:%S,%Q} [%t] %-5p - %m%n</pre>
		<pre>
				<br />2.logger的配置语法</pre>
		<pre>包括rootLogger和non-root logger。</pre>
		<pre>对于rootLogger来说：<br />log4cplus.rootLogger=[LogLevel], appenderName, appenderName, ...</pre>
		<pre>对于non-root logger来说：<br />log4cplus.logger.logger_name=[LogLevel|INHERITED], appenderName, appenderName, ...</pre>
		<pre>
				<br />脚本方式使用起来非常简单，只要首先加载配置即可（urconfig.properties是自行定义的配置文件）：</pre>
		<pre>PropertyConfigurator::doConfigure("urconfig.properties");</pre>
		<pre>
				<br />下面我们通过例子体会一下log4cplus强大的基于脚本过滤log信息的功能。</pre>
		<pre>
				<br />〖例8〗</pre>
		<pre>/*<br /> *    urconfig.properties<br /> */<br />log4cplus.rootLogger=TRACE, ALL_MSGS, TRACE_MSGS, DEBUG_INFO_MSGS, FATAL_MSGS</pre>
		<pre>log4cplus.appender.ALL_MSGS=log4cplus::RollingFileAppender<br />log4cplus.appender.ALL_MSGS.File=all_msgs.log<br />log4cplus.appender.ALL_MSGS.layout=log4cplus::TTCCLayout</pre>
		<pre>log4cplus.appender.TRACE_MSGS=log4cplus::RollingFileAppender<br />log4cplus.appender.TRACE_MSGS.File=trace_msgs.log<br />log4cplus.appender.TRACE_MSGS.layout=log4cplus::TTCCLayout<br />log4cplus.appender.TRACE_MSGS.filters.1=log4cplus::spi::LogLevelMatchFilter<br />log4cplus.appender.TRACE_MSGS.filters.1.LogLevelToMatch=TRACE<br />log4cplus.appender.TRACE_MSGS.filters.1.AcceptOnMatch=true<br />log4cplus.appender.TRACE_MSGS.filters.2=log4cplus::spi::DenyAllFilter</pre>
		<pre>log4cplus.appender.DEBUG_INFO_MSGS=log4cplus::RollingFileAppender<br />log4cplus.appender.DEBUG_INFO_MSGS.File=debug_info_msgs.log<br />log4cplus.appender.DEBUG_INFO_MSGS.layout=log4cplus::TTCCLayout<br />log4cplus.appender.DEBUG_INFO_MSGS.filters.1=log4cplus::spi::LogLevelRangeFilter<br />log4cplus.appender.DEBUG_INFO_MSGS.filters.1.LogLevelMin=DEBUG<br />log4cplus.appender.DEBUG_INFO_MSGS.filters.1.LogLevelMax=INFO<br />log4cplus.appender.DEBUG_INFO_MSGS.filters.1.AcceptOnMatch=true<br />log4cplus.appender.DEBUG_INFO_MSGS.filters.2=log4cplus::spi::DenyAllFilter</pre>
		<pre>log4cplus.appender.FATAL_MSGS=log4cplus::RollingFileAppender<br />log4cplus.appender.FATAL_MSGS.File=fatal_msgs.log<br />log4cplus.appender.FATAL_MSGS.layout=log4cplus::TTCCLayout<br />log4cplus.appender.FATAL_MSGS.filters.1=log4cplus::spi::StringMatchFilter<br />log4cplus.appender.FATAL_MSGS.filters.1.StringToMatch=FATAL<br />log4cplus.appender.FATAL_MSGS.filters.1.AcceptOnMatch=true<br />log4cplus.appender.FATAL_MSGS.filters.2=log4cplus::spi::DenyAllFilter</pre>
		<pre>
				<br />/*<br /> *    main.cpp<br /> */<br />#include &lt;log4cplus/logger.h&gt;<br />#include &lt;log4cplus/configurator.h&gt;<br />#include &lt;log4cplus/helpers/stringhelper.h&gt;<log4cplus /></pre>
		<pre>using namespace log4cplus;</pre>
		<pre>static Logger logger = Logger::getInstance("log");</pre>
		<pre>void printDebug()<br />{<br />    LOG4CPLUS_TRACE_METHOD(logger, "::printDebug()");<br />    LOG4CPLUS_DEBUG(logger, "This is a DEBUG message");<br />    LOG4CPLUS_INFO(logger, "This is a INFO message");<br />    LOG4CPLUS_WARN(logger, "This is a WARN message");<br />    LOG4CPLUS_ERROR(logger, "This is a ERROR message");<br />    LOG4CPLUS_FATAL(logger, "This is a FATAL message");<br />}<br />int main()<br />{<br />    Logger root = Logger::getRoot();<br />    PropertyConfigurator::doConfigure("urconfig.properties");<br />    printDebug();</pre>
		<pre>    return 0;<br />}</pre>
		<pre>运行结果：</pre>
		<pre>1. all_msgs.log<br />10-17-04 14:55:25,858 [1075298944] TRACE log &lt;&gt; - ENTER: ::printDebug()<br />10-17-04 14:55:25,871 [1075298944] DEBUG log &lt;&gt; - This is a DEBUG message<br />10-17-04 14:55:25,873 [1075298944] INFO log &lt;&gt; - This is a INFO message<br />10-17-04 14:55:25,873 [1075298944] WARN log &lt;&gt; - This is a WARN message<br />10-17-04 14:55:25,874 [1075298944] ERROR log &lt;&gt; - This is a ERROR message<br />10-17-04 14:55:25,874 [1075298944] FATAL log &lt;&gt; - This is a FATAL message<br />10-17-04 14:55:25,875 [1075298944] TRACE log &lt;&gt; - EXIT:  ::printDebug()</pre>
		<pre>2. trace_msgs.log<br />10-17-04 14:55:25,858 [1075298944] TRACE log &lt;&gt; - ENTER: ::printDebug()<br />10-17-04 14:55:25,875 [1075298944] TRACE log &lt;&gt; - EXIT:  ::printDebug()</pre>
		<pre>3. debug_info_msgs.log<br />10-17-04 14:55:25,871 [1075298944] DEBUG log &lt;&gt; - This is a DEBUG message<br />10-17-04 14:55:25,873 [1075298944] INFO log &lt;&gt; - This is a INFO message</pre>
		<pre>4. fatal_msgs.log<br />10-17-04 14:55:25,874 [1075298944] FATAL log &lt;&gt; - This is a FATAL message</pre>
		<pre> </pre>
		<pre>本部分详细介绍了如何有选择地控制log信息的输出，最后一部分我们将介绍一下多线程、<br />和C/S模式下该如何操作，顺便提一下NDC的概念。</pre>
<img src ="http://www.cppblog.com/tx7do/aggbug/11719.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2006-08-26 04:50 <a href="http://www.cppblog.com/tx7do/articles/11719.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>开源日志系统log4cplus(六)</title><link>http://www.cppblog.com/tx7do/articles/11720.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Fri, 25 Aug 2006 20:50:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/articles/11720.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/11720.html</wfw:comment><comments>http://www.cppblog.com/tx7do/articles/11720.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/11720.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/11720.html</trackback:ping><description><![CDATA[
		<p>log4cplus在很多方面做的都很出色，但是使用过程有些地方感觉不爽。在继续吹捧之前我先把不爽之处<br />稍微提一提，然后继续介绍关于线程和套接字的知识。<br /></p>
		<pre>### 一些可以改进之处 ###</pre>
		<pre>1. 用户自定义LogLevel的实现机制不够开放</pre>
		<pre>在第五篇中曾经介绍过如何实现用户自行定义LogLevel，为了实现比较理想的效果，甚至还需要改log4cplus<br />的源代码。：（</pre>
		<pre>2. 生成Logger对象的机制可以改进</pre>
		<pre>我在使用时候，经常需要在不同的文件、函数中操作同一个logger，虽然log4cplus实现了树状存储以及根据<br />名称生成Logger，却没有充分利用这样的特点确保同一个名称对应的logger对象的唯一性，比如以下代码：</pre>
		<pre>    ... ...<br />    <br />    Logger logger1 = Logger::getInstance("test");<br />    Logger logger2 = Logger::getInstance("test");</pre>
		<pre>    Logger * plogger1 = &amp;logger1;<br />    Logger * plogger2 = &amp;logger2;</pre>
		<pre>    std::cout &lt;&lt; "plogger1: " &lt;&lt; plogger1 &lt;&lt; std::endl &lt;&lt; "plogger2: " &lt;&lt; plogger2 &lt;&lt; std::endl;<br />    <br />    ... ...<br />    <br />    <br />运行结果：</pre>
		<pre>plogger1: 0xbfffe5a0<br />plogger2: 0xbfffe580</pre>
		<pre>
				<br />从结果可以看出，明明是同一个Logger，但每次调用都会产生一个Logger副本，虽然结果是正确的（因为将存<br />储和操作分开了），但是资源有些浪费，我看了一下log4cplus的代码，其实可以按照如下方式实现（示意性<br />的）：</pre>
		<pre>#include &lt;iostream&gt;<br />#include &lt;string&gt;<br />#include &lt;map&gt;<map></map></pre>
		<pre>/* forward declaration */<br />class Logger;</pre>
		<pre>class LoggerContainer<br />{<br />public:</pre>
		<pre>    ~LoggerContainer();</pre>
		<pre>    Logger * getinstance(const std::string &amp; strLogger);</pre>
		<pre>private:</pre>
		<pre>    typedef std::map&lt;:string,&gt; LoggerMap;<br />    LoggerMap loggerPtrs;<br />};</pre>
		<pre>class Logger<br />{<br />public:<br />     Logger() {std::cout &lt;&lt; "ctor of Logger " &lt;&lt; std::endl; }<br />    ~Logger() {std::cout &lt;&lt; "dtor of Logger " &lt;&lt; std::endl; }</pre>
		<pre>    static Logger * getInstance( const std::string &amp; strLogger)<br />    {<br />        static LoggerContainer defaultLoggerContainer;<br />        return defaultLoggerContainer.getinstance(strLogger);<br />    }<br />};</pre>
		<pre>LoggerContainer::~LoggerContainer()<br />{<br />    /* release all ptr in LoggerMap */<br />    LoggerMap::iterator itr = loggerPtrs.begin();</pre>
		<pre>    for( ; itr != loggerPtrs.end(); ++itr )<br /> {<br />     delete (*itr).second;<br /> }</pre>
		<pre>}</pre>
		<pre>Logger * LoggerContainer::getinstance(const std::string &amp; strLogger)<br />{<br />   LoggerMap::iterator itr = loggerPtrs.find(strLogger);</pre>
		<pre>   if(itr != loggerPtrs.end())<br />   {<br />       /* logger exist, just return it */<br />       return (*itr).second;<br />   }<br />   else<br />   {<br />       /* return a new logger */<br />       Logger * plogger = new Logger();<br />       loggerPtrs.insert(std::make_pair(strLogger, plogger));</pre>
		<pre>       return plogger;<br />   }<br />}</pre>
		<pre>int main()<br />{<br />    Logger * plogger1 = Logger::getInstance("test");<br />    Logger * plogger2 = Logger::getInstance("test");</pre>
		<pre>    std::cout &lt;&lt; "plogger1: " &lt;&lt; plogger1 &lt;&lt; std::endl &lt;&lt; "plogger2: " &lt;&lt; plogger2 &lt;&lt; std::endl;</pre>
		<pre>    return 0;<br />}</pre>
		<pre>
				<br />运行结果：</pre>
		<pre>ctor of Logger<br />plogger1: 0x804fc30<br />plogger2: 0x804fc30<br />dtor of Logger</pre>
		<pre>这里的LoggerContainer相当于log4cplus中的Hierarchy类，结果可以看出，通过同一个名称可以获取相同的<br />Logger实例。</pre>
		<pre>
				<br />还有一些小毛病比如RollingFileAppender和DailyRollingFileAppender的参数输入顺序可以调整成统一方式<br />等等，就不细说了。</pre>
		<pre>本部分提到了使用log4cplus时候感觉不爽的地方，最后一部分将介绍一下log4cplus中线程和套接字实现情况<br /></pre>
<img src ="http://www.cppblog.com/tx7do/aggbug/11720.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2006-08-26 04:50 <a href="http://www.cppblog.com/tx7do/articles/11720.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>开源日志系统log4cplus(二)</title><link>http://www.cppblog.com/tx7do/articles/11716.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Fri, 25 Aug 2006 20:49:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/articles/11716.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/11716.html</wfw:comment><comments>http://www.cppblog.com/tx7do/articles/11716.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/11716.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/11716.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 本文介绍了使用log4cplus有六个步骤，并提供了一些例子引导你了解log4cplus的基本使用。				### 基本使用 ###使用log4cplus有六个基本步骤：1. 实例化一个appender对象2. 实例化一个layout对象3. 将layout对象绑定(attach)到appender对象4. 实例化一个logger对象,调用静态函数：log4cplus::Logge...&nbsp;&nbsp;<a href='http://www.cppblog.com/tx7do/articles/11716.html'>阅读全文</a><img src ="http://www.cppblog.com/tx7do/aggbug/11716.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2006-08-26 04:49 <a href="http://www.cppblog.com/tx7do/articles/11716.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>开源日志系统log4cplus(三)</title><link>http://www.cppblog.com/tx7do/articles/11717.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Fri, 25 Aug 2006 20:49:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/articles/11717.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/11717.html</wfw:comment><comments>http://www.cppblog.com/tx7do/articles/11717.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/11717.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/11717.html</trackback:ping><description><![CDATA[
		<p>本文介绍了三种控制输出格式的布局管理器的概念和使用情况，通过掌握这些知识，可以更有效地控制log系统输出尽可能贴近你需求的信息来。<br /></p>
		<pre>
				<br />### 如何控制输出消息的格式 ###</pre>
		<pre>前面已经讲过，log4cplus通过布局器（Layouts）来控制输出的格式，log4cplus提供了三种类型的Layouts，<br />分别是SimpleLayout、PatternLayout、和TTCCLayout。其中：</pre>
		<pre>1. SimpleLayout<br />是一种简单格式的布局器，在输出的原始信息之前加上LogLevel和一个"-"。</pre>
		<pre>比如以下代码片段：</pre>
		<pre>    ... ...</pre>
		<pre>    /* step 1: Instantiate an appender object */<br />    SharedObjectPtr _append (new ConsoleAppender());<br />    _append-&gt;setName("append for test");</pre>
		<pre>    /* step 2: Instantiate a layout object */<br />    std::auto_ptr  _layout(new log4cplus::SimpleLayout());</pre>
		<pre>    /* step 3: Attach the layout object to the appender */<br />    _append-&gt;setLayout( _layout );</pre>
		<pre>    /* step 4: Instantiate a logger object */<br />    Logger _logger = Logger::getInstance("test");</pre>
		<pre>    /* step 5: Attach the appender object to the logger  */<br />    _logger.addAppender(_append);</pre>
		<pre>     /* log activity */<br />    LOG4CPLUS_DEBUG(_logger, "This is the simple formatted log message...")<br />    <br />    ... ...<br />    <br />    <br />将打印结果：<br />DEBUG - This is the simple formatted log message...</pre>
		<pre>2. PatternLayout<br />是一种有词法分析功能的模式布局器，一提起模式就会想起正则表达式，这里的模式和正则表达式类似，但是<br />远比后者简单，能够对预定义的标识符（称为conversion specifiers）进行解析，转换成特定格式输出。以下<br />代码片段演示了如何使用PatternLayout：</pre>
		<pre>    ... ...</pre>
		<pre>    /* step 1: Instantiate an appender object */<br />    SharedObjectPtr _append (new ConsoleAppender());<br />    _append-&gt;setName("append for test");<br />   <br />    /* step 2: Instantiate a layout object */<br />    std::string pattern = "%d{%m/%d/%y %H:%M:%S}  - %m [%l]%n";<br />    std::auto_ptr _layout(new PatternLayout(pattern));<br />    <br />    /* step 3: Attach the layout object to the appender */<br />    _append-&gt;setLayout( _layout );</pre>
		<pre>    /* step 4: Instantiate a logger object */<br />    Logger _logger = Logger::getInstance("test_logger.subtest");</pre>
		<pre>    /* step 5: Attach the appender object to the logger  */<br />    _logger.addAppender(_append);</pre>
		<pre>     /* log activity */<br />    LOG4CPLUS_DEBUG(_logger, "teststr")<br />    <br />    ... ...<br />    <br />输出结果：<br />10/16/04 18:51:25  - teststr [main.cpp:51]</pre>
		<pre>可以看出通过填写特定格式的模式字符串"pattern"，原始信息被包含到一堆有格式的信息当中了，这就使得<br />用户可以根据自身需要来定制显示内容。"pattern"可以包含普通字符串和预定义的标识符，其中：</pre>
		<pre>（1）普通字符串，能够被直接显示的信息。<br />（2）预定义标识符，通过"%"与一个或多个字符共同构成预定义的标识符，能够产生出特定格式信息。</pre>
		<pre>关于预定义标识符，log4cplus文档中提供了详细的格式说明，我每种都试了一下，以上述代码为例，根据不同<br />的pattern，各种消息格式使用情况列举如下：</pre>
		<pre>（1）"%%"，转义为%, 即，std::string pattern = "%%" 时输出: "%"<br />（2）"%c"，输出logger名称，比如std::string pattern ="%c" 时输出: "test_logger.subtest"，<br />     也可以控制logger名称的显示层次，比如"%c{1}"时输出"test_logger"，其中数字表示层次。<br />（3）"%D"，显示本地时间，当std::string pattern ="%D" 时输出:"2004-10-16 18:55:45"，%d显示标准时间，<br />     所以当std::string pattern ="%d" 时输出 "2004-10-16 10:55:45" （因为我们是东8区，差8个小时啊）。<br />     可以通过%d{...}定义更详细的显示格式，比如%d{%H:%M:%s}表示要显示小时:分钟：秒。大括号中可显示的<br />     预定义标识符如下：<br />     <br />%a -- 表示礼拜几，英文缩写形式，比如"Fri"<br />%A -- 表示礼拜几，比如"Friday"<br />%b -- 表示几月份，英文缩写形式，比如"Oct"<br />%B -- 表示几月份，"October"<br />%c -- 标准的日期＋时间格式，如 "Sat Oct 16 18:56:19 2004"<br />%d -- 表示今天是这个月的几号(1-31)"16"<br />%H -- 表示当前时刻是几时(0-23)，如 "18"<br />%I -- 表示当前时刻是几时(1-12)，如 "6"<br />%j -- 表示今天是哪一天(1-366)，如 "290"<br />%m -- 表示本月是哪一月(1-12)，如 "10"<br />%M -- 表示当前时刻是哪一分钟(0-59)，如 "59"<br />%p -- 表示现在是上午还是下午， AM or PM<br />%q -- 表示当前时刻中毫秒部分(0-999)，如 "237"<br />%Q -- 表示当前时刻中带小数的毫秒部分(0-999.999)，如 "430.732"<br />%S -- 表示当前时刻的多少秒(0-59)，如 "32"<br />%U -- 表示本周是今年的第几个礼拜，以周日为第一天开始计算(0-53)，如 "41"<br />%w -- 表示礼拜几，(0-6, 礼拜天为0)，如 "6"<br />%W -- 表示本周是今年的第几个礼拜，以周一为第一天开始计算(0-53)，如 "41"<br />%x -- 标准的日期格式，如 "10/16/04"<br />%X -- 标准的时间格式，如 "19:02:34"<br />%y -- 两位数的年份(0-99)，如 "04"<br />%Y -- 四位数的年份，如 "2004"<br />%Z -- 时区名，比如 "GMT"</pre>
		<pre>（4）"%F"，输出当前记录器所在的文件名称，比如std::string pattern ="%F" 时输出: "main.cpp"<br />（5）"%L"，输出当前记录器所在的文件行号，比如std::string pattern ="%L" 时输出: "51"<br />（6）"%l"，输出当前记录器所在的文件名称和行号，比如std::string pattern ="%L" 时输出:<br />     "main.cpp:51"<br />（7）"%m"，输出原始信息，比如std::string pattern ="%m" 时输出: "teststr"，即上述代码中<br />     LOG4CPLUS_DEBUG的第二个参数，这种实现机制可以确保原始信息被嵌入到带格式的信息中。<br />（8）"%n"，换行符，没什么好解释的<br />（9）"%p"，输出LogLevel，比如std::string pattern ="%p" 时输出: "DEBUG"<br />（10）"%t"，输出记录器所在的线程ID，比如std::string pattern ="%t" 时输出: "1075298944"<br />（11）"%x"，嵌套诊断上下文NDC (nested diagnostic context) 输出，从堆栈中弹出上下文信息，NDC可以用对<br />      不同源的log信息（同时地）交叉输出进行区分，关于NDC方面的详细介绍会在下文中提到。<br />（12）格式对齐，比如std::string pattern ="%-10m"时表示左对齐，宽度是10，此时会输出"teststr   "，当<br />      然其它的控制字符也可以相同的方式来使用，比如"%-12d"，"%-5p"等等（刚接触log4cplus文档时还以为<br />      "%-5p"整个字符串代表LogLevel呢，呵呵）。</pre>
		<pre>      <br />3. TTCCLayout<br />是在PatternLayout基础上发展的一种缺省的带格式输出的布局器， 其格式由时间，线程ID，Logger和NDC 组<br />成（consists of time, thread, Logger and nested diagnostic context information, hence the name），<br />因而得名（怎么得名的？Logger里哪里有那个"C"的缩写啊！名字起得真够烂的，想扁人）。提供给那些想显示<br />典型的信息（一般情况下够用了）又懒得配置pattern的同志们。</pre>
		<pre>TTCCLayout在构造时有机会选择显示本地时间或GMT时间，缺省是按照本地时间显示：<br />TTCCLayout::TTCCLayout(bool use_gmtime  = false)</pre>
		<pre>以下代码片段演示了如何使用TTCCLayout：</pre>
		<pre>    ... ...</pre>
		<pre>    /* step 1: Instantiate an appender object */<br />    SharedObjectPtr _append (new ConsoleAppender());<br />    _append-&gt;setName("append for test");</pre>
		<pre>    /* step 2: Instantiate a layout object */<br />    std::auto_ptr _layout(new TTCCLayout());</pre>
		<pre>    /* step 3: Attach the layout object to the appender */<br />    _append-&gt;setLayout( _layout );</pre>
		<pre>    /* step 4: Instantiate a logger object */<br />    Logger _logger = Logger::getInstance("test_logger");</pre>
		<pre>    /* step 5: Attach the appender object to the logger  */<br />    _logger.addAppender(_append);</pre>
		<pre>     /* log activity */<br />    LOG4CPLUS_DEBUG(_logger, "teststr")<br />    <br />    ... ...<br />    <br />输出结果：<br />10-16-04 19:08:27,501 [1075298944] DEBUG test_logger &lt;&gt; - teststr</pre>
		<pre>
				<br />当构造TTCCLayout对象时选择GMT时间格式时：</pre>
		<pre>    ... ...<br />    <br />    /* step 2: Instantiate a layout object */<br />    std::auto_ptr _layout(new TTCCLayout(true));<br />    <br />    ... ...<br />    <br />输出结果：<br />10-16-04 11:12:47,678 [1075298944] DEBUG test_logger &lt;&gt; - teststr</pre>
		<pre>
				<br />本文介绍了控制log信息格式的相关知识，下一部分将详细介绍log信息的几种文件操作方式。</pre>
<img src ="http://www.cppblog.com/tx7do/aggbug/11717.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2006-08-26 04:49 <a href="http://www.cppblog.com/tx7do/articles/11717.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>开源日志系统log4cplus(一)</title><link>http://www.cppblog.com/tx7do/articles/11715.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Fri, 25 Aug 2006 20:45:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/articles/11715.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/11715.html</wfw:comment><comments>http://www.cppblog.com/tx7do/articles/11715.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/11715.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/11715.html</trackback:ping><description><![CDATA[<p>log4cplus是C++编写的开源的日志系统，功能非常全面，用到自己开发的工程中会比较专业的，：），本文介绍了log4cplus基本概念，以及如何安装，配置。 <br></p>
<pre>				<br>### 简介 ###</pre>
<pre>log4cplus是C++编写的开源的日志系统，前身是java编写的log4j系统.受Apache Software License<br>保护。作者是Tad E. Smith。log4cplus具有线程安全、灵活、以及多粒度控制的特点，通过将信息划分<br>优先级使其可以面向程序调试、运行、测试、和维护等全生命周期； 你可以选择将信息输出到屏幕、文件、<br>NT event log、甚至是远程服务器；通过指定策略对日志进行定期备份等等。</pre>
<pre>&nbsp;</pre>
<pre>### 下载 ###</pre>
<pre>最新的log4cplus可以从以下网址下载 <a href="http://log4cplus.sourceforge.net/"><font color=#002c99>http://log4cplus.sourceforge.net</font></a><br>本文使用的版本为：1.0.2</pre>
<pre>&nbsp;</pre>
<pre>### 安装 ###</pre>
<pre>&nbsp;</pre>
<pre>1. linux下安装</pre>
<pre>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">tar&nbsp;xvzf&nbsp;log4cplus</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">x.x.x.tar.gz<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>cd&nbsp;log4cplus</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">x.x.x.<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">configure&nbsp;</span><span style="COLOR: #000000">--</span><span style="COLOR: #000000">prefix</span><span style="COLOR: #000000">=/</span><span style="COLOR: #000000">where</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">to</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">install<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>make<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>make&nbsp;install</span></div>
<br></pre>
<pre>这里我采用缺省安装路径：/usr/local，下文如无特别说明，均以此路径为准。</pre>
<pre>&nbsp;</pre>
<pre>2. windows下安装</pre>
<pre>不需要安装，有一个msvc6存放包括源代码和用例在内的开发工程（for VC6 only），使用之前请先编译<br>"log4cplus_dll class"工程生成dll，或者编译"log4cplus_static class"工程生成lib.</pre>
<pre>&nbsp;</pre>
<pre>### 使用前的配置 ###</pre>
<pre>1. linux下的配置</pre>
<pre>确保你的Makefile中包含 /usr/local/lib/liblog4cplus.a（静态库）或&nbsp; -llog4cplus（动态库）即可，<br>头文件在/usr/local/include/log4cplus目录下。对于动态库，要想正常使用，还得将库安装路径加入到<br>LD_LIBRARY_PATH 中，我一般是这样做的：以管理员身份登录，在/etc/ld.so.conf中加入安装路径，这里<br>是/usr/local/lib，然后执行ldconfig使设置生效即可。</pre>
<pre>2. windows下的配置</pre>
<pre>将"log4cplus_dll class"工程或"log4cplus_static class"工程的dsp 文件插入到你的工程中，或者直接<br>把两个工程编译生成的库以及头文件所在目录放到你的工程的搜索路径中，如果你使用静态库，请在你的工程中<br>"project/setting/C++"的preprocessor definitions中加入LOG4CPLUS_STATIC。</pre>
<pre>&nbsp;</pre>
<pre>### 构成要素介绍 ###</pre>
<pre>虽然功能强大，应该说log4cplus用起来还是比较复杂的，为了更好地使用它，先介绍一下它的基本要素。</pre>
<pre>Layouts&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ：布局器，控制输出消息的格式.<br>Appenders&nbsp;&nbsp;&nbsp; ：挂接器，与布局器紧密配合，将特定格式的消息输出到所挂接的设备终端<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; （如屏幕，文件等等)。<br>Logger&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ：记录器，保存并跟踪对象日志信息变更的实体，当你需要对一个对象进行<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 记录时，就需要生成一个logger。<br>Categories&nbsp;&nbsp; ：分类器，层次化（hierarchy）的结构，用于对被记录信息的分类，层次中<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 每一个节点维护一个logger的所有信息。<br>Priorities&nbsp;&nbsp; ：优先权，包括TRACE, DEBUG, INFO, WARNING, ERROR, FATAL。</pre>
<pre>				<br>本文介绍了log4cplus基本概念，以及如何安装，配置，下一篇将通过例子介绍如何使用log4cplus。</pre>
<img src ="http://www.cppblog.com/tx7do/aggbug/11715.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2006-08-26 04:45 <a href="http://www.cppblog.com/tx7do/articles/11715.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>  Linux Socket编程实例(一个Hello World程序) </title><link>http://www.cppblog.com/tx7do/articles/5966.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Thu, 20 Apr 2006 09:49:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/articles/5966.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/5966.html</wfw:comment><comments>http://www.cppblog.com/tx7do/articles/5966.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/5966.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/5966.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 在Linux下写了个小的socket程序，分为客户端和服务器端,服务端开一个端口(2000),做为一个daemon,等待客户的连接请求.一旦有客户连接,服务器端打印出客户端的IP地址和端口,并且向服务器端发送欢迎信息和时间.下面是服务端的代码(tcpserver.c).由于这只是个简单的程序，所以只用了单线程实现!/**//*&nbsp;*&nbsp;*&nbsp;Tcp&nbsp;Serve...&nbsp;&nbsp;<a href='http://www.cppblog.com/tx7do/articles/5966.html'>阅读全文</a><img src ="http://www.cppblog.com/tx7do/aggbug/5966.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2006-04-20 17:49 <a href="http://www.cppblog.com/tx7do/articles/5966.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何在linux下检测内存泄漏</title><link>http://www.cppblog.com/tx7do/articles/5964.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Thu, 20 Apr 2006 09:45:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/articles/5964.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/5964.html</wfw:comment><comments>http://www.cppblog.com/tx7do/articles/5964.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/5964.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/5964.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 转载自：http://www.ibm.com/developerworks/cn/linux/l-mleak/index.html洪琨&nbsp;(hcode@21cn.com), C++程序员2003 年 7 月 26 日本文针对 linux 下的 C++ 程序的内存泄漏的检测方法及其实现进行探讨。其中包括 C++ 中的 new 和 delete 的基本原理，内存检测子系统的实现原理...&nbsp;&nbsp;<a href='http://www.cppblog.com/tx7do/articles/5964.html'>阅读全文</a><img src ="http://www.cppblog.com/tx7do/aggbug/5964.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2006-04-20 17:45 <a href="http://www.cppblog.com/tx7do/articles/5964.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux守护进程的编程方法</title><link>http://www.cppblog.com/tx7do/articles/5963.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Thu, 20 Apr 2006 09:43:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/articles/5963.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/5963.html</wfw:comment><comments>http://www.cppblog.com/tx7do/articles/5963.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/5963.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/5963.html</trackback:ping><description><![CDATA[
		<p>
				<span class="Contents">守护进程（Daemon）是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。守护进程是一种很有用的进程。Linux的大多数服务器就是用守护进程实现的。比如，Internet服务器inetd，Web服务器httpd等。同时，守护进程完成许多系统任务。比如，作业规划进程crond，打印进程lpd等。 <br />守护进程的编程本身并不复杂，复杂的是各种版本的Unix的实现机制不尽相同，造成不同Unix环境下守护进程的编程规则并不一致。这需要读者注意，照搬某些书上的规则（特别是BSD4.3和低版本的System V）到Linux会出现错误的。下面将全面介绍Linux下守护进程的编程要点并给出详细实例。 <br /><br />一． 守护进程及其特性 <br /><br />守护进程最重要的特性是后台运行。在这一点上DOS下的常驻内存程序TSR与之相似。其次，守护进程必须与其运行前的环境隔离开来。这些环境包括未关闭的文件描述符，控制终端，会话和进程组，工作目录以及文件创建掩模等。这些环境通常是守护进程从执行它的父进程（特别是shell）中继承下来的。最后，守护进程的启动方式有其特殊之处。它可以在Linux系统启动时从启动脚本/etc/rc.d中启动，可以由作业规划进程crond启动，还可以由用户终端（通常是shell）执行。<br /><br />总之，除开这些特殊性以外，守护进程与普通进程基本上没有什么区别。因此，编写守护进程实际上是把一个普通进程按照上述的守护进程的特性改造成为守护进程。如果读者对进程有比较深入的认识就更容易理解和编程了。 <br /><br />二． 守护进程的编程要点 <br /><br />前面讲过，不同Unix环境下守护进程的编程规则并不一致。所幸的是守护进程的编程原则其实都一样，区别在于具体的实现细节不同。这个原则就是要满足守护进程的特性。同时，Linux是基于Syetem V的SVR4并遵循Posix标准，实现起来与BSD4相比更方便。编程要点如下； <br /><br /></span>1. 屏蔽一些有关控制终端操作的信号。<br />这是为了防止在守护进程没有正常运转起来时，控制终端受到干扰退出或挂起。示例如下：<br /></p>
		<pre style="MARGIN-LEFT: 80px">
				<ccid_code>signal(SIGTTOU,SIG_IGN); <br />signal(SIGTTIN,SIG_IGN); <br />signal(SIGTSTP,SIG_IGN); <br />signal(SIGHUP ,SIG_IGN);</ccid_code>
		</pre>　所有的信号都有自己的名字。这些名字都以“SIG”开头，只是后面有所不同。开发人员可以通过这些名字了解到系统中发生了什么事。当信号出现时，开发人员可以要求系统进行以下三种操作：<br /><p align="left">　忽略信号。大多数信号都是采取这种方式进行处理的，这里就采用了这种用法。但值得注意的是对SIGKILL和SIGSTOP信号不能做忽略处理。<br />　捕捉信号。最常见的情况就是，如果捕捉到SIGCHID信号，则表示子进程已经终止。然后可在此信号的捕捉函数中调用waitpid()函数取得该子进程的进程ID和它的终止状态。另外，如果进程创建了临时文件，那么就要为进程终止信号SIGTERM编写一个信号捕捉函数来清除这些临时文件。<br />　执行系统的默认动作。对绝大多数信号而言，系统的默认动作都是终止该进程。对这些有关终端的信号，一般采用忽略处理，从而保障了终端免受干扰。<br />　这类信号分别是，SIGTTOU（表示后台进程写控制终端）、SIGTTIN（表示后台进程读控制终端）、SIGTSTP（表示终端挂起）和SIGHUP（进程组长退出时向所有会议成员发出的）。 </p><span class="Contents">2. 在后台运行。 <br />为避免挂起控制终端将Daemon放入后台执行。方法是在进程中调用fork使父进程终止，让Daemon在子进程中后台执行。 <br /></span><div style="MARGIN-LEFT: 40px"><div style="MARGIN-LEFT: 40px"><span class="Contents">if(pid=fork()) </span><br /><span class="Contents">exit(0);//是父进程，结束父进程，子进程继续 <br /><br /></span></div><span class="Contents"></span></div><span class="Contents">3. 脱离控制终端，登录会话和进程组 <br />有必要先介绍一下Linux中的进程与控制终端，登录会话和进程组之间的关系：进程属于一个进程组，进程组号（GID）就是进程组长的进程号（PID）。登录会话可以包含多个进程组。这些进程组共享一个控制终端。这个控制终端通常是创建进程的登录终端。 <br />控制终端，登录会话和进程组通常是从父进程继承下来的。我们的目的就是要摆脱它们，使之不受它们的影响。方法是在第1点的基础上，调用setsid()使进程成为会话组长： <br /></span><div style="MARGIN-LEFT: 40px"><div style="MARGIN-LEFT: 40px"><span class="Contents">setsid(); </span><br /></div><span class="Contents"></span></div><span class="Contents">说明：当进程是会话组长时setsid()调用失败。但第一点已经保证进程不是会话组长。setsid()调用成功后，进程成为新的会话组长和新的进程组长，并与原来的登录会话和进程组脱离。由于会话过程对控制终端的独占性，进程同时与控制终端脱离。 <br /><br />4. 禁止进程重新打开控制终端 <br />现在，进程已经成为无终端的会话组长。但它可以重新申请打开一个控制终端。可以通过使进程不再成为会话组长来禁止进程重新打开控制终端： <br /></span><div style="MARGIN-LEFT: 40px"><div style="MARGIN-LEFT: 40px"><span class="Contents">if(pid=fork()) </span><br /><span class="Contents">exit(0);//结束第一子进程，第二子进程继续（第二子进程不再是会话组长） <br /><br /></span></div><span class="Contents"></span></div><span class="Contents">5. 关闭打开的文件描述符 <br />进程从创建它的父进程那里继承了打开的文件描述符。如不关闭，将会浪费系统资源，造成进程所在的文件系统无法卸下以及引起无法预料的错误。按如下方法关闭它们(NOFILE在头文件<sys>中定义)： <br /></sys></span><div style="MARGIN-LEFT: 40px"><div style="MARGIN-LEFT: 40px"><span class="Contents">for(i=0;i &lt; NOFILE;i++)<br />close(i);<br /><br /></span></div><span class="Contents"></span></div><span class="Contents">6. 改变当前工作目录 <br />进程活动时，其工作目录所在的文件系统不能卸下。一般需要将工作目录改变到根目录。对于需要转储核心，写运行日志的进程将工作目录改变到特定目录如/tmp：<br /></span><div style="MARGIN-LEFT: 40px"><div style="MARGIN-LEFT: 40px"><span class="Contents">chdir("/tmp") <br /><br /></span></div><span class="Contents"></span></div><span class="Contents">7. 重设文件创建掩模 <br />进程从创建它的父进程那里继承了文件创建掩模。它可能修改守护进程所创建的文件的存取位。为防止这一点，将文件创建掩模清除：<br /></span><div style="MARGIN-LEFT: 40px"><div style="MARGIN-LEFT: 40px"><span class="Contents">umask(0); <br /><br /></span></div><span class="Contents"></span></div><span class="Contents">8. 处理SIGCHLD信号 <br />处理SIGCHLD信号并不是必须的。但对于某些进程，特别是服务器进程往往在请求到来时生成子进程处理请求。如果父进程不等待子进程结束，子进程将成为僵尸进程（zombie）从而占用系统资源。如果父进程等待子进程结束，将增加父进程的负担，影响服务器进程的并发性能。在Linux下可以简单地将 SIGCHLD信号的操作设为SIG_IGN。 <br /></span><div style="MARGIN-LEFT: 40px"><div style="MARGIN-LEFT: 40px"><span class="Contents">signal(SIGCHLD,SIG_IGN); </span><br /></div><span class="Contents"></span></div><span class="Contents">这样，内核在子进程结束时不会产生僵尸进程。这一点与BSD4不同，BSD4下必须显式等待子进程结束才能释放僵尸进程。 </span><img src ="http://www.cppblog.com/tx7do/aggbug/5963.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2006-04-20 17:43 <a href="http://www.cppblog.com/tx7do/articles/5963.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>