??xml version="1.0" encoding="utf-8" standalone="yes"?>国产精品久久久久久影院 ,久久精品这里只有精99品,亚洲午夜久久久精品影院http://www.shnenglu.com/tx7do/category/1516.html严以律己,宽以待h. 三思而后?</br> GMail/GTalk: yanglinbo#google.com;</br> MSN/Email: tx7do#yahoo.com.cn;</br> QQ: 3 0 3 3 9 6 9 2 0 .zh-cnThu, 10 Jun 2010 08:32:14 GMTThu, 10 Jun 2010 08:32:14 GMT60开源日志系llog4cplus(?http://www.shnenglu.com/tx7do/articles/11721.html杨粼?/dc:creator>杨粼?/author>Fri, 25 Aug 2006 20:51:00 GMThttp://www.shnenglu.com/tx7do/articles/11721.htmlhttp://www.shnenglu.com/tx7do/comments/11721.htmlhttp://www.shnenglu.com/tx7do/articles/11721.html#Feedback4http://www.shnenglu.com/tx7do/comments/commentRss/11721.htmlhttp://www.shnenglu.com/tx7do/services/trackbacks/11721.html 

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

### NDC ###
首先我们先了解一下log4cplus中嵌入诊断上下文QNested Diagnostic ContextQ,即NDC。对logpȝ而言Q?br>当输入源可能不止一个,而只有一个输出时Q往往需要分辩所要输出消息的来源Q比如服务器处理来自不同
客户端的消息时就需要作此判断,NDC可以Z错显C的信息打上一个标?stamp)Q?使得辨认工作看v?br>比较Ҏ些,呵呵。这个标记是U程Ҏ的,利用了线E局部存储机ӞUCؓU程U有数据QThread-specific
 DataQ或TSDQ?看了一下源代码Q相兛_义如下,包括定义、初始化、获取、设|和清除操作Q?/pre>
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)
				
使用h比较单,在某个线E中Q?/pre>
    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Ӟ输出如下Q?/pre>
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) Q比如:
     
  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(); 
    

   
输出如下Q?/pre>
NDC:[]  - This is the FIRST log message...
NDC:[ur ndc string]  - This is the SECOND log message...
				
另外一U更单的使用Ҏ是在U程中直接用NDCContextCreatorQ?/pre>
    NDCContextCreator _first_ndc("ur ndc string");
    LOG4CPLUS_DEBUG(logger, 
"this is a NDC test")

   
不必昑ּ地调用push/pop了,而且当出现异常时Q能够确保push与pop的调用是匚w的?/pre>
    
### U程 ###
U程是log4cplus中的副品, 而且仅作了最基本的实玎ͼ使用h也异常简单,只要且必要
在派生类中重载run函数卛_Q?/pre>
class TestThread : public AbstractThread
{
public:
    
virtual void run();
}
;
                
void TestThread::run()

   
/* do sth. */ 
    
}

log4cplus的线E没有考虑同步、死锁,有互斥,实现U程切换的小函数挺别致的Q?/pre>
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方式的日志记录?/pre>
1. 客户端程序需要做的工作:
/* 定义一个SocketAppendercd的挂接器 */SharedAppenderPtr _append(new SocketAppender(host, 8888"ServerName"));
/* 把_append加入到logger?nbsp;*/Logger::getRoot().addAppender(_append);
/*  SocketAppendercd不需要Layout, 直接调用宏就可以信息发往loggerServer?nbsp;*/LOG4CPLUS_INFO(Logger::getRoot(), "This is a test: ")

【注?q里对宏的调用其实是调用了SocketAppender::appendQ里面有一个数据传输约定,卛_发?br>一个后l数据的总长度,然后再发送实际的数据Q?/pre>
     
    SocketBuffer buffer 
= convertToBuffer(event, serverName);
    SocketBuffer msgBuffer(LOG4CPLUS_MAX_MESSAGE_SIZE);
    msgBuffer.appendSize_t(buffer.getSize());
    msgBuffer.appendBuffer(buffer);        
				
2. 服务器端E序需要做的工作:
/* 定义一个ServerSocket */ServerSocket serverSocket(port);
 
/* 调用accept函数创徏一个新的socket与客Lq接 */Socket sock = serverSocket.accept();
				
此后卛_用该sockq行数据read/write?形如Q?/pre>
SocketBuffer msgSizeBuffer(sizeof(unsigned int));
if(!clientsock.read(msgSizeBuffer))
{
    
return;
}

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

Z读到的数据正常昄出来Q需要将SocketBuffer存放的内容{换成InternalLoggingEvent格式Q?/pre>
spi::InternalLoggingEvent event = readFromBuffer(buffer);
然后输出Q?br>
Logger logger = Logger::getInstance(event.getLoggerName());
logger.callAppenders(
event);
				
【注?read/write是按照阻塞方式实现的Q意味着对其调用直到满了所接收或发送的个数才返回?/pre>

]]>开源日志系llog4cplus(?http://www.shnenglu.com/tx7do/articles/11718.html杨粼?/dc:creator>杨粼?/author>Fri, 25 Aug 2006 20:50:00 GMThttp://www.shnenglu.com/tx7do/articles/11718.htmlhttp://www.shnenglu.com/tx7do/comments/11718.htmlhttp://www.shnenglu.com/tx7do/articles/11718.html#Feedback0http://www.shnenglu.com/tx7do/comments/commentRss/11718.htmlhttp://www.shnenglu.com/tx7do/services/trackbacks/11718.htmllog信息记录到文件应该说是日志系l的一个基本功能,log4cplus在此基础上,提供了更多的功能Q可以按照你预先讑֮的大来军_是否转储Q当过该大,后箋log信息会另存到新文件中Q依ơ类推;或者按照日期来军_是否转储。本文将详细介绍q些用法?/p>
				
### 如何log记录到文?###
我们在例5中给Z一个将log记录到文件的例子Q用的是FileAppendercd现的Qlog4cplus提供了三个类用于
文g操作Q它们是FileAppendercRRollingFileAppendercRDailyRollingFileAppendercR?/pre>
1. FileAppenderc?/pre>
		
实现了基本的文g操作功能Q构造函数如下:
FileAppender(const log4cplus::tstring& filename,
                     LOG4CPLUS_OPEN_MODE_TYPE mode = LOG4CPLUS_FSTREAM_NAMESPACE::ios::trunc,
                     bool immediateFlush = true);
                    
filename       : 文g?br />mode           : 文gcdQ可选择的文件类型包括app、ate、binary、in、out、truncQ因为实际上只是?br />                 stl的一个简单包装,呵呵Q这里就不多讲了。缺省是truncQ表C将先前文g删除?br />immediateFlush Q缓冲刷新标志,如果为true表示每向文g写一条记录就h一ơ缓存,否则直到FileAppender
                 被关闭或文g~存已满才更新文Ӟ一般是要设|true的,比如你往文g写的q程中出?br />                 了错误(如程序非正常退出)Q即使文件没有正常关闭也可以保证E序l止时刻之前的所?br />                 记录都会被正怿存?/pre>
FileAppendercȝ使用情况请参考例5Q这里不再赘q?/pre>
		
				
2. RollingFileAppenderc?/pre>
构造函数如下:
log4cplus::RollingFileAppender::RollingFileAppender(const log4cplus::tstring& filename,
                                                    long maxFileSize,
                                                    int maxBackupIndex,
                                                    bool immediateFlush)
filename       : 文g?br />maxFileSize    : 文g的最大尺?br />maxBackupIndex : 最大记录文件数
immediateFlush : ~冲h标志
                                                   
RollingFileAppendercd以根据你预先讑֮的大来军_是否转储Q当过该大,后箋log信息会另存到?br />文g中,除了定义每个记录文g的大之外,你还要确定在RollingFileAppendercd象构造时最多需要多个
q样的记录文?maxBackupIndex+1)Q当存储的文件数目超qmaxBackupIndex+1Ӟ会删除最早生成的文gQ?br />保证整个文g数目{于maxBackupIndex+1。然后l记录,比如以下代码片段Q?/pre>
    ... ...
   
    #define LOOP_COUNT 200000
   
    SharedAppenderPtr _append(new RollingFileAppender("Test.log", 5*1024, 5));
    _append->setName("file test");
    _append->setLayout( std::auto_ptr(new TTCCLayout()) );
    Logger::getRoot().addAppender(_append);
    Logger root = Logger::getRoot();
    Logger test = Logger::getInstance("test");
    Logger subTest = Logger::getInstance("test.subtest");
    for(int i=0; i    {
        NDCContextCreator _context("loop");
        LOG4CPLUS_DEBUG(subTest, "Entering loop #" << i)
    }
   
    ... ...
   
q行l果Q?/pre>
		
q行后会产生6个输出文ӞTest.log、Test.log.1、Test.log.2、Test.log.3、Test.log.4、Test.log.5
其中Test.log存放着最新写入的信息Q而最后一个文件中q不包含W一个写入信息,说明已经被不断更C?br />需要指出的是,q里除了Test.log之外Q每个文件的大小都是200K,而不是我们想像中?KQ这是因?br />log4cplus中隐含定义了文g的最尺寸是200KQ只有大?00K的设|才生效Q?lt;= 200k的设|都会被认ؓ?br />200K.
				
3. DailyRollingFileAppenderc?/pre>
构造函数如下:
DailyRollingFileAppender::DailyRollingFileAppender(const log4cplus::tstring& filename,
                                                   DailyRollingFileSchedule schedule,
                                                   bool immediateFlush,
                                                   int maxBackupIndex)
                                                  
filename       : 文g?br />schedule       : 存储频度
immediateFlush : ~冲h标志
maxBackupIndex : 最大记录文件数
DailyRollingFileAppendercd以根据你预先讑֮的频度来军_是否转储Q当过该频度,后箋log信息会另?br />到新文g中,q里的频度包括:MONTHLYQ每月)、WEEKLYQ每周)、DAILYQ每日)、TWICE_DAILYQ每两天Q?br />HOURLYQ每Ӟ、MINUTELYQ每分)。maxBackupIndex的含义同上所qͼ比如以下代码片段Q?/pre>
		
    ... ...
   
    SharedAppenderPtr _append(new DailyRollingFileAppender("Test.log", MINUTELY, true, 5));
    _append->setName("file test");
    _append->setLayout( std::auto_ptr(new TTCCLayout()) );
    Logger::getRoot().addAppender(_append);
    Logger root = Logger::getRoot();
    Logger test = Logger::getInstance("test");
    Logger subTest = Logger::getInstance("test.subtest");
    for(int i=0; i    {
        NDCContextCreator _context("loop");
        LOG4CPLUS_DEBUG(subTest, "Entering loop #" << i)
    }
   
    ... ...
				
q行l果Q?/pre>
q行后会以分钟ؓ单位Q分别生成名为Test.log.2004-10-17-03-03、Test.log.2004-10-17-03-04?br />Test.log.2004-10-17-03-05q样的文件?/pre>
		
需要指出的是,刚看到按照频度(如HOURLY、MINUTELYQ{储这L概念Q以为log4cplus提供了内部定时器Q?br />感觉很奇怪,因ؓ日志pȝ不应该主动记录,而loging事gL应该被动触发的啊。仔l看了源代码后才知道
q里?频度"q不是你写入文g的速度Q其实是否{储的标准q不依赖你写入文件的速度Q而是依赖于写?br />的那一时刻是否满了频度条Ӟx否超q了以分钟、小时、周、月为单位的旉dQ如果超q了另存?/pre>
本部分详l介llog信息的几U文件操作方式,下面重点介l一下如何有选择地控制log信息的输出?/pre>


]]>开源日志系llog4cplus(?http://www.shnenglu.com/tx7do/articles/11719.html杨粼?/dc:creator>杨粼?/author>Fri, 25 Aug 2006 20:50:00 GMThttp://www.shnenglu.com/tx7do/articles/11719.htmlhttp://www.shnenglu.com/tx7do/comments/11719.htmlhttp://www.shnenglu.com/tx7do/articles/11719.html#Feedback0http://www.shnenglu.com/tx7do/comments/commentRss/11719.htmlhttp://www.shnenglu.com/tx7do/services/trackbacks/11719.html日志pȝ的另一个基本功能就是能够让使用者按照自q意愿来控制什么时候,哪些log信息可以输出?br />如果能够让用户在L时刻讄允许输出的LogLevel的信息就好了Qlog4cplus通过LogLevelManager?br />LogLog、Filter三种方式实现了上q功能?/pre>
				
### 优先U控?###
在研ILogLevelManager之前Q首先介l一下log4cplus中logger的存储机Ӟ在log4cplus中,所?br />logger都通过一个层ơ化的结构(其实内部是hash表)来组l的Q有一个RootU别的logger,可以?br />q以下方法获取:
    Logger root = Logger::getRoot();
   
用户定义的logger都有一个名字与之对应,比如Q?/pre>
    Logger test = Logger::getInstance("test");
   
可以定义该logger的子logger:
    Logger subTest = Logger::getInstance("test.subtest");
   
注意RootU别的logger只有通过getRootҎ获取QLogger::getInstance("root")获得的是它的
子对象而已。有了这些具有父子关pȝlogger之后可分别设|其LogLevel,比如Q?/pre>
root.setLogLevel( ... );
Test.setLogLevel( ... );
subTest.setLogLevel( ... );
				
logger的这U父子关联性会体现在优先控制斚wQlog4cplus输出的log信息按照LogLevel
Q从低到高)分ؓQ?/pre>
NOT_SET_LOG_LEVEL (   -1) Q接受缺省的LogLevelQ如果有父logger则承它的LogLevel
ALL_LOG_LEVEL     (    0) Q开放所有log信息输出
TRACE_LOG_LEVEL   (    0) Q开放trace信息输出(即ALL_LOG_LEVEL)
DEBUG_LOG_LEVEL   (10000) Q开放debug信息输出
INFO_LOG_LEVEL    (20000) Q开放info信息输出
WARN_LOG_LEVEL    (30000) Q开放warning信息输出
ERROR_LOG_LEVEL   (40000) Q开放error信息输出
FATAL_LOG_LEVEL   (50000) Q开放fatal信息输出
OFF_LOG_LEVEL     (60000) Q关闭所有log信息输出
LogLevelManager负责讄logger的优先Q各个logger可以通过setLogLevel讄自己的优先Q?br />当某个logger的LogLevel讄成NOT_SET_LOG_LEVELӞ该logger会承父logger的优先Q另外,
如果定义了重名的多个logger, 对其中Q何一个的修改都会同时改变其它logger,我们举例说明Q?/pre>
〖例6?/pre>
		
#include "log4cplus/logger.h"
#include "log4cplus/consoleappender.h"
#include "log4cplus/loglevel.h"
#include <iostream>
using namespace std;
using namespace log4cplus;
int main()
{
    SharedAppenderPtr _append(new ConsoleAppender());
    _append->setName("test");
    Logger::getRoot().addAppender(_append);
    Logger root = Logger::getRoot();
    Logger test = Logger::getInstance("test");
    Logger subTest = Logger::getInstance("test.subtest");
    LogLevelManager& llm = getLogLevelManager();
    cout << endl << "Before Setting, Default LogLevel" << endl;
    LOG4CPLUS_FATAL(root, "root: " << llm.toString(root.getChainedLogLevel()))
    LOG4CPLUS_FATAL(root, "test: " << llm.toString(test.getChainedLogLevel()))
    LOG4CPLUS_FATAL(root, "test.subtest: " << llm.toString(subTest.getChainedLogLevel()))
    cout << endl << "Setting test.subtest to WARN" << endl;
    subTest.setLogLevel(WARN_LOG_LEVEL);
    LOG4CPLUS_FATAL(root, "root: " << llm.toString(root.getChainedLogLevel()))
    LOG4CPLUS_FATAL(root, "test: " << llm.toString(test.getChainedLogLevel()))
    LOG4CPLUS_FATAL(root, "test.subtest: " << llm.toString(subTest.getChainedLogLevel()))
    cout << endl << "Setting test.subtest to TRACE" << endl;
    test.setLogLevel(TRACE_LOG_LEVEL);
    LOG4CPLUS_FATAL(root, "root: " << llm.toString(root.getChainedLogLevel()))
    LOG4CPLUS_FATAL(root, "test: " << llm.toString(test.getChainedLogLevel()))
    LOG4CPLUS_FATAL(root, "test.subtest: " << llm.toString(subTest.getChainedLogLevel()))
    cout << endl << "Setting test.subtest to NO_LEVEL" << endl;
    subTest.setLogLevel(NOT_SET_LOG_LEVEL);
    LOG4CPLUS_FATAL(root, "root: " << llm.toString(root.getChainedLogLevel()))
    LOG4CPLUS_FATAL(root, "test: " << llm.toString(test.getChainedLogLevel()))
    LOG4CPLUS_FATAL(root, "test.subtest: " << llm.toString(subTest.getChainedLogLevel()) << '\n')
    cout << "create a logger test_bak, named \"test_\", too. " << endl;
    Logger test_bak = Logger::getInstance("test");
    cout << "Setting test to INFO, so test_bak also be set to INFO" << endl;
    test.setLogLevel(INFO_LOG_LEVEL);
    LOG4CPLUS_FATAL(root, "test: " << llm.toString(test.getChainedLogLevel()))
    LOG4CPLUS_FATAL(root, "test_bak: " << llm.toString(test_bak.getChainedLogLevel()))
    return 0;
}
输出l果Q?/pre>
		
Before Setting, Default LogLevel
FATAL - root: DEBUG
FATAL - test: DEBUG
FATAL - test.subtest: DEBUG
Setting test.subtest to WARN
FATAL - root: DEBUG
FATAL - test: DEBUG
FATAL - test.subtest: WARN
Setting test.subtest to TRACE
FATAL - root: DEBUG
FATAL - test: TRACE
FATAL - test.subtest: WARN
Setting test.subtest to NO_LEVEL
FATAL - root: DEBUG
FATAL - test: TRACE
FATAL - test.subtest: TRACE
create a logger test_bak, named "test_", too.
Setting test to INFO, so test_bak also be set to INFO
FATAL - test: INFO
FATAL - test_bak: INFO
				
下面的例子演CZ如何通过讄LogLevel来控制用Llog信息输出Q?/pre>
〖例7?/pre>
		
#include "log4cplus/logger.h"
#include "log4cplus/consoleappender.h"
#include "log4cplus/loglevel.h"
#include <iostream>
using namespace std;
using namespace log4cplus;
void ShowMsg(void)
{
    LOG4CPLUS_TRACE(Logger::getRoot(),"info")
    LOG4CPLUS_DEBUG(Logger::getRoot(),"info")
    LOG4CPLUS_INFO(Logger::getRoot(),"info")
    LOG4CPLUS_WARN(Logger::getRoot(),"info")
    LOG4CPLUS_ERROR(Logger::getRoot(),"info")
    LOG4CPLUS_FATAL(Logger::getRoot(),"info")
}
int main()
{
    SharedAppenderPtr _append(new ConsoleAppender());
    _append->setName("test");
    _append->setLayout(std::auto_ptr(new TTCCLayout()));
    Logger root = Logger::getRoot();
    root.addAppender(_append);
    cout << endl << "all-log allowed" << endl;
    root.setLogLevel(ALL_LOG_LEVEL);
    ShowMsg();
    cout << endl << "trace-log and above allowed" << endl;
    root.setLogLevel(TRACE_LOG_LEVEL);
    ShowMsg();
    cout << endl << "debug-log and above allowed" << endl;
    root.setLogLevel(DEBUG_LOG_LEVEL);
    ShowMsg();
    cout << endl << "info-log and above allowed" << endl;
    root.setLogLevel(INFO_LOG_LEVEL);
    ShowMsg();
    cout << endl << "warn-log and above allowed" << endl;
    root.setLogLevel(WARN_LOG_LEVEL);
    ShowMsg();
    cout << endl << "error-log and above allowed" << endl;
    root.setLogLevel(ERROR_LOG_LEVEL);
    ShowMsg();
    cout << endl << "fatal-log and above allowed" << endl;
    root.setLogLevel(FATAL_LOG_LEVEL);
    ShowMsg();
    cout << endl << "log disabled" << endl;
    root.setLogLevel(OFF_LOG_LEVEL);
    ShowMsg();
    return 0;
}
输出l果Q?/pre>
		
all-log allowed
10-17-04 10:11:40,587 [1075298944] TRACE root <> - info
10-17-04 10:11:40,590 [1075298944] DEBUG root <> - info
10-17-04 10:11:40,591 [1075298944] INFO root <> - info
10-17-04 10:11:40,591 [1075298944] WARN root <> - info
10-17-04 10:11:40,592 [1075298944] ERROR root <> - info
10-17-04 10:11:40,592 [1075298944] FATAL root <> - info
trace-log and above allowed
10-17-04 10:11:40,593 [1075298944] TRACE root <> - info
10-17-04 10:11:40,593 [1075298944] DEBUG root <> - info
10-17-04 10:11:40,594 [1075298944] INFO root <> - info
10-17-04 10:11:40,594 [1075298944] WARN root <> - info
10-17-04 10:11:40,594 [1075298944] ERROR root <> - info
10-17-04 10:11:40,594 [1075298944] FATAL root <> - info
debug-log and above allowed
10-17-04 10:11:40,595 [1075298944] DEBUG root <> - info
10-17-04 10:11:40,595 [1075298944] INFO root <> - info
10-17-04 10:11:40,596 [1075298944] WARN root <> - info
10-17-04 10:11:40,596 [1075298944] ERROR root <> - info
10-17-04 10:11:40,596 [1075298944] FATAL root <> - info
info-log and above allowed
10-17-04 10:11:40,597 [1075298944] INFO root <> - info
10-17-04 10:11:40,597 [1075298944] WARN root <> - info
10-17-04 10:11:40,597 [1075298944] ERROR root <> - info
10-17-04 10:11:40,598 [1075298944] FATAL root <> - info
warn-log and above allowed
10-17-04 10:11:40,598 [1075298944] WARN root <> - info
10-17-04 10:11:40,598 [1075298944] ERROR root <> - info
10-17-04 10:11:40,599 [1075298944] FATAL root <> - info
error-log and above allowed
10-17-04 10:11:40,599 [1075298944] ERROR root <> - info
10-17-04 10:11:40,600 [1075298944] FATAL root <> - info
fatal-log and above allowed
10-17-04 10:11:40,600 [1075298944] FATAL root <> - info
log disabled
 
用户也可以自行定义LogLevelQ操作比较简单,首先要定义LEVEL|比如HELLO_LOG_LEVEL定义如下Q?/pre>
		
/* DEBUG_LOG_LEVEL  < HELLO_LOG_LEVEL < INFO_LOG_LEVEL */
const LogLevel HELLO_LOG_LEVEL = 15000;
然后定义以下宏即可:
/* define MACRO LOG4CPLUS_HELLO */
#define LOG4CPLUS_HELLO(logger, logEvent) \
    if(logger.isEnabledFor(HELLO_LOG_LEVEL)) { \
        log4cplus::tostringstream _log4cplus_buf; \
        _log4cplus_buf << logEvent; \
 logger.forcedLog(HELLO_LOG_LEVEL, _log4cplus_buf.str(), __FILE__, __LINE__); \
    }
不过log4cplus没有提供l用户一个接口来实现LEVELg字符串的转换Q所以当带格式输出LogLevel字符
串时候会昄"UNKNOWN"Q?不够理想。比如用TTCCLayout控制输出的结果可能会如下所C:
10-17-04 11:17:51,124 [1075298944] UNKNOWN root <> - info
而不是期望的以下l果Q?br />10-17-04 11:17:51,124 [1075298944] HELLO root <> - info
要想实现W二U结果,按照log4cplus现有的接口机Ӟ只能改其源代码后重新~译Q方法是在loglevel.cxx
中加入:
#define _HELLO_STRING LOG4CPLUS_TEXT("HELLO")
然后修改log4cplus::tstring  defaultLogLevelToStringMethod(LogLevel ll)函数Q增加一个判断:
case HELLO_LOG_LEVEL:    return _HELLO_STRING;
重新~译log4cplus源代码后生成库文Ӟ再用时卛_实现满意效果?/pre>
		
				
### 调试模式 ###
即通过loglog来控制输试、警告或错误信息Q见?Q这里不再赘q?/pre>
		
 
### Z脚本配置来过滤log信息 ###
除了通过E序实现对log环境的配|之外,log4cplus通过PropertyConfiguratorcdCZ脚本配置的功能?br />通过脚本可以完成对logger、appender和layout的配|,因此可以解决怎样输出Q输出到哪里的问题,我将?br />全文的最后一部分中提到多U程环境中如何利用脚本配|来配合实现性能试Q本节将重点介绍本实现过
滤log信息的功能?/pre>
首先单介l一下脚本的语法规则Q?/pre>
		
包括Appender的配|语法和logger的配|语法,其中Q?/pre>
		
1.Appender的配|语?
Q?Q设|名Uͼ
/*讄Ҏ*/
log4cplus.appender.appenderName=fully.qualified.name.of.appender.class
例如Q列举了所有可能的AppenderQ其中SocketAppender后面会讲刎ͼQ?br />log4cplus.appender.append_1=log4cplus::ConsoleAppender
log4cplus.appender.append_2=log4cplus::FileAppender
log4cplus.appender.append_3=log4cplus::RollingFileAppender
log4cplus.appender.append_4=log4cplus::DailyRollingFileAppender
log4cplus.appender.append_4=log4cplus::SocketAppender
Q?Q设|FilterQ?/pre>
		
包括选择qo器和讄qo条gQ可选择的过滤器包括QLogLevelMatchFilter、LogLevelRangeFilter?br />和StringMatchFilterQ?/pre>
		
对LogLevelMatchFilter来说Q过滤条件包括LogLevelToMatch和AcceptOnMatchQtrue|falseQ, 只有
当log信息的LogLevelgLogLevelToMatch相同Q且AcceptOnMatch为true时才会匹配?/pre>
LogLevelRangeFilter来说Q过滤条件包括LogLevelMin、LogLevelMax和AcceptOnMatchQ只有当log信息
的LogLevel在LogLevelMin、LogLevelMax之间同时AcceptOnMatch为true时才会匹配?/pre>
对StringMatchFilter来说Q过滤条件包括StringToMatch和AcceptOnMatchQ只有当log信息的LogLevel?br />与StringToMatch对应的LogLevelg相同Q?且AcceptOnMatch为true时会匚w?/pre>
		
				
qo条g处理机制cM于IPTABLE的Responsibility chainQ(卛_deny、再allowQ不q执行顺序刚好相反,
后写的条件会被先执行Q比如:
log4cplus.appender.append_1.filters.1=log4cplus::spi::LogLevelMatchFilter
log4cplus.appender.append_1.filters.1.LogLevelToMatch=TRACE
log4cplus.appender.append_1.filters.1.AcceptOnMatch=true
#log4cplus.appender.append_1.filters.2=log4cplus::spi::DenyAllFilter
会首先执行filters.2的过滤条Ӟ关闭所有过滤器Q然后执行filters.1Q仅匚wTRACE信息?/pre>
		
Q?Q设|Layout
可以选择不设|、TTCCLayout、或PatternLayout
如果不设|,会输出简单格式的log信息?/pre>
		
讄TTCCLayout如下所C:
log4cplus.appender.ALL_MSGS.layout=log4cplus::TTCCLayout
讄PatternLayout如下所C:
log4cplus.appender.append_1.layout=log4cplus::PatternLayout
log4cplus.appender.append_1.layout.ConversionPattern=%d{%m/%d/%y %H:%M:%S,%Q} [%t] %-5p - %m%n
				
2.logger的配|语?/pre>
包括rootLogger和non-root logger?/pre>
		
对于rootLogger来说Q?br />log4cplus.rootLogger=[LogLevel], appenderName, appenderName, ...
对于non-root logger来说Q?br />log4cplus.logger.logger_name=[LogLevel|INHERITED], appenderName, appenderName, ...
				
脚本方式使用h非常单,只要首先加蝲配置卛_Qurconfig.properties是自行定义的配置文gQ:
PropertyConfigurator::doConfigure("urconfig.properties");
				
下面我们通过例子体会一下log4cplus强大的基于脚本过滤log信息的功能?/pre>
				
〖例8?/pre>
/*
 *    urconfig.properties
 */
log4cplus.rootLogger=TRACE, ALL_MSGS, TRACE_MSGS, DEBUG_INFO_MSGS, FATAL_MSGS
log4cplus.appender.ALL_MSGS=log4cplus::RollingFileAppender
log4cplus.appender.ALL_MSGS.File=all_msgs.log
log4cplus.appender.ALL_MSGS.layout=log4cplus::TTCCLayout
log4cplus.appender.TRACE_MSGS=log4cplus::RollingFileAppender
log4cplus.appender.TRACE_MSGS.File=trace_msgs.log
log4cplus.appender.TRACE_MSGS.layout=log4cplus::TTCCLayout
log4cplus.appender.TRACE_MSGS.filters.1=log4cplus::spi::LogLevelMatchFilter
log4cplus.appender.TRACE_MSGS.filters.1.LogLevelToMatch=TRACE
log4cplus.appender.TRACE_MSGS.filters.1.AcceptOnMatch=true
log4cplus.appender.TRACE_MSGS.filters.2=log4cplus::spi::DenyAllFilter
log4cplus.appender.DEBUG_INFO_MSGS=log4cplus::RollingFileAppender
log4cplus.appender.DEBUG_INFO_MSGS.File=debug_info_msgs.log
log4cplus.appender.DEBUG_INFO_MSGS.layout=log4cplus::TTCCLayout
log4cplus.appender.DEBUG_INFO_MSGS.filters.1=log4cplus::spi::LogLevelRangeFilter
log4cplus.appender.DEBUG_INFO_MSGS.filters.1.LogLevelMin=DEBUG
log4cplus.appender.DEBUG_INFO_MSGS.filters.1.LogLevelMax=INFO
log4cplus.appender.DEBUG_INFO_MSGS.filters.1.AcceptOnMatch=true
log4cplus.appender.DEBUG_INFO_MSGS.filters.2=log4cplus::spi::DenyAllFilter
log4cplus.appender.FATAL_MSGS=log4cplus::RollingFileAppender
log4cplus.appender.FATAL_MSGS.File=fatal_msgs.log
log4cplus.appender.FATAL_MSGS.layout=log4cplus::TTCCLayout
log4cplus.appender.FATAL_MSGS.filters.1=log4cplus::spi::StringMatchFilter
log4cplus.appender.FATAL_MSGS.filters.1.StringToMatch=FATAL
log4cplus.appender.FATAL_MSGS.filters.1.AcceptOnMatch=true
log4cplus.appender.FATAL_MSGS.filters.2=log4cplus::spi::DenyAllFilter
				
/*
 *    main.cpp
 */
#include <log4cplus/logger.h>
#include <log4cplus/configurator.h>
#include <log4cplus/helpers/stringhelper.h>
using namespace log4cplus;
static Logger logger = Logger::getInstance("log");
void printDebug()
{
    LOG4CPLUS_TRACE_METHOD(logger, "::printDebug()");
    LOG4CPLUS_DEBUG(logger, "This is a DEBUG message");
    LOG4CPLUS_INFO(logger, "This is a INFO message");
    LOG4CPLUS_WARN(logger, "This is a WARN message");
    LOG4CPLUS_ERROR(logger, "This is a ERROR message");
    LOG4CPLUS_FATAL(logger, "This is a FATAL message");
}
int main()
{
    Logger root = Logger::getRoot();
    PropertyConfigurator::doConfigure("urconfig.properties");
    printDebug();
    return 0;
}
q行l果Q?/pre>
		
1. all_msgs.log
10-17-04 14:55:25,858 [1075298944] TRACE log <> - ENTER: ::printDebug()
10-17-04 14:55:25,871 [1075298944] DEBUG log <> - This is a DEBUG message
10-17-04 14:55:25,873 [1075298944] INFO log <> - This is a INFO message
10-17-04 14:55:25,873 [1075298944] WARN log <> - This is a WARN message
10-17-04 14:55:25,874 [1075298944] ERROR log <> - This is a ERROR message
10-17-04 14:55:25,874 [1075298944] FATAL log <> - This is a FATAL message
10-17-04 14:55:25,875 [1075298944] TRACE log <> - EXIT:  ::printDebug()
2. trace_msgs.log
10-17-04 14:55:25,858 [1075298944] TRACE log <> - ENTER: ::printDebug()
10-17-04 14:55:25,875 [1075298944] TRACE log <> - EXIT:  ::printDebug()
3. debug_info_msgs.log
10-17-04 14:55:25,871 [1075298944] DEBUG log <> - This is a DEBUG message
10-17-04 14:55:25,873 [1075298944] INFO log <> - This is a INFO message
4. fatal_msgs.log
10-17-04 14:55:25,874 [1075298944] FATAL log <> - This is a FATAL message
 
本部分详l介l了如何有选择地控制log信息的输出,最后一部分我们介l一下多U程?br />和C/S模式下该如何操作Q顺便提一下NDC的概c?/pre>


]]>开源日志系llog4cplus(?http://www.shnenglu.com/tx7do/articles/11720.html杨粼?/dc:creator>杨粼?/author>Fri, 25 Aug 2006 20:50:00 GMThttp://www.shnenglu.com/tx7do/articles/11720.htmlhttp://www.shnenglu.com/tx7do/comments/11720.htmlhttp://www.shnenglu.com/tx7do/articles/11720.html#Feedback0http://www.shnenglu.com/tx7do/comments/commentRss/11720.htmlhttp://www.shnenglu.com/tx7do/services/trackbacks/11720.htmllog4cplus在很多方面做的都很出Ԍ但是使用q程有些地方感觉不爽。在l箋Ҏ之前我先把不爽之?br />E微提一提,然后l箋介绍关于U程和套接字的知识?br />

### 一些可以改q之?###
1. 用户自定义LogLevel的实现机制不够开?/pre>
		
在第五篇中曾l介l过如何实现用户自行定义LogLevelQؓ了实现比较理想的效果Q甚臌需要改log4cplus
的源代码。:Q?/pre>
2. 生成Logger对象的机制可以改q?/pre>
		
我在使用时候,l常需要在不同的文件、函C操作同一个loggerQ虽然log4cplus实现了树状存储以及根?br />名称生成LoggerQ却没有充分利用q样的特点确保同一个名U对应的logger对象的唯一性,比如以下代码Q?/pre>
		
    ... ...
   
    Logger logger1 = Logger::getInstance("test");
    Logger logger2 = Logger::getInstance("test");
    Logger * plogger1 = &logger1;
    Logger * plogger2 = &logger2;
    std::cout << "plogger1: " << plogger1 << std::endl << "plogger2: " << plogger2 << std::endl;
   
    ... ...
   
   
q行l果Q?/pre>
plogger1: 0xbfffe5a0
plogger2: 0xbfffe580
				
从结果可以看出,明明是同一个LoggerQ但每次调用都会产生一个Logger副本Q虽然结果是正确的(因ؓ存
储和操作分开了)Q但是资源有些浪费,我看了一下log4cplus的代码,其实可以按照如下方式实现Q示意?br />的)Q?/pre>
#include <iostream>
#include <string>
#include <map>
/* forward declaration */
class Logger;
class LoggerContainer
{
public:
    ~LoggerContainer();
    Logger * getinstance(const std::string & strLogger);
private:
    typedef std::map<:string,> LoggerMap;
    LoggerMap loggerPtrs;
};
class Logger
{
public:
     Logger() {std::cout << "ctor of Logger " << std::endl; }
    ~Logger() {std::cout << "dtor of Logger " << std::endl; }
    static Logger * getInstance( const std::string & strLogger)
    {
        static LoggerContainer defaultLoggerContainer;
        return defaultLoggerContainer.getinstance(strLogger);
    }
};
LoggerContainer::~LoggerContainer()
{
    /* release all ptr in LoggerMap */
    LoggerMap::iterator itr = loggerPtrs.begin();
    for( ; itr != loggerPtrs.end(); ++itr )
 {
     delete (*itr).second;
 }
}
Logger * LoggerContainer::getinstance(const std::string & strLogger)
{
   LoggerMap::iterator itr = loggerPtrs.find(strLogger);
   if(itr != loggerPtrs.end())
   {
       /* logger exist, just return it */
       return (*itr).second;
   }
   else
   {
       /* return a new logger */
       Logger * plogger = new Logger();
       loggerPtrs.insert(std::make_pair(strLogger, plogger));
       return plogger;
   }
}
int main()
{
    Logger * plogger1 = Logger::getInstance("test");
    Logger * plogger2 = Logger::getInstance("test");
    std::cout << "plogger1: " << plogger1 << std::endl << "plogger2: " << plogger2 << std::endl;
    return 0;
}
				
q行l果Q?/pre>
ctor of Logger
plogger1: 0x804fc30
plogger2: 0x804fc30
dtor of Logger
q里的LoggerContainer相当于log4cplus中的Hierarchyc,l果可以看出Q通过同一个名U可以获取相同的
Logger实例?/pre>
				
q有一些小毛病比如RollingFileAppender和DailyRollingFileAppender的参数输入顺序可以调整成l一方式
{等Q就不细说了?/pre>
本部分提C使用log4cplus时候感觉不爽的地方Q最后一部分介l一下log4cplus中线E和套接字实现情?br />


]]>开源日志系llog4cplus(?http://www.shnenglu.com/tx7do/articles/11716.html杨粼?/dc:creator>杨粼?/author>Fri, 25 Aug 2006 20:49:00 GMThttp://www.shnenglu.com/tx7do/articles/11716.htmlhttp://www.shnenglu.com/tx7do/comments/11716.htmlhttp://www.shnenglu.com/tx7do/articles/11716.html#Feedback0http://www.shnenglu.com/tx7do/comments/commentRss/11716.htmlhttp://www.shnenglu.com/tx7do/services/trackbacks/11716.html阅读全文

]]>
开源日志系llog4cplus(?http://www.shnenglu.com/tx7do/articles/11717.html杨粼?/dc:creator>杨粼?/author>Fri, 25 Aug 2006 20:49:00 GMThttp://www.shnenglu.com/tx7do/articles/11717.htmlhttp://www.shnenglu.com/tx7do/comments/11717.htmlhttp://www.shnenglu.com/tx7do/articles/11717.html#Feedback0http://www.shnenglu.com/tx7do/comments/commentRss/11717.htmlhttp://www.shnenglu.com/tx7do/services/trackbacks/11717.html本文介绍了三U控制输出格式的布局理器的概念和用情况,通过掌握q些知识Q可以更有效地控制logpȝ输出可能脓q你需求的信息来?br />

				
### 如何控制输出消息的格?###
前面已经讲过Qlog4cplus通过布局器(LayoutsQ来控制输出的格式,log4cplus提供了三U类型的LayoutsQ?br />分别是SimpleLayout、PatternLayout、和TTCCLayout。其中:
1. SimpleLayout
是一U简单格式的布局器,在输出的原始信息之前加上LogLevel和一?-"?/pre>
比如以下代码片段Q?/pre>
		
    ... ...
    /* step 1: Instantiate an appender object */
    SharedObjectPtr _append (new ConsoleAppender());
    _append->setName("append for test");
    /* step 2: Instantiate a layout object */
    std::auto_ptr  _layout(new log4cplus::SimpleLayout());
    /* step 3: Attach the layout object to the appender */
    _append->setLayout( _layout );
    /* step 4: Instantiate a logger object */
    Logger _logger = Logger::getInstance("test");
    /* step 5: Attach the appender object to the logger  */
    _logger.addAppender(_append);
     /* log activity */
    LOG4CPLUS_DEBUG(_logger, "This is the simple formatted log message...")
   
    ... ...
   
   
打印结果:
DEBUG - This is the simple formatted log message...
2. PatternLayout
是一U有词法分析功能的模式布局器,一提v模式׃惌v正则表达式,q里的模式和正则表达式类|但是
q比后者简单,能够寚w定义的标识符Q称为conversion specifiersQ进行解析,转换成特定格式输出。以?br />代码片段演示了如何用PatternLayoutQ?/pre>
    ... ...
    /* step 1: Instantiate an appender object */
    SharedObjectPtr _append (new ConsoleAppender());
    _append->setName("append for test");
  
    /* step 2: Instantiate a layout object */
    std::string pattern = "%d{%m/%d/%y %H:%M:%S}  - %m [%l]%n";
    std::auto_ptr _layout(new PatternLayout(pattern));
   
    /* step 3: Attach the layout object to the appender */
    _append->setLayout( _layout );
    /* step 4: Instantiate a logger object */
    Logger _logger = Logger::getInstance("test_logger.subtest");
    /* step 5: Attach the appender object to the logger  */
    _logger.addAppender(_append);
     /* log activity */
    LOG4CPLUS_DEBUG(_logger, "teststr")
   
    ... ...
   
输出l果Q?br />10/16/04 18:51:25  - teststr [main.cpp:51]
可以看出通过填写特定格式的模式字W串"pattern"Q原始信息被包含C堆有格式的信息当中了Q这׃?br />用户可以Ҏ自n需要来定制昄内容?pattern"可以包含普通字W串和预定义的标识符Q其中:
Q?Q普通字W串Q能够被直接昄的信息?br />Q?Q预定义标识W,通过"%"与一个或多个字符共同构成预定义的标识W,能够产生出特定格式信息?/pre>
		
关于预定义标识符Qlog4cplus文档中提供了详细的格式说明,我每U都试了一下,以上qC码ؓ例,Ҏ不同
的patternQ各U消息格式用情况列丑֦下:
Q?Q?%%"Q{义ؓ%, 卻Istd::string pattern = "%%" 时输? "%"
Q?Q?%c"Q输出logger名称Q比如std::string pattern ="%c" 时输? "test_logger.subtest"Q?br />     也可以控制logger名称的显C层ơ,比如"%c{1}"时输?test_logger"Q其中数字表C层ơ?br />Q?Q?%D"Q显C本地时_当std::string pattern ="%D" 时输?"2004-10-16 18:55:45"Q?d昄标准旉Q?br />     所以当std::string pattern ="%d" 时输?"2004-10-16 10:55:45" Q因为我们是?区,?个小时啊Q?br />     可以通过%d{...}定义更详l的昄格式Q比?d{%H:%M:%s}表示要显C小?分钟Q秒。大括号中可昄?br />     预定义标识符如下Q?br />    
%a -- 表示C拜几,英文~写形式Q比?Fri"
%A -- 表示C拜几,比如"Friday"
%b -- 表示几月份,英文~写形式Q比?Oct"
%B -- 表示几月份,"October"
%c -- 标准的日期+旉格式Q如 "Sat Oct 16 18:56:19 2004"
%d -- 表示今天是这个月的几?1-31)"16"
%H -- 表示当前时刻是几?0-23)Q如 "18"
%I -- 表示当前时刻是几?1-12)Q如 "6"
%j -- 表示今天是哪一?1-366)Q如 "290"
%m -- 表示本月是哪一?1-12)Q如 "10"
%M -- 表示当前时刻是哪一分钟(0-59)Q如 "59"
%p -- 表示现在是上午还是下午, AM or PM
%q -- 表示当前时刻中毫U部?0-999)Q如 "237"
%Q -- 表示当前时刻中带数的毫U部?0-999.999)Q如 "430.732"
%S -- 表示当前时刻的多秒(0-59)Q如 "32"
%U -- 表示本周是今q的W几个礼拜,以周日ؓW一天开始计?0-53)Q如 "41"
%w -- 表示C拜几,(0-6, C拜天ؓ0)Q如 "6"
%W -- 表示本周是今q的W几个礼拜,以周一为第一天开始计?0-53)Q如 "41"
%x -- 标准的日期格式,?"10/16/04"
%X -- 标准的时间格式,?"19:02:34"
%y -- 两位数的q䆾(0-99)Q如 "04"
%Y -- 四位数的q䆾Q如 "2004"
%Z -- 时区名,比如 "GMT"
Q?Q?%F"Q输出当前记录器所在的文g名称Q比如std::string pattern ="%F" 时输? "main.cpp"
Q?Q?%L"Q输出当前记录器所在的文g行号Q比如std::string pattern ="%L" 时输? "51"
Q?Q?%l"Q输出当前记录器所在的文g名称和行P比如std::string pattern ="%L" 时输?
     "main.cpp:51"
Q?Q?%m"Q输出原始信息,比如std::string pattern ="%m" 时输? "teststr"Q即上述代码?br />     LOG4CPLUS_DEBUG的第二个参数Q这U实现机制可以确保原始信息被嵌入到带格式的信息中?br />Q?Q?%n"Q换行符Q没什么好解释?br />Q?Q?%p"Q输出LogLevelQ比如std::string pattern ="%p" 时输? "DEBUG"
Q?0Q?%t"Q输录器所在的U程IDQ比如std::string pattern ="%t" 时输? "1075298944"
Q?1Q?%x"Q嵌套诊断上下文NDC (nested diagnostic context) 输出Q从堆栈中弹Z下文信息QNDC可以用对
      不同源的log信息Q同时地Q交叉输行区分,关于NDC斚w的详l介l会在下文中提到?br />Q?2Q格式对齐,比如std::string pattern ="%-10m"时表C左寚wQ宽度是10Q此时会输出"teststr   "Q当
      然其它的控制字符也可以相同的方式来用,比如"%-12d"Q?%-5p"{等Q刚接触log4cplus文档时还以ؓ
      "%-5p"整个字符串代表LogLevel呢,呵呵Q?/pre>
      
3. TTCCLayout
是在PatternLayout基础上发展的一U缺省的带格式输出的布局器, 其格式由旉Q线EIDQLogger和NDC l?br />成(consists of time, thread, Logger and nested diagnostic context information, hence the nameQ,
因而得名(怎么得名的?Logger里哪里有那个"C"的羃写啊Q名字v得真够烂的,x人)。提供给那些xC?br />典型的信息(一般情况下够用了)又懒得配|pattern的同志们?/pre>
TTCCLayout在构造时有机会选择昄本地旉或GMT旉Q缺省是按照本地旉昄Q?br />TTCCLayout::TTCCLayout(bool use_gmtime  = false)
以下代码片段演示了如何用TTCCLayoutQ?/pre>
		
    ... ...
    /* step 1: Instantiate an appender object */
    SharedObjectPtr _append (new ConsoleAppender());
    _append->setName("append for test");
    /* step 2: Instantiate a layout object */
    std::auto_ptr _layout(new TTCCLayout());
    /* step 3: Attach the layout object to the appender */
    _append->setLayout( _layout );
    /* step 4: Instantiate a logger object */
    Logger _logger = Logger::getInstance("test_logger");
    /* step 5: Attach the appender object to the logger  */
    _logger.addAppender(_append);
     /* log activity */
    LOG4CPLUS_DEBUG(_logger, "teststr")
   
    ... ...
   
输出l果Q?br />10-16-04 19:08:27,501 [1075298944] DEBUG test_logger <> - teststr
				
当构造TTCCLayout对象旉择GMT旉格式Ӟ
    ... ...
   
    /* step 2: Instantiate a layout object */
    std::auto_ptr _layout(new TTCCLayout(true));
   
    ... ...
   
输出l果Q?br />10-16-04 11:12:47,678 [1075298944] DEBUG test_logger <> - teststr
				
本文介绍了控制log信息格式的相关知识,下一部分详l介llog信息的几U文件操作方式?/pre>

]]>开源日志系llog4cplus(一)http://www.shnenglu.com/tx7do/articles/11715.html杨粼?/dc:creator>杨粼?/author>Fri, 25 Aug 2006 20:45:00 GMThttp://www.shnenglu.com/tx7do/articles/11715.htmlhttp://www.shnenglu.com/tx7do/comments/11715.htmlhttp://www.shnenglu.com/tx7do/articles/11715.html#Feedback0http://www.shnenglu.com/tx7do/comments/commentRss/11715.htmlhttp://www.shnenglu.com/tx7do/services/trackbacks/11715.htmllog4cplus是C++~写的开源的日志pȝQ功能非常全面,用到自己开发的工程中会比较专业的,Q)Q本文介l了log4cplus基本概念Q以及如何安装,配置?

				
### ?###
log4cplus是C++~写的开源的日志pȝQ前w是java~写的log4jpȝ.受Apache Software License
保护。作者是Tad E. Smith。log4cplushU程安全、灵zR以及多_度控制的特点,通过信息划?br>优先U其可以面向程序调试、运行、测试、和l护{全生命周期Q?你可以选择信息输出到屏幕、文件?br>NT event log、甚xq程服务器;通过指定{略Ҏ志进行定期备份等{?/pre>
 
### 下蝲 ###
最新的log4cplus可以从以下网址下蝲 http://log4cplus.sourceforge.net
本文使用的版本ؓQ?.0.2
 
### 安装 ###
 
1. linux下安?/pre>
tar xvzf log4cplus-x.x.x.tar.gz
cd log4cplus
-x.x.x.
/configure --prefix=/where/to/install
make
make install

q里我采用缺省安装\径:/usr/localQ下文如无特别说明,均以此\径ؓ准?/pre>
 
2. windows下安?/pre>
不需要安装,有一个msvc6存放包括源代码和用例在内的开发工E(for VC6 onlyQ,使用之前请先~译
"log4cplus_dll class"工程生成dllQ或者编?log4cplus_static class"工程生成lib.
 
### 使用前的配置 ###
1. linux下的配置
保你的Makefile中包?/usr/local/lib/liblog4cplus.aQ静态库Q或  -llog4cplusQ动态库Q即可,
头文件在/usr/local/include/log4cplus目录下。对于动态库Q要x怋用,q得库安装路径加入?br>LD_LIBRARY_PATH 中,我一般是q样做的Q以理员n份登录,?etc/ld.so.conf中加入安装\径,q里
?usr/local/libQ然后执行ldconfig使设|生效即可?/pre>
2. windows下的配置
?log4cplus_dll class"工程?log4cplus_static class"工程的dsp 文g插入C的工E中Q或者直?br>把两个工E编译生成的库以及头文g所在目录放C的工E的搜烦路径中,如果你用静态库Q请在你的工E中
"project/setting/C++"的preprocessor definitions中加入LOG4CPLUS_STATIC?/pre>
 
### 构成要素介绍 ###
虽然功能强大Q应该说log4cplus用v来还是比较复杂的Qؓ了更好地使用它,先介l一下它的基本要素?/pre>
Layouts      Q布局器,控制输出消息的格?
Appenders    Q挂接器Q与布局器紧密配合,特定格式的消息输出到所挂接的设备终?br>               Q如屏幕Q文件等{??br>Logger       Q记录器Q保存ƈ跟踪对象日志信息变更的实体,当你需要对一个对象进?br>               记录Ӟ需要生成一个logger?br>Categories   Q分cdQ层ơ化QhierarchyQ的l构Q用于对被记录信息的分类Q层ơ中
               每一个节点维护一个logger的所有信息?br>Priorities   Q优先权Q包括TRACE, DEBUG, INFO, WARNING, ERROR, FATAL?/pre>
				
本文介绍了log4cplus基本概念Q以及如何安装,配置Q下一将通过例子介绍如何使用log4cplus?/pre>

]]> Linux Socket~程实例(一个Hello WorldE序) http://www.shnenglu.com/tx7do/articles/5966.html杨粼?/dc:creator>杨粼?/author>Thu, 20 Apr 2006 09:49:00 GMThttp://www.shnenglu.com/tx7do/articles/5966.htmlhttp://www.shnenglu.com/tx7do/comments/5966.htmlhttp://www.shnenglu.com/tx7do/articles/5966.html#Feedback0http://www.shnenglu.com/tx7do/comments/commentRss/5966.htmlhttp://www.shnenglu.com/tx7do/services/trackbacks/5966.html阅读全文

]]>
如何在linux下检内存泄?/title><link>http://www.shnenglu.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.shnenglu.com/tx7do/articles/5964.html</guid><wfw:comment>http://www.shnenglu.com/tx7do/comments/5964.html</wfw:comment><comments>http://www.shnenglu.com/tx7do/articles/5964.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.shnenglu.com/tx7do/comments/commentRss/5964.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/tx7do/services/trackbacks/5964.html</trackback:ping><description><![CDATA[     摘要: 转蝲自:http://www.ibm.com/developerworks/cn/linux/l-mleak/index.html z琨 (hcode@21cn.com), C++E序?2003 q?7 ?26 ?本文针对 linux 下的 C++ E序的内存泄漏的方法及其实现进行探讨。其中包?C++ 中的 new ?delete 的基本原理,内存子pȝ的实现原?..  <a href='http://www.shnenglu.com/tx7do/articles/5964.html'>阅读全文</a><img src ="http://www.shnenglu.com/tx7do/aggbug/5964.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/tx7do/" target="_blank">杨粼?/a> 2006-04-20 17:45 <a href="http://www.shnenglu.com/tx7do/articles/5964.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux守护q程的编E方?/title><link>http://www.shnenglu.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.shnenglu.com/tx7do/articles/5963.html</guid><wfw:comment>http://www.shnenglu.com/tx7do/comments/5963.html</wfw:comment><comments>http://www.shnenglu.com/tx7do/articles/5963.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.shnenglu.com/tx7do/comments/commentRss/5963.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/tx7do/services/trackbacks/5963.html</trackback:ping><description><![CDATA[ <p> <span id="eecus4y" class="Contents">守护q程QDaemonQ是q行在后台的一U特D进E。它独立于控制终端ƈ且周期性地执行某种d或等待处理某些发生的事g。守护进E是一U很有用的进E。Linux的大多数服务器就是用守护q程实现的。比如,Internet服务器inetdQWeb服务器httpd{。同Ӟ守护q程完成许多pȝd。比如,作业规划q程crondQ打印进Elpd{?<br />守护q程的编E本wƈ不复杂,复杂的是各种版本的Unix的实现机制不相同,造成不同Unix环境下守护进E的~程规则q不一致。这需要读者注意,照搬某些书上的规则(特别是BSD4.3和低版本的System VQ到Linux会出现错误的。下面将全面介绍Linux下守护进E的~程要点q给l实例?<br /><br />一Q?守护q程及其Ҏ?<br /><br />守护q程最重要的特性是后台q行。在q一点上DOS下的帔R内存E序TSR与之怼。其ơ,守护q程必须与其q行前的环境隔离开来。这些环境包括未关闭的文件描q符Q控制终端,会话和进E组Q工作目录以及文件创建掩模等。这些环境通常是守护进E从执行它的父进E(特别是shellQ中l承下来的。最后,守护q程的启动方式有其特D之处。它可以在Linuxpȝ启动时从启动脚本/etc/rc.d中启动,可以׃业规划进Ecrond启动Q还可以qL端(通常是shellQ执行?br /><br />MQ除开q些Ҏ性以外,守护q程与普通进E基本上没有什么区别。因此,~写守护q程实际上是把一个普通进E按照上q的守护q程的特性改造成为守护进E。如果读者对q程有比较深入的认识更Ҏ理解和编E了?<br /><br />二. 守护q程的编E要?<br /><br />前面讲过Q不同Unix环境下守护进E的~程规则q不一致。所q的是守护进E的~程原则其实都一P区别在于具体的实现细节不同。这个原则就是要满守护q程的特性。同ӞLinux是基于Syetem V的SVR4q循Posix标准Q实现v来与BSD4相比更方ѝ编E要点如下; <br /><br /></span>1. 屏蔽一些有x制终端操作的信号?br />q是Z防止在守护进E没有正常运转v来时Q控制终端受到干扰退出或挂v。示例如下:<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”开_只是后面有所不同。开发h员可以通过q些名字了解到系l中发生了什么事。当信号出现Ӟ开发h员可以要求系l进行以下三U操作:<br /><p align="left"> 忽略信号。大多数信号都是采取q种方式q行处理的,q里采用了q种用法。但值得注意的是对SIGKILL和SIGSTOP信号不能做忽略处理?br /> 捕捉信号。最常见的情况就是,如果捕捉到SIGCHID信号Q则表示子进E已l终止。然后可在此信号的捕捉函C调用waitpid()函数取得该子q程的进EID和它的终止状态。另外,如果q程创徏了时文Ӟ那么pE终止信号SIGTERM~写一个信h捉函数来清除q些临时文g?br /> 执行pȝ的默认动作。对l大多数信号而言Q系l的默认动作都是l止该进E。对q些有关l端的信P一般采用忽略处理,从而保障了l端免受q扰?br /> q类信号分别是,SIGTTOUQ表C后台进E写控制l端Q、SIGTTINQ表C后台进E读控制l端Q、SIGTSTPQ表C终端挂P和SIGHUPQ进E组镉K出时向所有会议成员发出的Q?</p><span id="2cuimew" class="Contents">2. 在后台运行?<br />为避免挂h制终端将Daemon攑օ后台执行。方法是在进E中调用fork使父q程l止Q让Daemon在子q程中后台执行?<br /></span><div style="MARGIN-LEFT: 40px"><div style="MARGIN-LEFT: 40px"><span id="su244m4" class="Contents">if(pid=fork()) </span><br /><span id="wes44s4" class="Contents">exit(0);//是父q程Q结束父q程Q子q程l箋 <br /><br /></span></div><span id="s2cuu26" class="Contents"></span></div><span id="m6oi2gk" class="Contents">3. q控制l端Q登录会话和q程l?<br />有必要先介绍一下Linux中的q程与控制终端,d会话和进E组之间的关p:q程属于一个进E组Q进E组PGIDQ就是进E组长的q程PPIDQ。登录会话可以包含多个进E组。这些进E组׃n一个控制终端。这个控制终端通常是创E的dl端?<br />控制l端Q登录会话和q程l通常是从父进E承下来的。我们的目的是要摆脱它们,使之不受它们的媄响。方法是在第1点的基础上,调用setsid()使进E成Z话组长: <br /></span><div style="MARGIN-LEFT: 40px"><div style="MARGIN-LEFT: 40px"><span id="24mgu66" class="Contents">setsid(); </span><br /></div><span id="4ao2s4w" class="Contents"></span></div><span id="mw2em4c" class="Contents">说明Q当q程是会话组长时setsid()调用p|。但W一点已l保证进E不是会话组ѝsetsid()调用成功后,q程成ؓ新的会话l长和新的进E组长,q与原来的登录会话和q程l脱R由于会话过E对控制l端的独占性,q程同时与控制终端脱R?<br /><br />4. 止q程重新打开控制l端 <br />现在Q进E已l成为无l端的会话组ѝ但它可以重新申h开一个控制终端。可以通过使进E不再成Z话组长来止q程重新打开控制l端Q?<br /></span><div style="MARGIN-LEFT: 40px"><div style="MARGIN-LEFT: 40px"><span id="myc2oqu" class="Contents">if(pid=fork()) </span><br /><span id="e244k44" class="Contents">exit(0);//l束W一子进E,W二子进El(W二子进E不再是会话l长Q?<br /><br /></span></div><span id="2k4kcwc" class="Contents"></span></div><span id="cme4q2y" class="Contents">5. 关闭打开的文件描q符 <br />q程从创建它的父q程那里l承了打开的文件描q符。如不关闭,会费pȝ资源Q造成q程所在的文gpȝ无法怸以及引v无法预料的错误。按如下Ҏ关闭它们(NOFILE在头文g<sys>中定?Q?<br /></sys></span><div style="MARGIN-LEFT: 40px"><div style="MARGIN-LEFT: 40px"><span id="ye2uoca" class="Contents">for(i=0;i < NOFILE;i++)<br />close(i);<br /><br /></span></div><span id="2y2444a" class="Contents"></span></div><span id="ca2gy22" class="Contents">6. 改变当前工作目录 <br />q程zdӞ其工作目录所在的文gpȝ不能怸。一般需要将工作目录改变到根目录。对于需要{储核心,写运行日志的q程工作目录改变到特定目录?tmpQ?br /></span><div style="MARGIN-LEFT: 40px"><div style="MARGIN-LEFT: 40px"><span id="k2o2oiw" class="Contents">chdir("/tmp") <br /><br /></span></div><span id="24444ma" class="Contents"></span></div><span id="e2422e4" class="Contents">7. 重设文g创徏掩模 <br />q程从创建它的父q程那里l承了文件创建掩模。它可能修改守护q程所创徏的文件的存取位。ؓ防止q一点,文件创建掩模清除:<br /></span><div style="MARGIN-LEFT: 40px"><div style="MARGIN-LEFT: 40px"><span id="e424mgu" class="Contents">umask(0); <br /><br /></span></div><span id="i44uoe2" class="Contents"></span></div><span id="wg4eew2" class="Contents">8. 处理SIGCHLD信号 <br />处理SIGCHLD信号q不是必ȝ。但对于某些q程Q特别是服务器进E往往在请求到来时生成子进E处理请求。如果父q程不等待子q程l束Q子q程成为僵进E(zombieQ从而占用系l资源。如果父q程{待子进E结束,增加父q程的负担,影响服务器进E的q发性能。在Linux下可以简单地?SIGCHLD信号的操作设为SIG_IGN?<br /></span><div style="MARGIN-LEFT: 40px"><div style="MARGIN-LEFT: 40px"><span id="ia4ko2w" class="Contents">signal(SIGCHLD,SIG_IGN); </span><br /></div><span id="u4gy2ec" class="Contents"></span></div><span id="as4cwws" class="Contents">q样Q内核在子进E结束时不会产生僵尸q程。这一点与BSD4不同QBSD4下必L式等待子q程l束才能释放僵尸q程?</span><img src ="http://www.shnenglu.com/tx7do/aggbug/5963.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/tx7do/" target="_blank">杨粼?/a> 2006-04-20 17:43 <a href="http://www.shnenglu.com/tx7do/articles/5963.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <p>лǵվܻԴȤ</p> <a href="http://www.shnenglu.com/" title="精品视频久久久久">精品视频久久久久</a> <div class="friend-links"> </div> </div> </footer> <a href="http://www.taskbee.cn" target="_blank">ĻƷþ</a>| <a href="http://www.engil.cn" target="_blank">þۺۺϾþúݺݺ97ɫ88 </a>| <a href="http://www.sosolishi.cn" target="_blank">þùƷ-þþƷ</a>| <a href="http://www.uubux.com.cn" target="_blank">ɫ͵͵þһ</a>| <a href="http://www.masterflexpump.com.cn" target="_blank">޹Ʒþþò</a>| <a href="http://www.cc5ujj.cn" target="_blank">þ99ֻƵƷ8</a>| <a href="http://www.sxysw.cn" target="_blank">˹ھƷþþþӰԺVR</a>| <a href="http://www.bqtao.cn" target="_blank">ձþþþþþþþ</a>| <a href="http://www.wangyanl3.com.cn" target="_blank">777ҹƷþav </a>| <a href="http://www.xuanhaoma.com.cn" target="_blank">ۺϾþü</a>| <a href="http://www.lenglie.cn" target="_blank">þ99žŹѿС˵</a>| <a href="http://www.ramar.com.cn" target="_blank">ҹþþþþ</a>| <a href="http://www.epcinet.cn" target="_blank">69Ʒþþþ99 </a>| <a href="http://www.vocard.cn" target="_blank">þþþһƷɫ</a>| <a href="http://www.80xz.cn" target="_blank">99þþù</a>| <a href="http://www.opsdc8.cn" target="_blank">þ99Ʒ鶹լլ</a>| <a href="http://www.jisuvpn.cn" target="_blank">Ʒþþþһ</a>| <a href="http://www.2268.net.cn" target="_blank">޾ƷҹVAþó</a>| <a href="http://www.2cafe.cn" target="_blank">ۺϳ˾þôƬ91</a>| <a href="http://www.webugame.cn" target="_blank">AVһȾþ</a>| <a href="http://www.rainbows.net.cn" target="_blank">Ʒþþþþþþþ</a>| <a href="http://www.ciidc.org.cn" target="_blank">þۺϾþ߾Ʒ</a>| <a href="http://www.joy7.com.cn" target="_blank">˾þô߽ۺվ</a>| <a href="http://www.yunfengxuandk.cn" target="_blank">ݺɫþۺ</a>| <a href="http://www.yoyopj.cn" target="_blank">ҹƷþþþþ99</a>| <a href="http://www.nanwx.cn" target="_blank">޹Ʒþþž</a>| <a href="http://www.htja.com.cn" target="_blank">˾þþþƷ</a>| <a href="http://www.s5273.cn" target="_blank">97þóƷɰ</a>| <a href="http://www.hcpyr.cn" target="_blank">ҹavþþþ</a>| <a href="http://www.taskbee.cn" target="_blank">Ұ¾þһ</a>| <a href="http://www.axtea2007.cn" target="_blank">žȾþƵ</a>| <a href="http://www.ouhly.cn" target="_blank">91þþƷ91ɫҲ</a>| <a href="http://www.05958.cn" target="_blank">þùĻ</a>| <a href="http://www.xiangzen.cn" target="_blank">Ʒþþþþþ</a>| <a href="http://www.ruimen.com.cn" target="_blank">պƷþþþþ</a>| <a href="http://www.mingxiao123.cn" target="_blank">þþþþþƵ</a>| <a href="http://www.cd919.cn" target="_blank">һaɫƬþ</a>| <a href="http://www.vhxz.cn" target="_blank">պľþ</a>| <a href="http://www.aqbfrmi.cn" target="_blank">ƷŮٸAVѾþ </a>| <a href="http://www.mllp.net.cn" target="_blank">޹徫Ʒ߾þ</a>| <a href="http://www.wenmeiclass.cn" target="_blank">þþþþþۺձ</a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>