不久前在系統(tǒng)中完成了監(jiān)控的功能,監(jiān)控系統(tǒng)的信息量很大,用戶對頁面的每一個點擊都會產生記錄,每天下來的日志量有2G多,我用log4j把這些監(jiān)控記錄
放在日志里,然后進行異步處理,但即使是這樣,記錄日志會對磁盤IO產生頻繁的訪問,而IO通常就是系統(tǒng)的瓶頸所在。于是對log4j配置進行一些調優(yōu)就
成了必要。下面是我系統(tǒng)中的log4j配置:
log4j.rootLogger=ERROR,fileout,stdout
log4j.logger.monitorLogger=INFO,monitorAppender
log4j.additivity.monitorLogger=false
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d (%F:%L) %-5p %c - %m%n
log4j.appender.fileout=org.apache.log4j.DailyRollingFileAppender
log4j.appender.fileout.File=logs/server_log.txt
log4j.appender.fileout.layout=org.apache.log4j.PatternLayout
log4j.appender.fileout.layout.ConversionPattern=%d [%t] (%F:%L) %-5p %c - %m%n
log4j.appender.monitorAppender=org.apache.log4j.DailyRollingFileAppender
log4j.appender.monitorAppender.File=mtlogs/mt_log.txt
log4j.appender.monitorAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.monitorAppender.layout.ConversionPattern=%m%n
log4j.appender.monitorAppender.DatePattern='.'yyyy-MM-dd-HH
log4j.appender.monitorAppender.BufferedIO=true
#Buffer單位為字節(jié),默認是8K
log4j.appender.monitorAppender.BufferSize=8192
1)
log4j.additivity.monitorLogger=false
這個選項用于控制監(jiān)控logger的日志不會輸出到rootlogger,否則無論會產生許多重復的數據,同時也會影響性能;
2)log4j.appender.monitorAppender.DatePattern='.'yyyy-MM-dd-HH
這個選項用于告訴DailyRollingFileAppender每小時輸出日志,而不是默認的一天輸出一次,因為監(jiān)控日志的數據量很巨大,如果以天為單位輸出,日志文件會很大(G級),而且再處理會很耗時。
其他一些輸出選項還有:
1)'.'yyyy-MM: 每月
2)'.'yyyy-ww: 每周
3)'.'yyyy-MM-dd: 每天
4)'.'yyyy-MM-dd-a: 每天兩次
5)'.'yyyy-MM-dd-HH: 每小時
6)'.'yyyy-MM-dd-HH-mm: 每分鐘
3)log4j.appender.monitorAppender.BufferedIO=true
log4j.appender.monitorAppender.BufferSize=8192
這
個選項用于告訴log4j輸出日志的時候采用緩沖的方式,而不是即時flush方式,并且設定了緩沖為8K,8K是默認值,可以根據日志輸出的情況來修
改。這個選項很重要,在測試中發(fā)現,當并發(fā)訪問很高,例如每一秒100個并發(fā)以上,使用緩存跟不使用緩沖差距很大。具體數字我這里就不列出來了。
另外我想說的是,log4j輸出緩沖日志是以8K為單位的,因為磁盤的一個block為8K,這樣可以減少碎片,也就是說假設你設置緩存為18K,log4j在16K(8K*2)的時候就會輸出),而不是18K。
4)組裝輸出內容之前可對logger的輸出級別先進行判斷而不要完全依賴log4j控制,因為組裝輸出日志內容也是要損耗效率的。
//若log4j并未開啟info級日志記錄,直接返回
if(!monitorLogger.isInfoEnabled()){
return;
}
StringBuilder log = new StringBuilder();
logSql.append(logPk+" ");
...
5)使用異步輸出 org.apache.log4j.AsyncAppender,異步輸出必須使用xml方式配置才能支持,我把上面properties形式的配置文件用xml表達一下:
<?xml version="1.0" encoding="UTF-8"?>
<log4j:configuration debug="true">
<appender name="stdout"
class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d (%F:%L) %-5p %c - %m%n" />
</layout>
</appender>
<appender name="fileout"
class="org.apache.log4j.DailyRollingFileAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d [%t] (%F:%L) %-5p %c - %m%n" />
</layout>
<param name="File"
value="logs/server_log.txt" />
</appender>
<appender name="monitorAppender"
class="org.apache.log4j.DailyRollingFileAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%m%n" />
</layout>
<param name="DatePattern" value="'.'yyyy-MM-dd-HH" />
<param name="File" value="mtlogs/mt_log.txt" />
<param name="BufferedIO" value="true" />
<!-- 8K為一個寫單元 -->
<param name="BufferSize" value="8192" />
</appender>
<appender name="async" class="org.apache.log4j.AsyncAppender">
<appender-ref ref="monitorAppender"/>
</appender>
<root>
<priority value="error" />
<appender-ref ref="stdout" />
<appender-ref ref="fileout" />
</root>
<category name="com.danga.MemCached">
<priority value="error" />
<appender-ref ref="fileout" />
</category >
<category name="com.opensymphony">
<priority value="error" />
<appender-ref ref="fileout" />
</category >
<category name="monitorLogger" additivity="false">
<priority value="info" />
<appender-ref ref="async" />
</category >
</log4j:configuration>
配置中紅色的部分就是用于支持異步輸出的,在用jmeter測試的過程中發(fā)覺使用異步方式,工作的不是很穩(wěn)定。性能的提升也不顯著。所以最后并沒有采用。
InputStream in=null;
try {
in = Log4jConfigLocator.class.getResourceAsStream(fileName);
if(fileName.endsWith(".xml")){
//載入XML格式的配置文件
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(in);
DOMConfigurator.configure(doc.getDocumentElement());
}else{
//載入properties格式的配置文件
Properties props = new Properties();
props.load(in);
PropertyConfigurator.configure(props);
}

