非常詳細的logback學習筆記
Logback介紹
Logback 分為三個模組:Core、Classic 和 Access。Core模組是其他兩個模組的基礎。 Classic模組擴充套件了core模組。 Classic模組相當於log4j的顯著改進版。Logback-classic 直接實現了 SLF4J API。
要引入logback,由於Logback-classic依賴slf4j-api.jar和logback-core.jar,所以要把slf4j-api.jar、logback-core.jar、logback-classic.jar,新增到要引入Logbac日誌管理的專案的class path中.
Logback
Logger、Appender和 Layout
Logback建立於三個主要類之上:Logger、Appender 和 Layout。Logger類是logback-classic模組的一部分,而Appender和Layout介面來自logback-core。作為一個多用途模組,logback-core 不包含任何logger。
Logger作為日誌的記錄器,把它關聯到應用的對應的context上後,主要用於存放日誌物件,也可以定義日誌型別、級別。Appender主要用於指定日誌輸出的目的地,目的地可以是控制檯、檔案、遠端套接字伺服器、MySQL、 PostreSQL、 Oracle
各個logger 都被關聯到一個 LoggerContext,LoggerContext負責製造logger,也負責以樹結構排列各logger。
如果 logger的名稱帶上一個點號後是另外一個 logger的名稱的字首,那麼,前者就被稱為後者的祖先。如果logger與其後代 logger之間沒有其他祖先,那麼,前者就被稱為子logger 之父。比如,名為"com.foo""的 logger 是名為"com.foo.Bar"之父。root logger 位於
其他所有logger也通過org.slf4j.LoggerFactory 類的靜態方法getLogger取得。 getLogger方法以logger 名稱為引數。用同一名字呼叫LoggerFactory.getLogger 方法所得到的永遠都是同一個logger物件的引用。
有效級別與級別繼承
Logger 可以被分配級別。級別包括:TRACE、DEBUG、INFO、WARN 和 ERROR,定義於ch.qos.logback.classic.Level類。如果 logger沒有被分配級別,那麼它將從有被分配級別的最近的祖先那裡繼承級別。root logger 預設級別是 DEBUG。
列印方法與基本選擇規則
列印方法決定記錄請求的級別。例如,如果 L 是一個 logger 例項,那麼,語句 L.info("..")是一條級別為 INFO 的記錄語句。記錄請求的級別在高於或等於其 logger 的有效級別時被稱為被啟用,否則,稱為被禁用。
記錄請求級別為 p,其 logger的有效級別為 q,只有則當 p>=q時,該請求才會被執行。
該規則是 logback 的核心。級別排序為: TRACE < DEBUG < INFO <WARN < ERROR。
Logger、Appenders及layouts的關係
一個 logger 可以被關聯多個 appender。方法 addAppender() 為指定的 logger 新增一個appender。對於 logger 的每個啟用了的記錄請求,都將被髮送到 logger 裡的全部 appender 及更高等級的 appender。換句話說,appender疊加性地繼承了 logger 的層次等級。
Logger L的記錄語句的輸出會發送給 L及其祖先的全部 appender。如果 logger L的某個祖先 P設定疊加性標識為 false,那麼,L的輸出會發送給L 與 P之間(含P)的所有 appender,但不會發送給P的任何祖先的appender。
Logger 的疊加性預設為 true。如果希望定製輸出格式。這時為 appender 關聯一個 layout 即可。Layout負責根據使用者意願對記錄請求進行格式化,appender 負責將格式化化後的輸出傳送到目的地。
例如,轉換模式"%-4relative[%thread] %-5level %logger{32} - %msg%n"在 PatternLayout裡會輸出形如:
176 [main] DEBUGmanual.architecture.HelloWorld2 - Hello world.
第一個欄位是自程式啟動以來的逝去時間,單位是毫秒。
第二個地段發出記錄請求的執行緒。
第三個欄位是記錄請求的級別。
第四個欄位是與記錄請求關聯的 logger 的名稱。
"-"之後是請求的訊息文字。
Logback的預設配置
如果配置檔案 logback-test.xml 和 logback.xml 都不存在,那麼 logback 預設地會呼叫BasicConfigurator ,建立一個最小化配置。最小化配置由一個關聯到根 logger 的ConsoleAppender組成。輸出用模式為%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 的PatternLayoutEncoder 進行格式化。rootlogger 預設級別是 DEBUG。
logback配置檔案
Logback 配置檔案的語法非常靈活。正因為靈活,所以無法用 DTD 或 XML schema 進行定義。儘管如此,可以這樣描述配置檔案的基本結構:以<configuration>開頭,後面有零個或多個<appender>元素,有零個或多個<logger>元素,有最多一個<root>元素。
Logback預設配置的採用的步驟
1. 嘗試在 classpath 下查詢檔案 logback-test.xml;
2. 如果檔案不存在,則查詢檔案 logback.xml;
3. 如果兩個檔案都不存在,logback 用 Bas icConfigurator 自動對自己進行配置,這會導致記錄輸出到控制檯。
假設配置檔案 logback-test.xml 和 logback.xml 都不存在,那麼 logback 預設地會呼叫BasicConfigurator ,建立一個最小化配置。最小化配置由一個關聯到根 logger 的ConsoleAppender組成。輸出用模式為%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 的PatternLayoutEncoder 進行格式化。還有,根 logger 預設級別是 DEBUG。
最簡單的配置方法就是使用預設配置。以下是logback用BasicConfigurator 配置的簡單例子:
package com.ttpod.chapters.configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
publicclass MyApp1 {
finalstatic Logger logger = LoggerFactory.getLogger(MyApp1.class);
publicstaticvoid main(String[] args) {
logger.info("Entering application."); //進行另一個application中
Foo foo = new Foo();
foo.doIt(); //執行其它中的日誌輸出方法
logger.info("Exiting application."); //退出另一個application
}
}
該類定義了一個靜態變數 logger,然後例項化一個 Foo 物件。Foo 類如下
package com.ttpod.chapters.configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
publicclass Foo {
staticfinal Logger logger = LoggerFactory.getLogger(Foo.class);
publicvoid doIt() {
logger.debug("Did it again!"); //定義一個debug級別的日誌輸出
}
…………
}
自動列印警告和錯誤訊息
當解析配置檔案有警告或出錯時,logback 會在控制檯上自動列印狀態資料。如果沒有警告或錯誤,還是想檢查logback 的內部狀態的話,可以呼叫 StatusPrinter 的 print()方法。示例如下:
finalstatic Logger logger = LoggerFactory.getLogger(MyApp2.class);
publicstaticvoid main(String[] args) {
// 在當前環境中假設 SLF4J 已經被繫結到logback
LoggerContextlc = (LoggerContext) LoggerFactory.getILoggerFactory();
// 列印logback的內部狀態
StatusPrinter.print(lc);
…………
}
}
對應的配置檔案:
<?xmlversion="1.0"encoding="UTF-8"?>
<configuration>
<!--定義一個名為STDOUT的appender,並將其關聯到ch.qos.logback.core.ConsoleAppender-->
<appendername="STDOUT"
class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders 作用是將logger事件轉換成位元組陣列,並將位元組陣列寫入到輸出流-->
<encoder>
<!--格式化輸出:%d表示日期,%thread表示執行緒名,%-5level:級別從左顯示5個字元寬度
%msg:日誌訊息,%n是換行符-->
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<rootlevel="debug"> <!-- root logger,定義級別為debug-->
<appender-refref="STDOUT"/> <!--將名為STDOUT的appender新增到root logger下-->
</root>
</configuration>
控制檯輸出結果如下:
…………
20:12:33,359|-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT findresource [logback.groovy]
20:12:33,359|-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT findresource [logback-test.xml]
20:12:33,359|-INFO in ch.qos.logback.classic.LoggerContext[default] - Found resource[logback.xml] at[file:/D:/Workspaces/MyEclipse%208.5/logback_test/WebRoot/WEB-INF/classes/logback.xml]
20:12:33,484|-INFO in ch.qos.logback.core.joran.action.AppenderAction - About toinstantiate appender of type [ch.qos.logback.core.ConsoleAppender]
20:12:33,484|-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as[STDOUT]
20:12:33,500|-INFO in ch.qos.logback.core.joran.action.NestedComplexPropertyIA - Assumingdefault type [ch.qos.logback.classic.encoder.PatternLayoutEncoder] for[encoder] property
20:12:33,593|-INFO in ch.qos.logback.classic.joran.action.RootLoggerAction - Setting levelof ROOT logger to DEBUG
20:12:33,593|-INFO in ch.qos.logback.core.joran.action.AppenderRefAction - Attachingappender named [STDOUT] to Logger[ROOT]
20:12:33,593|-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - End ofconfiguration.
20:12:33,593|-INFO in [email protected] - Registeringcurrent configuration as safe fallback point
…………
Logback自定義配置
配置root logger
<root>元素配置根 logger。該元素有一個 level屬性。沒有 name 屬性,因為已經被命名為"ROOT"。Level 屬性的值大小寫無關,其值為下面其中一個字串:TRACE、DEBUG、INFO、WARN、ERROR、ALL和OFF。注意不能設定為"INHERITED" 或"NULL"。 <logger>元素可以包含零個或多個<appender-ref>元素。與<logger>元素類似,宣告<root>元素後,會先關閉然後移除全部當前 appender,只引用聲明瞭的appender。如果 root 元素沒有引用任何 appender,就會失去所有 appender。
假設我們不想看到"com.ttpod.file"包裡的任何元件的任何 DEBUG 資訊,可以設定如下:
<?xmlversion="1.0"encoding="UTF-8"?>
<configuration>
<appendername="STDOUT"class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>
%d{HH:mm:ss.SSS}[%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<!-- 設定configuration下的logger的級別為INFO,預設是繼承root logger的debug級別 -->
<loggername="chapters.configuration"level="INFO"/>
<!-- 嚴格來說, root logger 的level屬性沒有必要設定,因為 -->
<!-- root logger的級別被預設設定為DEBUG -->
<rootlevel="DEBUG">
<!--
在root標籤內沒有引入chapters.configuration,所有在此包下不會
顯示任何元件的任何 DEBUG 資訊
-->
<appender-refref="STDOUT"/> <!-- 將appender引入到root logger-->
</root>
</configuration>
注意:由名為"chapters.configuration.Foo"的 logger 生成的 DEBUG 級別的資訊都被遮蔽了.同樣,也可以為任意數量的 logger 設定級別。
配置 Appenders
Appender 用<appender>元素配置,該元素必要屬性 name 和 class。 name 屬性指定 appender 的名稱,class 屬性指定 appender 類的全限定名。 <appender>元素可以包含零個或多個<layout>元素、零個或多個<encoder>元素和零個或多個<filter>元素。除了這三個常用元素之外,還可以包含 appender 類的任意數量的 javabean
屬性。下圖演示了常用結構,注意對 javabean 屬性的支援在圖中不可見。
記錄輸出到多個 appender 很簡單,先定義各種 appender,然後在 logger 裡進行引用,就行了。如下面的配置檔案所示:
<configuration>
<appendername="FILE"class="ch.qos.logback.core.FileAppender">
<file>myApp.log</file>
<!-- encodersare assigned by default the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder-->
<encoder>
<pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
</encoder>
</appender>
<appendername="STDOUT"class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%msg%n</pattern>
</encoder>
</appender>
<rootlevel="debug">
<appender-refref="FILE"/>
<appender-refref="STDOUT"/>
</root>
</configuration>
該配置檔案定義了兩個 appender,分別是"FILE"和"STDOUT"。"FILE"這個 appender 把記錄輸出到檔案"myapp.log ",它的 encoder 是PatternLayoutEncoder,輸出了日期、級別、執行緒名、logger 名、檔名及記錄請求的行號、訊息和行分隔符。"STDOUT"這個 appender 把記錄輸出到控制檯,它的 encoder 只是輸出訊息和行分隔符。 myApp.log檔案內容如下:
2011-12-2516:56:48,593 INFO [main] c.t.c.c.MyApp3 [MyApp3.java:48] Entering application.
2011-12-2516:56:48,593 DEBUG [main] c.t.c.c.Foo [Foo.java:24] Did it again!
2011-12-2516:56:48,593 INFO [main] c.t.c.c.MyApp3 [MyApp3.java:52] Exiting application.
注意每個 appender 都有自己的 encoder。Encoder 通常不能被多個 appender 共享,layout也是。所以,logback 的配置檔案裡沒有共享 encoder 或 layout 的語法。
Appender累積
預設情況下,appender 是可累積的:logger 會把記錄輸出到它自身的 appender 和它所有祖先的appender。因此,把同一 appender 關聯到多個 logger 會導致重複輸出,如下面的配置檔案會導致重複的輸出:
<configuration>
<appendername="STDOUT"
class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>
%d{HH:mm:ss.SSS}[%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<loggername="chapters.configuration">
<appender-refref="STDOUT"/>
</logger>
<rootlevel="debug">
<appender-refref="STDOUT"/> <!—這會導致重複輸出-->
</root>
</configuration>
輸出結果如下:
20:53:29.328[main] INFO c.t.chapters.configuration.MyApp2 - Entering application.
20:53:29.328[main] INFO c.t.chapters.configuration.MyApp2 - Entering application.
20:53:29.328[main] DEBUG com.ttpod.chapters.configuration.Foo - Did it again!
20:53:29.328[main] DEBUG com.ttpod.chapters.configuration.Foo - Did it again!
20:53:29.328[main] INFO c.t.chapters.configuration.MyApp2 - Exiting application.
20:53:29.328[main] INFO c.t.chapters.configuration.MyApp2 - Exiting application.
覆蓋預設的累積行為
如果你覺得預設的累積行為不合適,可以設定疊加性標識為 false 以關閉它。這樣的話,logger 樹裡的某個分支可以輸出到與其他 logger 不同的 appender。
示例:疊加性標識
<configuration>
…………
<loggername="com.ttpod.chapters.configuration.Foo"additivity="false">
<appender-refref="FILE"/>
</logger>
<rootlevel="debug">
<appender-refref="STDOUT"/>
</root>
</configuration>
輸出結果:
Enteringapplication.
Exitingapplication.
此例中,logger"chapters.configuration.Foo"關聯 appender"FILE",它的疊加性標記為false,這樣它的記錄輸出僅會被髮送到 appender"FILE",不會被髮送到更高 logger 等級關聯的 appender。其他logger 不受此影響。用 additivityFlag.xml 配置 MyApp3,執行後,控制檯上由輸出由"chapters.configuration.MyApp3"產生的記錄。而 logger"chapters.configuration.Foo"將且僅僅將輸出到檔案 foo.log。
Layout格式化輸出日誌
配置自定義 layout
MySampleLayout 的LayoutWrappingEncoder 例項傳遞給FileAppender。下面是配置檔案:
它和C語言的printf方法非常類似。格式轉換由普通字元和轉換字元組合而成。轉換字元由%開始,緊跟著的是可選的格式修飾符和轉換字元標示。使用%字首的表示符號將被轉換到實際的內容。如name, level, date, thread name.可用的轉換符有:
轉換符 |
描述 |
c |
呼叫日誌事件的所在記錄器的名字,如一個logger的名字是my.test.bbb.ccc,呼叫的是WARN級別的日誌輸出,那麼輸出的是輸出my.test.bbb.ccc,可以在其右邊指定了精度,如%c{2}那麼輸出的是bbb.ccc |
C |
呼叫日誌事件的所在的類名,和c轉換符一樣,可以在右邊指定寬度,如%C{2}輸出%C{2} |
d |
日誌呼叫所發生的時間,日期格式在其後跟著的大括號內的格式指定如%d{yyyy-MM-dd HH:mm:ss},我現在輸出的結果是2011-07-11 21:05:22,推薦使用的是log4j本身提供的日期格式,如%d{ISO8601},%d{ABSOLUTE},%d{DATE} |
F |
所處所在檔名,如上面說C轉換符的例子,輸出結果是LayoutTest.java |
l |
是的日誌事件發生的 |