logback學習速記

大部分內容均來自Logback官網

Logback

Logback是一種日志框架,它是由log4j和SLF4J日志框架的設計者設計,意在取代log4j。通常和SLF4J配合使用。

1 架構(Architecture)

Logback框架分為3個模塊,分別是logback-corelogback-classiclogback-access

  • 顧名思義,core模塊是其它兩個模塊的基礎。

  • classic模塊繼承自core模塊,它是對log4j的重大改進。Logback-classic原生實現了SLF4J的API,這樣就可以讓使用者在logback和其它日志系統之間自由切換,比如log4j或者java.util.logging(JUL)。

  • access模塊集成了Servlet容器,提供了基于HTTP訪問的日志功能。

2 Logger,Appenders和Layouts

Logback框架主要基于3個類(接口):LoggerAppenderLayout

通過上述3種組件的聯合使用,可以幫助開發者針對不同的消息類型和等級記錄日志,并控制應用運行時的日志格式和輸出位置。

Logger類是logback-classic模塊的一部分,而AppenderLayout接口是logback-core的一部分。Logger類沒有包含在logback-core中是考慮到模塊的通用性。

2.1 Logger上下文(Logger context)

相比于普通的System.out.println而言,任何一種日志API首要且最重要的優勢就在于選擇性輸出或打印特定的日志語句(log statements)。這種能力通常假設存在一個日志空間(logging space),該空間里包含了所有可能的日志語句,開發者能根據設定的某些準則將這些語句劃分為不同的類別。簡單地說,比如info、warn、error等。

注:不管是logback,還是slf4j,亦或是log4j中,對“記錄日志”這樣的行為都是基于一種模型假設:日志器(logger)負責記錄日志(log)。這有點類似于英文的work和worker的關系,其中work表示工作,worker表示工人。同樣的道理,log表示日志,logger表示記錄日志的主體——日志器(p.s. 譯得很low,但確實沒想到更好的譯名)

每個獨立的日志器(logger)都將綁定一個日志上下文LoggerContext,它負責產生日志器,并在一個類似層級結構的樹結構中安置日志器。

日志器(loggers)是命名的實體(named entities)。它們的名字是大小寫敏感,并遵循層級命名規則:

Named Hierarchy
A logger is said to be an ancestor of another logger if its name followed by a dot is a prefix of the descendant logger name. A logger is said to be a parent of a child logger if there are no ancestors between itself and the descendant logger.

熟悉Java包命名規則的一定會覺得上述規則很眼熟。是的,沒錯,該規則跟Java的包命名規則基本是相同的。例如,名為“com.codershangfeng”的日志器是名為“com.codershangfeng.backup”日志器的父一級日志器。

根日志器(root logger)位于所有日志器層級結構的頂部。任何一個日志器層級結構中都包含這樣一個根日志器。它也可以像獲取其他日志器一樣,通過它的名字來獲取,如下:

Logger rootLogger = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
所有日志器都包含5類打印方法,還有很多重載(overload)的方法未逐一列出(遠不止下面的5個)。

package org.slf4j; 
public interface Logger {

  // Printing methods: 
  public void trace(String message);
  public void debug(String message);
  public void info(String message); 
  public void warn(String message); 
  public void error(String message); 
}

開發者根據開發需要調用合適的方法打印輸出日志。

2.2 日志等級

從剛才的Logger接口中可以看到,每個日志器其實包含了5種日志輸出等級,即:TRACE(跟蹤)、DEBUG(調試)、INFO(信息)、WARN(警告)和ERROR(錯誤)。TRACE等級最低,ERROR等級最高。

例如,當指定日志器的輸出等級為TRACE時,那么,該日志器調用的trace()debug()info()warn()error()方法都將輸出日志。反之,若指定該日志器的輸出等級為ERROR,則僅輸出該日志器調用的error()方法的日志。

每個日志器都可以指定它的輸出等級,當未指定時,則選用它的非空父一級日志器的等級,若非空父一級日志器也未指定,則繼續上溯,最終可上溯至日志層級結構的頂級日志器——root,并采用root的輸出等級作為該日志器的輸出等級。

可以參考官方的解釋:

The effective level for a given logger L, is equal to the first non-null level in its hierarchy, starting at L itself and proceeding upwards in the hierarchy towards the root logger.

特別注意,這與實際使用日志器時,在方法里實際調用的Logger方法無關!也就是說,在方法里你仍然可以調用某個日志器實例的logger.×××()方法,但至于是否輸出打印,則取決于開發者對該Logger及其父一級,甚至根日志器的輸出等級配置。

再來幾個例子解釋下日志器的日志等級設置:

  • 例1
Logger name Assigned level Effective level
root DEBUG DEBUG
X none DEBUG
X.Y none DEBUG
X.Y.Z none DEBUG

例1中,只有root日志器(根日志器)設定了輸出等級——DEBUG,則該應用中所有繼承自根日志器(root)的日志器,如XX.YX.Y.Z都將繼承root日志器的DEBUG輸出等級。

  • 例2
Logger name Assigned level Effective level
root ERROR ERROR
X INFO INFO
X.Y DEBUG DEBUG
X.Y.Z WARN WARN

例2中,每個日志器都指定了輸出等級,不需要再使用繼承關系進行指定輸出等級。

  • 例3
Logger name Assigned level Effective level
root DEBUG DEBUG
X INFO INFO
X.Y none INFO
X.Y.Z none INFO

例3中,rootX分別指定DEBUG和INFO的輸出等級;X.YX.Y.Z繼承它最近的父一級的日志器X,故其輸出等級為INFO。

2.3 獲取日志器

例如:

Logger x = LoggerFactory.getLogger("wombat"); 
Logger y = LoggerFactory.getLogger("wombat");

日志器xy都指向名為wombat的相同日志器實例。

1.2.4 Appenders and Layouts

如果說,輸出等級表示的是選擇哪些日志進行輸出,那么,Layouts和Appenders則分別是選擇以哪些格式輸出日志,將日志輸出到哪些地方。

在logback的術語中,一個輸出目的地被稱為一個附加器(Appender)。目前,可供選擇的附加器包括控制臺(console),文件(files),遠程套接字服務器(remote socket server),MySQL、PostgreSQL和其它數據庫,Java消息服務(JMS),遠程UNIX系統日志守護線程(remote UNIX Syslog daemons)。

一個日志器可以綁定多個附加器(appender)。

類似日志器的輸出等級層級結構,附加器也存在類似的繼承關系,但是其決定關系剛好是逆向的,即“子-->父”:

Appender Additivity

The output of a log statement of logger L will go to all the appenders in L and its ancestors. This is the meaning of the term "appender additivity".

However, if an ancestor of logger L, say P, has the additivity flag set to false, then L's output will be directed to all the appenders in L and its ancestors up to and including P but not the appenders in any of the ancestors of P.

Loggers have their additivity flag set to true by default.

從上述定義可以得出三點結論:

(1)子一級日志器產生的日志將輸出至父一級的所有附加器中;

(2)若父一級日志器(假設為P)的additivity標識位設置為false,則子一級日志器(假設為L)的日志將輸出至L自己的附加器,P的附加器,但不包含P的父一級日志器的附加器;

(3)所有日志器的additivity標識位默認為ture(root除外)。

舉例:

Logger Name Attached Appenders Additivity Flag Output Targets Comment
root A1 not applicable A1 Since the root logger stands at the top of the logger hierarchy, the additivity flag does not apply to it.
x A-x1, A-x2 true A1, A-x1, A-x2 Appenders of "x" and of root.
x.y none true A1, A-x1, A-x2 Appenders of "x" and of root.
x.y.z A-xyz1 true A1, A-x1, A-x2, A-xyz1 Appenders of "x.y.z", "x" and of root.
security A-sec false A-sec No appender accumulation since the additivity flag is set to false. Only appender A-sec will be used.
security.access none true A-sec Only appenders of "security" because the additivity flag in "security" is set to false.

至于Layout,標準logback中發布PatternLayout可以幫助使用者利用類似C語言中printf函數的方法轉換日志的輸出格式。

例如,轉換格式"%-4relative [%thread] %-5level %logger{32} - %msg%n"將輸出類似如下:

176  [main] DEBUG manual.architecture.HelloWorld2 - Hello world.

2 配置

logback在查找配置文件遵循以下規則:

  1. Logback tries to find a file called logback-test.xml in the classpath.

  2. If no such file is found, logback tries to find a file called logback.groovy in the classpath.

  3. If no such file is found, it checks for the file logback.xml in the classpath.

  4. If no such file is found, service-provider loading facility ( introduced in JDK 1.6) is used to resolve the implementation of com.qos.logback.classic.spi.Configurator interface by looking up the META-INF\services\ch.qos.logback.classic.spi.Configurator in the class path. It contents should specify the fully qualified class name of the desired Configurator implementation.

  5. If none of the above succeeds, logback configures itself automatically using the BasicConfigurator which will cause logging output to be directed to the console.

其中,1-3都是通過文件直接進行配置;4-5是通過接口或類進行配置。

較為常見的是第3種,即通過logback.xmlXML文件進行配置。

如果使用Maven進行項目開發,可以將logback-test.xml放到src/test/resources文件夾下,這樣就可以在測試時使用logback-test.xml配置文件,而在產品中使用logback.xml配置文件。

不過,即使不配置,logback也能利用第5種方案進行默認配置(有興趣可參考鏈接)。

2.1 使用logback-test.xml或logback.xml自動配置

例1:基本配置

<configuration>

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <!-- encoders are assigned the type
         ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
  </appender>

  <root level="debug">
    <appender-ref ref="STDOUT" />
  </root>
</configuration>

例1中,“<”和“>”兩個尖括號表示XML文件結構中的一個元素或標簽;“<foo>”和“</foo>”表示元素“foo”的起始和結束位置;'appender'標簽表示日志最終輸出的目的地,類似通信模型中的“信宿”;encoder標簽就相當于上文提到的Layout(也可以用繼承接口或抽象類的方法實現更為復雜的格式邏輯,但通常來說用encoder的字符串格式符就足夠了),用于以C語言的printf函數形式設置每條日志語句的格式;'root'是根日志器的標簽;appender-ref表示該日志器所指向或掛靠的附加器。

例2:為日志器設置輸出等級

<configuration>

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <!-- encoders are assigned the type
         ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
  </appender>

  <logger name="chapters.configuration" level="INFO"/>

  <!-- Strictly speaking, the level attribute is not necessary since -->
  <!-- the level of the root level is set to DEBUG by default.       -->
  <root level="DEBUG">          
    <appender-ref ref="STDOUT" />
  </root>  
  
</configuration>

例2中,對名為“chapter.configuration”的日志器設置了INFO輸出等級,并按照logback框架日志器層級關系,“chapter.configuration”日志器也將使用root日志器的附加器,即“STDOUT”,這一點有別于log4j(沒用過,文檔里這么說的)。

例3:為多個日志器設置輸出等級

<configuration>

  <appender name="STDOUT"
    class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>
        %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
     </pattern>
    </encoder>
  </appender>

  <logger name="chapters.configuration" level="INFO" />
  <logger name="chapters.configuration.Foo" level="DEBUG" />

  <root level="DEBUG">
    <appender-ref ref="STDOUT" />
  </root>

</configuration>

例4: 多個附加器

<configuration>

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>myApp.log</file>

    <encoder>
      <pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
    </encoder>
  </appender>

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%msg%n</pattern>
    </encoder>
  </appender>

  <root level="debug">
    <appender-ref ref="FILE" />
    <appender-ref ref="STDOUT" />
  </root>
</configuration>

例5:附加器復用

<configuration>

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
  </appender>

  <logger name="chapters.configuration">
    <appender-ref ref="STDOUT" />
  </logger>

  <root level="debug">
    <appender-ref ref="STDOUT" />
  </root>
</configuration>

例6:多日志器,多附加器

<configuration>

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>myApp.log</file>
    <encoder>
      <pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
    </encoder>
  </appender>

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%msg%n</pattern>
    </encoder>
  </appender>

  <logger name="chapters.configuration">
    <appender-ref ref="FILE" />
  </logger>

  <root level="debug">
    <appender-ref ref="STDOUT" />
  </root>
</configuration>

例7:定義變量

<configuration>

  <property name="USER_HOME" value="/home/sebastien" />

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>${USER_HOME}/myApp.log</file>
    <encoder>
      <pattern>%msg%n</pattern>
    </encoder>
  </appender>

  <root level="debug">
    <appender-ref ref="FILE" />
  </root>
</configuration>

還有關于Layout、Filter、JMX Configuration、Using SSL等內容暫不記錄。

所有代碼均來自logback官網文檔The logback manual

EOF

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,565評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,115評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,577評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,514評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,234評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,621評論 1 326
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,641評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,822評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,380評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,128評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,319評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,879評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,548評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,970評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,229評論 1 291
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,048評論 3 397
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,285評論 2 376

推薦閱讀更多精彩內容

  • 在應用程序中添加日志記錄總的來說基于三個目的:監視代碼中變量的變化情況,周期性的記錄到文件中供其他應用進行統計分析...
    時待吾閱讀 5,072評論 1 13
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,810評論 18 139
  • (http://www.cnblogs.com/zhangchenliang/p/4546352.html) 1、...
    凌雲木閱讀 2,447評論 0 2
  • 在應用程序中添加日志記錄總的來說基于三個目的:監視代碼中變量的變化情況,周期性的記錄到文件中供其他應用進行統計分析...
    時待吾閱讀 5,010評論 0 6
  • 9月28日咖啡冥想 1、早上八點多開始告別手機,到下午五點多,不去用手機聯網,回歸以前手機無網狀態,專注干該干的活...