logback配置詳解


本文轉自:https://segmentfault.com/a/1190000008315137

概覽

簡單地說,Logback 是一個 Java 領域的日志框架。它被認為是 Log4J 的繼承人。
Logback 主要由三個模塊組成:

  • logback-core

  • logback-classic

  • logback-access

logback-core 是其它模塊的基礎設施,其它模塊基於它構建,顯然,logback-core 提供了一些關鍵的通用機制。logback-classic 的地位和作用等同於 Log4J,它也被認為是 Log4J 的一個改進版,並且它實現了簡單日志門面 SLF4J;而 logback-access 主要作為一個與 Servlet 容器交互的模塊,比如說 tomcat 或者 jetty,提供一些與 HTTP 訪問相關的功能。

目前 Logback 的使用很廣泛,很多知名的開源軟件都使用了 Logback作為日志框架,比如說 Akka,Apache Camel 等。

Logback 與 Log4J

實際上,這兩個日志框架都出自同一個開發者之手,Logback 相對於 Log4J 有更多的優點

  • 同樣的代碼路徑,Logback 執行更快

  • 更充分的測試

  • 原生實現了 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

讓 Logback 打印出一些它自身的內部消息 

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.

Logger,Appenders 與 Layouts

在 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

獲取 logger

在 logback 中,每個 logger 都是一個單例,調用 LoggerFactory.getLogger 方法時,如果傳入的 logger name 相同,獲取到的 logger 都是同一個實例。

在為 logger 命名時,用類的全限定類名作為 logger name 是最好的策略,這樣能夠追蹤到每一條日志消息的來源。

Appender 和 Layout

在 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);

這樣的方式,避免了字符串拼接,也避免了多一次日志級別的判斷。

logback 內部運行流程

 

當應用程序發起一個記錄日志的請求,例如 info() 時,logback 的內部運行流程如下所示

  1. 獲得過濾器鏈條

  2. 檢查日志級別以決定是否繼續打印

  3. 創建一個 LoggingEvent 對象

  4. 調用 Appenders

  5. 進行日志信息格式化

  6. 發送 LoggingEvent 到對應的目的地

有關性能問題

關於日志系統,人們討論得最多的是性能問題,即使是小型的應用程序,也有可能輸出大量的日志。打印日志中的不當處理,會引發各種性能問題,例如太多的日志記錄請求可能使磁盤 IO 成為性能瓶頸,從而影響到應用程序的正常運行。在合適的時候記錄日志、以更好的方式發起日志請求、以及合理設置日志級別方面,都有可能造成性能問題。
關於性能問題,以下幾個方面需要了解

  • 建議使用占位符的方式參數化記錄日志

  • logback 內部機制保證 logger 在記錄日志時,不必每一次都去遍歷它的父輩以獲得關於日志級別、Appender 的信息

  • 在 logback 中,將日志信息格式化,以及輸出到目的地,是最損耗性能的操作

logback 配置

配置須知

配置方式

logback 提供的配置方式有以下幾種:

  • 編程式配置

  • xml 格式

  • groovy 格式

logback 在啟動時,根據以下步驟尋找配置文件:

  1. 在 classpath 中尋找 logback-test.xml文件

  2. 如果找不到 logback-test.xml,則在 classpath 中尋找 logback.groovy 文件

  3. 如果找不到 logback.groovy,則在 classpath 中尋找 logback.xml文件

  4. 如果上述的文件都找不到,則 logback 會使用 JDK 的 SPI 機制查找 META-INF/services/ch.qos.logback.classic.spi.Configurator 中的 logback 配置實現類,這個實現類必須實現 Configuration 接口,使用它的實現來進行配置

  5. 如果上述操作都不成功,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 會在運行時根據調用的頻繁度來動態調整這個數目。

輸出異常棧時也打印出 jar 包的信息

這個屬性默認是關閉,可通過以下方式開啟:

<configuration packagingData="true">
  ...
</configuration>

也可以通過 LoggerContext 的 setPackagingDataEnabled(boolean) 方法來開啟

 LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
 lc.setPackagingDataEnabled(true);

直接調用 JoranConfigurator

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> 標簽中配置,<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 節點

<root> 標簽和 <logger> 標簽的配置類似,只不過 <root> 標簽只允許一個屬性,那就是 level 屬性,並且它的取值范圍只能取 TRACE, DEBUG, INFO, WARN, ERROR, ALL, OFF
<root> 標簽下允許有0個或者多個 <appender-ref>。

配置 appender 節點

<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>

設置 Context Name

<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>

從JNDI 獲取變量

使用 <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" ..../>

添加一個 Context Listener

LoggerContextListener 接口的實例能監聽 logger context 上發生的事件,比如說日志級別的變化,添加的方式如下所示:

 

<configuration debug="true">
  <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator"/>
  .... 
</configuration>

 

具體的其它高級功能配置請看官網:

https://logback.qos.ch/documentation.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM