本文轉自:https://segmentfault.com/a/1190000008315137html
簡單地說,Logback 是一個 Java 領域的日誌框架。它被認爲是 Log4J 的繼承人。
Logback 主要由三個模塊組成:java
logback-corenode
logback-classicexpress
logback-access編程
logback-core 是其它模塊的基礎設施,其它模塊基於它構建,顯然,logback-core 提供了一些關鍵的通用機制。logback-classic 的地位和做用等同於 Log4J,它也被認爲是 Log4J 的一個改進版,而且它實現了簡單日誌門面 SLF4J;而 logback-access 主要做爲一個與 Servlet 容器交互的模塊,好比說 tomcat 或者 jetty,提供一些與 HTTP 訪問相關的功能。segmentfault
目前 Logback 的使用很普遍,不少知名的開源軟件都使用了 Logback做爲日誌框架,好比說 Akka,Apache Camel 等。api
實際上,這兩個日誌框架都出自同一個開發者之手,Logback 相對於 Log4J 有更多的優勢tomcat
一樣的代碼路徑,Logback 執行更快網絡
更充分的測試app
原生實現了 SLF4J API(Log4J 還須要有一箇中間轉換層)
內容更豐富的文檔
支持 XML 或者 Groovy 方式配置
配置文件自動熱加載
從 IO 錯誤中優雅恢復
自動刪除日誌歸檔
自動壓縮日誌成爲歸檔文件
支持 Prudent 模式,使多個 JVM 進程能記錄同一個日誌文件
支持配置文件中加入條件判斷來適應不一樣的環境
更強大的過濾器
支持 SiftingAppender(可篩選 Appender)
異常棧信息帶有包信息
想在 Java 程序中使用 Logback,須要依賴三個 jar 包,分別是 slf4j-api,logback-core,logback-classic。其中 slf4j-api 並非 Logback 的一部分,是另一個項目,可是強烈建議將 slf4j 與 Logback 結合使用。要引用這些 jar 包,在 maven 項目中引入如下3個 dependencies
<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.5</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.0.11</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.0.11</version> </dependency>
package io.beansoft.logback.demo.universal; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * * * @author beanlam * @date 2017年2月9日 下午11:17:53 * @version 1.0 * */ public class SimpleDemo { private static final Logger logger = LoggerFactory.getLogger(SimpleDemo.class); public static void main(String[] args) { logger.info("Hello, this is a line of log message logged by Logback"); } }
以上代碼的運行結果是:
23:19:41.131 [main] INFO i.b.l.demo.universal.SimpleDemo - Hello, this is a line of log message logged by Logback
注意到這裏,代碼裏並無引用任何一個跟 Logback 相關的類,而是引用了 SLF4J 相關的類,這邊是使用 SLF4J 的好處,在須要將日誌框架切換爲其它日誌框架時,無需改動已有的代碼。
LoggerFactory
的 getLogger()
方法接收一個參數,以這個參數決定 logger 的名字,這裏傳入了 SimpleDemo
這個類的 Class 實例,那麼 logger 的名字即是 SimpleDemo
這個類的全限定類名:io.beansoft.logback.demo.universal.SimpleDemo
package io.beansoft.logback.demo.universal; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.core.util.StatusPrinter; /** * * * @author beanlam * @date 2017年2月9日 下午11:31:55 * @version 1.0 * */ public class LogInternalStateDemo { private static final Logger logger = LoggerFactory.getLogger(LogInternalStateDemo.class); public static void main(String[] args) { logger.info("Hello world"); //打印 Logback 內部狀態 LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); StatusPrinter.print(lc); } }
除了打印正常的日誌信息,還打印出了 Logback 自身的內部狀態信息
23:33:19.340 [main] INFO i.b.l.d.u.LogInternalStateDemo - Hello world 23:33:19,265 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback.groovy] 23:33:19,265 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback-test.xml] 23:33:19,265 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback.xml] 23:33:19,266 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Setting up default configuration.
在 logback 裏,最重要的三個類分別是
Logger
Appender
Layout
Logger 類位於 logback-classic 模塊中, 而 Appender 和 Layout 位於 logback-core 中,這意味着, Appender 和 Layout 並不關心 Logger 的存在,不依賴於 Logger,同時也能看出, Logger 會依賴於 Appender 和 Layout 的協助,日誌信息才能被正常打印出來。
爲了能夠控制哪些信息須要輸出,哪些信息不須要輸出,logback 中引進了一個 分層 概念。每一個 logger 都有一個 name,這個 name 的格式與 Java 語言中的包名格式相同。這也是前面的例子中直接把一個 class 對象傳進 LoggerFactory.getLogger() 方法做爲參數的緣由。
logger 的 name 格式決定了多個 logger 可以組成一個樹狀的結構,爲了維護這個分層的樹狀結構,每一個 logger 都被綁定到一個 logger 上下文中,這個上下文負責釐清各個 logger 之間的關係。
例如, 命名爲 io.beansoft
的 logger,是命名爲 io.beansoft.logback
的 logger 的父親,是命名爲 io.beansoft.logback.demo
的 logger 的祖先。
在 logger 上下文中,有一個 root logger,做爲全部 logger 的祖先,這是 logback 內部維護的一個 logger,並不是開發者自定義的 logger。
可經過如下方式得到這個 logger :
Logger rootLogger = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
一樣,經過 logger 的 name,就能得到對應的其它 logger 實例。
Logger
這個接口主要定義的方法有:
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); }
logger 有日誌打印級別,能夠爲一個 logger 指定它的日誌打印級別。
若是不爲一個 logger 指定打印級別,那麼它將繼承離他最近的一個有指定打印級別的祖先的打印級別。這裏有一個容易混淆想不清楚的地方,若是 logger 先找它的父親,而它的父親沒有指定打印級別,那麼它會當即忽略它的父親,往上繼續尋找它爺爺,直到它找到 root logger。所以,也能看出來,要使用 logback, 必須爲 root logger 指定日誌打印級別。
日誌打印級別從低級到高級排序的順序是:TRACE < DEBUG < INFO < WARN < ERROR
若是一個 logger 容許打印一條具備某個日誌級別的信息,那麼它也必須容許打印具備比這個日誌級別更高級別的信息,而不容許打印具備比這個日誌級別更低級別的信息。
舉個例子:
package io.beansoft.logback.demo.universal; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ch.qos.logback.classic.Level; /** * * * @author beanlam * @date 2017年2月10日 上午12:20:33 * @version 1.0 * */ public class LogLevelDemo { public static void main(String[] args) { //這裏強制類型轉換時爲了能設置 logger 的 Level ch.qos.logback.classic.Logger logger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger("com.foo"); logger.setLevel(Level.INFO); Logger barlogger = LoggerFactory.getLogger("com.foo.Bar"); // 這個語句能打印,由於 WARN > INFO logger.warn("can be printed because WARN > INFO"); // 這個語句不能打印,由於 DEBUG < INFO. logger.debug("can not be printed because DEBUG < INFO"); // barlogger 是 logger 的一個子 logger // 它繼承了 logger 的級別 INFO // 如下語句能打印,由於 INFO >= INFO barlogger.info("can be printed because INFO >= INFO"); // 如下語句不能打印,由於 DEBUG < INFO barlogger.debug("can not be printed because DEBUG < INFO"); } }
打印結果是:
00:27:19.251 [main] WARN com.foo - can be printed because WARN > INFO
00:27:19.255 [main] INFO com.foo.Bar - can be printed because INFO >= INFO
在 logback 中,每一個 logger 都是一個單例,調用 LoggerFactory.getLogger
方法時,若是傳入的 logger name 相同,獲取到的 logger 都是同一個實例。
在爲 logger 命名時,用類的全限定類名做爲 logger name 是最好的策略,這樣可以追蹤到每一條日誌消息的來源。
在 logback 的世界中,日誌信息不只僅能夠打印至 console,也能夠打印至文件,甚至輸出到網絡流中,日誌打印的目的地由 Appender 來決定,不一樣的 Appender 能將日誌信息打印到不一樣的目的地去。
Appender 是綁定在 logger 上的,同時,一個 logger 能夠綁定多個 Appender,意味着一條信息能夠同時打印到不一樣的目的地去。例如,常見的作法是,日誌信息既輸出到控制檯,同時也記錄到日誌文件中,這就須要爲 logger 綁定兩個不一樣的 logger。
Appender 是綁定在 logger 上的,而 logger 又有繼承關係,所以一個 logger 打印信息時的目的地 Appender 須要參考它的父親和祖先。在 logback 中,默認狀況下,若是一個 logger 打印一條信息,那麼這條信息首先會打印至它本身的 Appender,而後打印至它的父親和父親以上的祖先的 Appender,但若是它的父親設置了 additivity = false
,那麼這個 logger 除了打印至它本身的 Appender 外,只會打印至其父親的 Appender,由於它的父親的 additivity
屬性置爲了 false,開始變得忘祖忘宗了,因此這個 logger 只認它父親的 Appender;此外,對於這個 logger 的父親來講,若是父親的 logger 打印一條信息,那麼它只會打印至本身的 Appender中(若是有的話),由於父親已經忘記了爺爺及爺爺以上的那些父輩了。
打印的日誌除了有打印的目的地外,還有日誌信息的展現格式。在 logback 中,用 Layout 來表明日誌打印格式。好比說,PatternLayout 可以識別如下這條格式:
%-4relative [%thread] %-5level %logger{32} - %msg%n
而後打印出來的格式效果是:
176 [main] DEBUG manual.architecture.HelloWorld2 - Hello world.
上面這個格式的第一個字段表明從程序啓動開始後通過的毫秒數,第二個字段表明打印出這條日誌的線程名字,第三個字段表明日誌信息的日誌打印級別,第四個字段表明 logger name,第五個字段是日誌信息,第六個字段僅僅是表明一個換行符。
常常能看到打印日誌的時候,使用如下這種方式打印日誌:
logger.debug("the message is " + msg + " from " + somebody);
這種打印日誌的方式有個缺點,就是不管日誌級別是什麼,程序總要先執行 "the message is " + msg + " from " + somebody
這段字符串的拼接操做。當 logger 設置的日誌級別爲比 DEBUG 級別更高級別時,DEBUG 級別的信息不回被打印出來的,顯然,字符串拼接的操做是沒必要要的,當要拼接的字符串很大時,這無疑會帶來很大的性能白白損耗。
因而,一種改進的打印日誌方式被人們發現了:
if(logger.isDebugEnabled()) { logger.debug("the message is " + msg + " from " + somebody); }
這樣的方式確實能避免字符串拼接的沒必要要損耗,但這也不是最好的方法,當日志級別爲 DEBUG 時,那麼打印這行消息,須要判斷兩第二天志級別。一次是logger.isDebugEnabled()
,另外一次是 logger.debug()
方法內部也會作的判斷。這樣也會帶來一點點效率問題,若是能找到更好的方法,誰願意無視白白消耗的效率。
有一種更好的方法,那就是提供佔位符的方式,以參數化的方式打印日誌,例如上述的語句,能夠是這樣的寫法:
logger.debug("the message {} is from {}", msg, somebody);
這樣的方式,避免了字符串拼接,也避免了多一第二天志級別的判斷。
當應用程序發起一個記錄日誌的請求,例如 info() 時,logback 的內部運行流程以下所示
得到過濾器鏈條
檢查日誌級別以決定是否繼續打印
建立一個 LoggingEvent
對象
調用 Appenders
進行日誌信息格式化
發送 LoggingEvent
到對應的目的地
關於日誌系統,人們討論得最多的是性能問題,即便是小型的應用程序,也有可能輸出大量的日誌。打印日誌中的不當處理,會引起各類性能問題,例如太多的日誌記錄請求可能使磁盤 IO 成爲性能瓶頸,從而影響到應用程序的正常運行。在合適的時候記錄日誌、以更好的方式發起日誌請求、以及合理設置日誌級別方面,都有可能形成性能問題。
關於性能問題,如下幾個方面須要瞭解
建議使用佔位符的方式參數化記錄日誌
logback 內部機制保證 logger 在記錄日誌時,沒必要每一次都去遍歷它的父輩以得到關於日誌級別、Appender 的信息
在 logback 中,將日誌信息格式化,以及輸出到目的地,是最損耗性能的操做
logback 提供的配置方式有如下幾種:
編程式配置
xml 格式
groovy 格式
logback 在啓動時,根據如下步驟尋找配置文件:
在 classpath 中尋找 logback-test.xml文件
若是找不到 logback-test.xml,則在 classpath 中尋找 logback.groovy 文件
若是找不到 logback.groovy,則在 classpath 中尋找 logback.xml文件
若是上述的文件都找不到,則 logback 會使用 JDK 的 SPI 機制查找 META-INF/services/ch.qos.logback.classic.spi.Configurator 中的 logback 配置實現類,這個實現類必須實現 Configuration
接口,使用它的實現來進行配置
若是上述操做都不成功,logback 就會使用它自帶的 BasicConfigurator
來配置,並將日誌輸出到 console
logback-test.xml 通常用來在測試代碼中打日誌,若是是 maven 項目,通常把 logback-test.xml 放在 src/test/resources 目錄下。maven 打包的時候也不會把這個文件打進 jar 包裏。
logback 啓動的時候解析配置文件大概須要 100 毫秒的時間,若是但願更快啓動,能夠採用 SPI 的方式。
前面有提到默認的配置,由 BasicConfiguator
類配置而成,這個類的配置能夠用以下的配置文件來表示:
<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>
若是 logback 在啓動時,解析配置文件時,出現了須要警告的信息或者錯誤信息,那 logback 會自動先打印出自身的狀態信息。
若是但願正常狀況下也打印出狀態信息,則可使用以前提到的方式,在代碼裏顯式地調用使其輸出:
public static void main(String[] args) { // assume SLF4J is bound to logback in the current environment LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); // print logback's internal status StatusPrinter.print(lc); ... }
也能夠在配置文件中,指定 configuration 的 debug 屬性爲 true
<configuration debug="true"> <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>
還能夠指定一個 Listener:
<configuration> <statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" /> ... the rest of the configuration file </configuration>
設置 logback.configurationFile 系統變量,能夠經過 -D 參數設置,所指定的文件名必須以 .xml 或者 .groovy 做爲文件後綴,不然 logback 會忽略這些文件。
要使配置文件自動重載,須要把 scan 屬性設置爲 true,默認狀況下每分鐘纔會掃描一次,能夠指定掃描間隔:
<configuration scan="true" scanPeriod="30 seconds" > ... </configuration>
注意掃描間隔要加上單位,可用的單位是 milliseconds,seconds,minutes 和 hours。若是隻指定了數字,但沒有指定單位,這默認單位爲 milliseconds。
在 logback 內部,當設置 scan 屬性爲 true 後,一個叫作 ReconfigureOnChangeFilter
的過濾器就會被牽扯進來,它負責判斷是否到了該掃描的時候,以及是否該從新加載配置。Logger 的任何一個打印日誌的方法被調用時,都會觸發這個過濾器,因此關於這個過濾器的自身的性能問題,變得十分重要。logback 目前採用這樣一種機制,當 logger 的調用次數到達必定次數後,才真正讓過濾器去作它要作的事情,這個次數默認是 16,而 logback 會在運行時根據調用的頻繁度來動態調整這個數目。
這個屬性默認是關閉,可經過如下方式開啓:
<configuration packagingData="true"> ... </configuration>
也能夠經過 LoggerContext 的 setPackagingDataEnabled(boolean) 方法來開啓
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); lc.setPackagingDataEnabled(true);
Joran 是 logback 使用的一個配置加載庫,若是想要從新實現 logback 的配置機制,能夠直接調用這個類 JoranConfigurator
來實現:
package chapters.configuration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.joran.JoranConfigurator; import ch.qos.logback.core.joran.spi.JoranException; import ch.qos.logback.core.util.StatusPrinter; public class MyApp3 { final static Logger logger = LoggerFactory.getLogger(MyApp3.class); public static void main(String[] args) { // assume SLF4J is bound to logback in the current environment LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); try { JoranConfigurator configurator = new JoranConfigurator(); configurator.setContext(context); // Call context.reset() to clear any previous configuration, e.g. default // configuration. For multi-step configuration, omit calling context.reset(). context.reset(); configurator.doConfigure(args[0]); } catch (JoranException je) { // StatusPrinter will handle this } StatusPrinter.printInCaseOfErrorsOrWarnings(context); logger.info("Entering application."); Foo foo = new Foo(); foo.doIt(); logger.info("Exiting application."); } }
根節點是 configuration,可包含0個或多個 appender,0個或多個 logger,最多一個 root。
在配置文件中,logger 的配置在<logger> 標籤中配置,<logger> 標籤只有一個屬性是必定要的,那就是 name,除了 name 屬性,還有 level 屬性,additivity 屬性能夠配置,不過它們是可選的。
level 的取值能夠是 TRACE, DEBUG, INFO, WARN, ERROR, ALL, OFF, INHERITED, NULL
, 其中 INHERITED
和 NULL
的做用是同樣的,並非不打印任何日誌,而是強制這個 logger 必須從其父輩繼承一個日誌級別。
additivity 的取值是一個布爾值,true 或者 false。
<logger> 標籤下只有一種元素,那就是 <appender-ref>,能夠有0個或多個,意味着綁定到這個 logger 上的 Appender。
<root> 標籤和 <logger> 標籤的配置相似,只不過 <root> 標籤只容許一個屬性,那就是 level 屬性,而且它的取值範圍只能取 TRACE, DEBUG, INFO, WARN, ERROR, ALL, OFF
。
<root> 標籤下容許有0個或者多個 <appender-ref>。
<appender> 標籤有兩個必須填的屬性,分別是 name 和 class,class 用來指定具體的實現類。<appender> 標籤下能夠包含至多一個 <layout>,0個或多個 <encoder>,0個或多個 <filter>,除了這些標籤外,<appender> 下能夠包含一些相似於 JavaBean 的配置標籤。
<layout> 包含了一個必須填寫的屬性 class,用來指定具體的實現類,不過,若是該實現類的類型是 PatternLayout
時,那麼能夠不用填寫。<layout> 也和 <appender> 同樣,能夠包含相似於 JavaBean 的配置標籤。
<encoder> 標籤包含一個必須填寫的屬性 class,用來指定具體的實現類,若是該類的類型是 PatternLayoutEncoder
,那麼 class 屬性能夠不填。
若是想要往一個 logger 上綁定 appender,則使用如下方式:
<logger name="HELLO" level="debug"> <appender-ref ref="FILE" /> <appender-ref ref="STDOUT" /> </logger>
<configuration> <contextName>myAppName</contextName> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d %contextName [%t] %level %logger{36} - %msg%n</pattern> </encoder> </appender> <root level="debug"> <appender-ref ref="STDOUT" /> </root> </configuration>
在 logback 中,支持以 ${varName} 來引用變量
能夠直接在 logback.xml 中定義變量
<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>
也能夠經過大D參數來定義
java -DUSER_HOME="/home/sebastien" MyApp2
也能夠經過外部文件來定義
<configuration> <property file="src/main/java/chapters/configuration/variables1.properties" /> <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>
外部文件也支持 classpath 中的文件
<configuration> <property resource="resource1.properties" /> <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>
外部文件的格式是 key-value 型。
USER_HOME=/home/sebastien
變量有三個做用域
local
context
system
local 做用域在配置文件內有效,context 做用域的有效範圍延伸至 logger context,system 做用域的範圍最廣,整個 JVM 內都有效。
logback 在替換變量時,首先搜索 local 變量,而後搜索 context,而後搜索 system。
如何爲變量指定 scope ?
<configuration> <property scope="context" name="nodeId" value="firstNode" /> <appender name="FILE" class="ch.qos.logback.core.FileAppender"> <file>/opt/${nodeId}/myApp.log</file> <encoder> <pattern>%msg%n</pattern> </encoder> </appender> <root level="debug"> <appender-ref ref="FILE" /> </root> </configuration>
在引用一個變量時,若是該變量未定義,那麼能夠爲其指定默認值,作法是:
${aName:-golden}
須要使用 <define> 標籤,指定接口 PropertyDfiner
對應的實現類。以下所示:
<configuration> <define name="rootLevel" class="a.class.implementing.PropertyDefiner"> <shape>round</shape> <color>brown</color> <size>24</size> </define> <root level="${rootLevel}"/> </configuration>
logback 容許在配置文件中定義條件語句,以決定配置的不一樣行爲,具體語法格式以下:
<!-- if-then form --> <if condition="some conditional expression"> <then> ... </then> </if> <!-- if-then-else form --> <if condition="some conditional expression"> <then> ... </then> <else> ... </else> </if>
示例:
<configuration debug="true"> <if condition='property("HOSTNAME").contains("torino")'> <then> <appender name="CON" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d %-5level %logger{35} - %msg %n</pattern> </encoder> </appender> <root> <appender-ref ref="CON" /> </root> </then> </if> <appender name="FILE" class="ch.qos.logback.core.FileAppender"> <file>${randomOutputDir}/conditional.log</file> <encoder> <pattern>%d %-5level %logger{35} - %msg %n</pattern> </encoder> </appender> <root level="ERROR"> <appender-ref ref="FILE" /> </root> </configuration>
使用 <insertFromJNDI> 能夠從 JNDI 加載變量,以下所示:
<configuration> <insertFromJNDI env-entry-name="java:comp/env/appName" as="appName" /> <contextName>${appName}</contextName> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d ${CONTEXT_NAME} %level %msg %logger{50}%n</pattern> </encoder> </appender> <root level="DEBUG"> <appender-ref ref="CONSOLE" /> </root> </configuration>
可使用 ≶include> 標籤在一個配置文件中包含另一個配置文件,以下圖所示:
<configuration> <include file="src/main/java/chapters/configuration/includedConfig.xml"/> <root level="DEBUG"> <appender-ref ref="includedConsole" /> </root> </configuration>
被包含的文件必須有如下格式:
<included> <appender name="includedConsole" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>"%d - %m%n"</pattern> </encoder> </appender> </included>
支持從多種源頭包含
從文件中包含
<include file="src/main/java/chapters/configuration/includedConfig.xml"/>
從 classpath 中包含
<include resource="includedConfig.xml"/>
從 URL 中包含
<include url="http://some.host.com/includedConfig.xml"/>
若是包含不成功,那麼 logback 會打印出一條警告信息,若是不但願 logback 抱怨,只需這樣作:
<include optional="true" ..../>
LoggerContextListener
接口的實例能監聽 logger context 上發生的事件,好比說日誌級別的變化,添加的方式以下所示:
<configuration debug="true"> <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator"/> .... </configuration>
具體的其它高級功能配置請看官網:
https://logback.qos.ch/documentation.html