大多數講log4j配置的教程用的都是log4j.properties文件,我覺得xml或許更好一點,在這里我提供一個我已經用於生產環境的log4j.xml的例子,先上代碼,然后再解釋:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE log4j:configuration PUBLIC "-//log4j/log4j Configuration//EN" "log4j.dtd"> <log4j:configuration> <!--輸出到控制台--> <appender name="consoleAppender" class="org.apache.log4j.ConsoleAppender"> <param name="Threshold" value="DEBUG"/> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/> </layout> </appender> <!--輸出到文件(info)--> <!--將生成“info.log.2014-06-11”這樣的日志文件--> <appender name="fileAppenderInfo" class="org.apache.log4j.DailyRollingFileAppender"> <param name="File" value="${user.home}/logs/website/info.log" /> <param name="DatePattern" value=".yyyy-MM-dd" /> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/> </layout> <filter class="org.apache.log4j.varia.LevelRangeFilter"> <param name="LevelMin" value="INFO" /> <param name="LevelMax" value="INFO" /> </filter> </appender> <!--輸出到文件(warn)--> <appender name="fileAppenderWarn" class="org.apache.log4j.DailyRollingFileAppender"> <param name="File" value="${user.home}/logs/website/warn.log" /> <param name="DatePattern" value=".yyyy-MM-dd" /> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/> </layout> <filter class="org.apache.log4j.varia.LevelRangeFilter"> <param name="LevelMin" value="WARN" /> <param name="LevelMax" value="WARN" /> </filter> </appender> <!--輸出到文件(error)--> <appender name="fileAppenderError" class="org.apache.log4j.DailyRollingFileAppender"> <param name="File" value="${user.home}/logs/website/error.log" /> <param name="DatePattern" value=".yyyy-MM-dd" /> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/> </layout> <filter class="org.apache.log4j.varia.LevelRangeFilter"> <param name="LevelMin" value="ERROR" /> <param name="LevelMax" value="ERROR" /> </filter> </appender> <!--屏蔽所有org.springframework.*輸出的Debug(及以下)信息--> <logger name="org.springframework"> <level value="INFO"></level> </logger> <root> <level value="ALL"/> <appender-ref ref="consoleAppender" /> <appender-ref ref="fileAppenderInfo" /> <appender-ref ref="fileAppenderWarn" /> <appender-ref ref="fileAppenderError" /> </root> </log4j:configuration>
log4j簡單地說,由3個東西組成:
- 一個叫“logger”,是我們的程序直接使用的東西,log4j高明之處就在於它的logger可以有繼承關系,下面我會稍微用到一點這個功能;
- 一個叫“appender”,負責管日志到底輸出到哪里去,目前對我們而言輸出日志最多的兩個地方,一是控制台,另一當然是文件;
- 一個叫“layout”,也就是日志輸出的格式定義。
你可以定義一個layout,給一些appender使用,再定義幾個logger,使用不同的appender,總之很靈活,而我用的功能則很簡單:
- 對於info、warning和error這幾種錯誤,都需要輸出到文件去,而且是不同的文件
- 自動按天新建文件,避免單個日志文件過大
- debug信息不需要輸出到文件,只需要在控制台中顯示
- spring框架輸出的debug信息太多,要屏蔽
我針對info,warning,error定義了3個appender,這3個appender的類型都是“DailyRollingFileAppender”,是log4j直接提供的,能夠按天新建日志文件,這些日志文件的存放位置在用戶的home目錄的log/website子目錄下,為什么不存在程序當前的目錄?因為程序我經常要更新,一不小心就把log目錄刪掉了,當然你也可以存到別的地方去,比如上級目錄,前提是要有寫入權限。另外還有一個appender是用於輸出到控制台的,類型是“ConsoleAppender”,此類型也是log4j提供的。一共4個appender。
我的layout使用了“PatternLayout”,也是log4j提供的,這種layout可以自己定義一個輸出模板,我的輸出模板是“[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n”,會生成這樣的輸出格式:
[15:22:15:131] [DEBUG] - com.ignet.website.ui.controller.HomeController.exceptionTest(HomeController.java:19) - test output format [15:22:15:140] [ERROR] - com.ignet.website.ui.resolver.SimpleLoggingExceptionResolver.resolveException(SimpleLoggingExceptionResolver.java:26) - 未考慮到的異常發生,請注意排查
對一般的項目來說,足夠了。需要更豐富的信息的話就自己寫在日志內容里吧。
而對於logger,我只定義了兩個,一個是root,這個是所有logger的“祖先”,這個logger包含了前面定義的4個appender,這意味則什么呢?意味着所有的日志,都會嘗試調用這4個appender去記錄。那問題來了,假如我一個要log一個warning信息,那么豈不是3個日志文件中都有這個信息?——放心,仔細看,我在appender中設置了過濾,看一看你就明白了。
一切安好,除了運行時候發覺spring框架輸出的廢話實在太多,那些debug信息對我們來說沒什么用,我們又不打算修改spring的代碼,於是我定義了另一個logger,名字叫“org.springframework”,所有“org.springframework”命名空間下的類,都會使用這個logger,我給這個logger設置了一個level,為info,debug比info低,所以從此以后spring的那些debug信息就不來煩我了。“org.springframework”這個logger是root logger的孩子,所以理所當然地“繼承了”4個appender,不需要再寫了吧?
這里稍微提一下,為啥spring框架這么聰明,會自動使用我們另外加上去的log4j?其實spring是用了一個叫“commons-logging”的庫,這玩意兒能自動檢測各大logging framework並使用,很牛逼就是。
最后生成的日志文件大致是這樣的,大家感受下:
error.log error.log.2014-08-13 info.log.2014-07-23 info.log.2014-08-04 info.log.2014-08-14 error.log.2014-07-11 info.log info.log.2014-07-24 info.log.2014-08-05 info.log.2014-08-15 error.log.2014-07-18 info.log.2014-07-11 info.log.2014-07-25 info.log.2014-08-06 info.log.2014-08-19 error.log.2014-07-22 info.log.2014-07-17 info.log.2014-07-28 info.log.2014-08-07 info.log.2014-08-20 error.log.2014-08-04 info.log.2014-07-18 info.log.2014-07-29 info.log.2014-08-08 info.log.2014-08-21 error.log.2014-08-05 info.log.2014-07-19 info.log.2014-07-30 info.log.2014-08-09 info.log.2014-08-22 error.log.2014-08-07 info.log.2014-07-21 info.log.2014-07-31 info.log.2014-08-11 warn.log error.log.2014-08-11 info.log.2014-07-22 info.log.2014-08-01 info.log.2014-08-13 warn.log.2014-07-11
日積月累,日志文件越來越多,咋辦?教大家個秘籍,在這個日志目錄的上兩層目錄寫個腳本:
find ./logs/website -ctime +10 -exec rm {} \;
執行這個腳本,就能刪除掉10天以前的過期日志。