前言 前段時間,將團隊架構中的Struts2切換到SpringMVC,做一個系統系統,同時將一些共用組件抽取、獨立,團隊成員提議使用LogBack記錄日誌,因之前做的基礎組件使用的Log4j,對LogBack不太熟悉,所以自己學習了一下LogBack,學習過程中,發現心儀的中文資料比較少,結合自己開的項目,分享一下LogBack在項目中的應用及自己所遇到的問題。回過頭思考使用LogBack的過程,官方文檔還是最準確、最完成的學習資源,雖然是英文的,正好此時在翻譯一本英文書籍,能靜下心去看官方的文檔,解決了項目中遇到的一些問題。 項目中使用的LogBack的配置如下: 其檔案已經放到GitHub上,地址: https://github.com/wangdongsong/java/blob/master/src/main/java/com/wds/java/base/web/log/logback.xml
<?xml version="1.0" encoding="UTF-8"?><!-- 說明:1、記錄層級及檔案日誌記錄採用分級記錄,層級與記錄檔名相對應,不同層級的日誌資訊記錄到不同的記錄檔中例如:error層級記錄到log_error_xxx.log或log_error.log(該檔案為目前記錄的記錄檔),而log_error_xxx.log為歸檔日誌,記錄檔按日期記錄,同一天內,若記錄檔大小等於或大於2M,則按0、1、2...順序分別命名例如log-level-2013-12-21.0.log其它層級的日誌也是如此。2、檔案路徑若開發、測試用,在Eclipse中運行項目,則到Eclipse的安裝路徑尋找logs檔案夾,以相對路徑../logs。若部署到Tomcat下,則在Tomcat下的logs檔案中3、AppenderFILEERROR對應error層級,檔案名稱以log-error-xxx.log形式命名FILEWARN對應warn層級,檔案名稱以log-warn-xxx.log形式命名FILEINFO對應info層級,檔案名稱以log-info-xxx.log形式命名FILEDEBUG對應debug層級,檔案名稱以log-debug-xxx.log形式命名stdout將日誌資訊輸出到控制上,為方便開發測試使用 --><configuration><!-- 在Eclipse中運行,請到Eclipse的安裝目錄中找log檔案,Tomcat下,請到Tomcat目錄下找 --><property name="LOG_PATH" value="../logs" /><!-- 日誌記錄器,日期滾動記錄 --><appender name="FILEERROR" class="ch.qos.logback.core.rolling.RollingFileAppender"><!-- 正在記錄的記錄檔的路徑及檔案名稱 --><file>${LOG_PATH}/log_error.log</file><!-- 日誌記錄器的滾動策略,按日期,按大小記錄 --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 歸檔的記錄檔的路徑,例如今天是2013-12-21日誌,當前寫的記錄檔路徑為file節點指定,可以將此檔案與file指定檔案路徑設定為不同路徑,從而將當前記錄檔或歸檔記錄檔置不同的目錄。 而2013-12-21的記錄檔在由fileNamePattern指定。%d{yyyy-MM-dd}指定日期格式,%i指定索引 --> <fileNamePattern>${LOG_PATH}/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <!-- 除按日誌記錄之外,還配置了記錄檔不能超過2M,若超過2M,記錄檔會以索引0開始, 命名記錄檔,例如log-error-2013-12-21.0.log --> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>2MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> <!-- 追加方式記錄日誌 --><append>true</append><!-- 記錄檔的格式 --><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>%-5p [%d] %C:%L - %m %n</pattern><charset>utf-8</charset></encoder><!-- 此記錄檔只記錄error層級的 --><filter class="ch.qos.logback.classic.filter.LevelFilter"><level>error</level><onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch></filter></appender><appender name="FILEWARN" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>${LOG_PATH}/log_warn.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${LOG_PATH}/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>2MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy><append>true</append><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>%-5p [%d] %C:%L - %m %n</pattern><charset>utf-8</charset></encoder><!-- 此記錄檔只記錄warn層級,不記錄大於warn層級的日誌 --><filter class="ch.qos.logback.classic.filter.LevelFilter"><level>WARN</level><onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch></filter></appender><appender name="FILEINFO" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>${LOG_PATH}/log_info.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${LOG_PATH}/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>2MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy><append>true</append><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>%-5p [%d] %C:%L - %m %n</pattern><charset>utf-8</charset></encoder><!-- 此記錄檔只記錄info層級,不記錄大於info層級的日誌 --><filter class="ch.qos.logback.classic.filter.LevelFilter"><level>INFO</level><onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch></filter></appender><appender name="FILEDEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>${LOG_PATH}/log_debug.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${LOG_PATH}/log-debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>2MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy><append>true</append><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>%-5p [%d] %C:%L - %m %n</pattern><charset>utf-8</charset></encoder><!-- 此記錄檔只記錄debug層級,不記錄大於debug層級的日誌 --><filter class="ch.qos.logback.classic.filter.LevelFilter"><level>DEBUG</level><onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch></filter></appender><appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"><Target>System.out</Target><encoder><pattern>%-5p [%d] %C:%L - %m %n</pattern><charset>utf-8</charset></encoder><!-- 此日誌appender是為開發使用,只配置最底層級,控制台輸出的記錄層級是大於或等於此層級的日誌資訊--><filter class="ch.qos.logback.classic.filter.ThresholdFilter"><level>DEBUG</level></filter></appender><!-- 為單獨的包配置記錄層級,若root的層級大於此層級, 此處層級也會輸出應用情境:生產環境一般不會將記錄層級設定為trace或debug,但是為詳細的記錄SQL語句的情況,可將hibernate的層級設定為debug,如此一來,記錄檔中就會出現hibernate的debug層級日誌,而其它包則會按root的層級輸出日誌--><logger name="org.hibernate.SQL" level="DEBUG" /><logger name="org.hibernate.jdbc" level="DEBUG"/><logger name="org.springframework" level="DEBUG"/><!-- 生產環境,將此層級配置為適合的層級,以名記錄檔太多或影響程式效能 --><root level="INFO"><appender-ref ref="FILEDEBUG" /><appender-ref ref="FILEINFO" /><appender-ref ref="FILEWARN" /><appender-ref ref="FILEERROR" /><!-- 生產環境將請stdout去掉 --><appender-ref ref="stdout" /></root></configuration>
LogBack
LogBack是由log4j的創始人開發的一個日誌組件,用於替代log4j。LogBack的架構設計足夠通用,可適用於不同的環境,目前LogBack分為三個模:lobback-core,logback-classic和logback-access。
core模組是其它兩個模組的基礎,classic是core的擴充,是log4j巨大改進的版本。LogBack-classic本身實現了SL4J的API,因此可以很容易的在logback與其它日誌系統之間轉換,例如log4j、JDK1.4中的java.util.logging(JUL)。第三個模組access,它整合了Servlet容器,提供了通過HTTP訪問日誌的功能,若瞭解access可訪問其獨立文檔http://logback.qos.ch/access.html。
LogBack的記錄層級有trace、debug、info、warn、error,關於基層級,可參考官方文檔(http://logback.qos.ch/manual/architecture.html)。 配置 LogBack可以通過編程式或以XML、Groovy格式配置,原來使用log4j的使用者可以通過 屬性轉換器將log4j.properties轉換成logback.xml檔案。我在使用這個轉換器的時候,能轉換成功,但是在Web-App中日誌輸出的有點小問題,後來就自己寫logback.xml檔案,LogBack讀取配置或屬性檔案的步驟: LogBack在類路徑下嘗試尋找logback.groovy的檔案。 如果logback.groovy沒有找到,就在類路徑下尋找logback-test.xml檔案。 若logback-test.xml檔案沒有找到,就會在類路徑下尋找logback.xml檔案(自己使用的就是這種方式,將logback.xml設定檔放到類路徑下)。 如果都找不到,LogBack就會使用BasicConfigurator啟動預設配置,該配置會將日誌輸出到控制上。 第4步,意味著使用預設配置,它提供了預設(最基礎)的日誌功能。 如果使用Maven,可以將logback-test.xml的設定檔置於src/test/resources檔案夾下,因此,可以在測試時使用logback-test.xml配置,而在產品中使用logback.xml,這一點,我也木用使用到。我的用法是Web-App中,將logback.xml檔案放到了src/main/resources路徑下,而在Java-App中,將檔案放到src/main/java下,如下圖:
Web-App的目錄結構圖:
Java工程的目錄結構圖:
Appender LogBack的日誌Appender都必須實現 ch.qos.logback.core.Appender介面,常用的有ConsoleAppender、FileAppender和RollingFileAppender,類圖如下:
項目中使用的Appender有兩種:ConsoleAppender和RollingFileAppender ConsoleAppender:主要是將日誌資訊輸出到控制上,在上面的記錄檔中,stdout的Append就是ConsoleAppender RollingFileAppender:是按日期滾動記錄日誌,例如RollingFileAppender將日誌記錄到log.txt檔案中,一旦設定的條件滿足,就將日誌資訊記錄到另一個檔案中,它繼承FileAppender。與RollingFileAppender互動的兩個重要組件分別是:RollingPolicy和TriggeringPolicy。前者負責滾動神馬,後者負責神馬時候滾動。 任何時候使用,RollingFileAppender都必須有RollingFileAppender和TriggeringPolicy的配置,但是如果它的RollingPolicy也實現了TriggeringPolicy介面,只需要指定前者即可。此點需要注意:筆者在使用時,就忽略這一點,導致日誌滾動不成功。其具體屬性如下:(以項目中使用到的為例 ) file:繼承自FileAppender,指定記錄檔名。 append:繼承自FileAppender,為true,日誌將追加到記錄檔的尾部,false將刪除已經存在的記錄檔,預設為true。 encoder:Encoder,指定日誌格式及編碼 RollingPolicy TimeBaseRollingPolicy可能是最常用的滾動策略了,它是基於時間的,例如可以以天或月為周期,同時,這個類同時實現了RollingPolicy介面和TriggeringPolicy介面。在RollingFileAppender中只使用這個類就可以了,項目中就是使用的這個RollingPolicy,日期格式由%d{yyyy-MM-dd}指定,%i是索引。具體配置可參考上述的設定檔。RollingPolicy還有一此其它屬性,具體可參考官方文檔,項目中未使用到,例如最大歷史期限等。 LogBack也提供了FixedWindowRollingPolicy,該類未使用,可參考官方檔案。 此外,我們還可以根據時間和大小來決定滾動策略,在項目中使用的就是這種類型,項目中使用設定檔可見上述,下面為官方提供的設定檔:
<configuration> <appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>mylog.txt</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- rollover daily --> <fileNamePattern>mylog-%d{yyyy-MM-dd}.%i.txt</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <!-- or whenever the file size reaches 100MB --> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> <encoder> <pattern>%msg%n</pattern> </encoder> </appender> <root level="DEBUG"> <appender-ref ref="ROLLING" /> </root></configuration>
TriggeringPolicy SizeBasedTriggeringPolicy:控制當前檔案大小,如果記錄檔大於指定的大小,則觸發滾動,由maxFileSize屬性指定,該值可以取KB、MB、及GB,如下下面的設定檔(官方提供的,未在項目中使用):
<configuration> <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>test.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> <fileNamePattern>test.%i.log.zip</fileNamePattern> <minIndex>1</minIndex> <maxIndex>3</maxIndex> </rollingPolicy> <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> <maxFileSize>5MB</maxFileSize> </triggeringPolicy> <encoder> <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern> </encoder> </appender> <root level="DEBUG"> <appender-ref ref="FILE" /> </root></configuration>
Filter 項目中使用到了LevelFilter和ThresholdFilter兩種,官方還提供了其它的Filter可參考。
LevelFilter:基於精確匹配,如果事件的層級與配置的層級相同,則將會根據已經配置的onMatch和onMismatch的屬性決定接受或拒絕,如果項目中的使用的設定檔中的FILEERROR、FILEWARN、FILEINFO、FILEDEBUG,下面的配置是官方提供的配置:
<configuration> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>INFO</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <encoder> <pattern> %-4relative [%thread] %-5level %logger{30} - %msg%n </pattern> </encoder> </appender> <root level="DEBUG"> <appender-ref ref="CONSOLE" /> </root></configuration>
ThresholdFilter:指定下限層級,低於此層級的事件將被拒絕,如果項目中使用的設定檔中的stdout的配置,下面為官方提供的配置:
<configuration> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <!-- deny all events with a level below INFO, that is TRACE and DEBUG --> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>INFO</level> </filter> <encoder> <pattern> %-4relative [%thread] %-5level %logger{30} - %msg%n </pattern> </encoder> </appender> <root level="DEBUG"> <appender-ref ref="CONSOLE" /> </root></configuration>
官方提供了其它的Filter,也可以自己實現自己的Filter,具體參考官方文檔。
問題 1、路徑 這個問題在設定檔中做了詳細的注釋,請參考。 2、關於Spring或其它已經使用了log4j、common-logging或java.util.longging的整合 LogBack提供了jcl-over-slf4j和jul-to-slf4j,jcl是指common-logging,jul指java.utils.longging,如果需要將Spring的日誌統一處理,就需要將jcl-over-slf4j的包加入到工作中,項目中使用Maven開發,依賴如下:
<dependency><groupId>ch.qos.logback</groupId><artifactId>logback-core</artifactId><version>1.0.13</version></dependency><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.0.13</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>jcl-over-slf4j</artifactId><version>1.7.0</version></dependency><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-access</artifactId><version>1.0.13</version></dependency>
3、代碼區別 源寫法:
if (logger.isInfoEnabled()) {logger.info("***** BaseAuthoritiesResourcesServiceImpl.getList() method begin*****");}
使用LogBack之後,可將if判斷去掉,如下:
logger.debug("***** BaseDictionaryServiceImpl.delete() method begin*****");
如果 記錄層級高於Debug,則這一行日誌資訊將不會輸出。