1. 程式人生 > >logback 入門教程系列-03-logback config 配置

logback 入門教程系列-03-logback config 配置

配置

將日誌請求插入應用程式程式碼需要相當多的計劃和努力。

觀察表明,大約4%的程式碼專門用於記錄。

因此,即使是適度大小的應用程式也會在其程式碼中嵌入數千個日誌記錄語句。

鑑於它們的數量,我們需要工具來管理這些日誌語句。

可以通過程式設計方式或使用以XML或Groovy格式表示的配置指令碼來配置Logback。

順便說一句,現有的log4j使用者可以使用我們的PropertiesTranslator Web應用程式將他們的log4j.properties檔案轉換為logback.xml。

初始化步驟

讓我們首先討論後續嘗試配置自身的初始化步驟:

  1. Logback嘗試在類路徑中查詢名為logback-test.xml的檔案。

  2. 如果未找到此類檔案,則logback會嘗試在類路徑中查詢名為logback.groovy的檔案。

  3. 如果找不到這樣的檔案,它會檢查類路徑中的檔案logback.xml。

  4. 如果沒有找到這樣的檔案,則通過查詢檔案META-INF\services\ch,使用服務提供者載入工具(在JDK 1.6中引入)來解析com.qos.logback.classic.spi.Configurator介面的實現類路徑中的qos.logback.classic.spi.Configurator。
    其內容應指定所需Configurator實現的完全限定類名。

  5. 如果以上都不成功,則logback將使用BasicConfigurator自動配置自身,這將導致日誌記錄輸出定向到控制檯。

最後一步是在沒有配置檔案的情況下提供預設(但非常基本)的日誌記錄功能的最後努力。

如果您正在使用Maven,並且將logback-test.xml放在src/test/resources資料夾下,Maven將確保它不會包含在生成的工件中。

因此,您可以使用不同的配置檔案,即測試期間的logback-test.xml,以及生產中的另一個檔案,即logback.xml。

快速啟動Joran解析給定的回溯配置檔案大約需要100毫秒。

要在應用程式啟動時減少這些毫秒,您可以使用服務提供程式載入工具(上面的第4項)來載入您自己的自定義Configurator類,使用BasicConfigrator作為一個很好的起點。

自動化配置

預設

不使用任何配置

  • AutoConfigDemo.java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author binbin.hou
 * @date 2018/11/20 16:37
 */
public class AutoConfigDemo {

    final static Logger logger = LoggerFactory.getLogger(AutoConfigDemo.class);

    public static void main(String[] args) {
        logger.info("Entering application.");
        logger.debug("Debug info...");
        logger.info("Exiting application.");
    }
}
  • 日誌資訊
16:38:44.178 [main] INFO  c.g.h.l.learn.config.AutoConfigDemo - Entering application.
16:38:44.184 [main] DEBUG c.g.h.l.learn.config.AutoConfigDemo - Debug info...
16:38:44.184 [main] INFO  c.g.h.l.learn.config.AutoConfigDemo - Exiting application.

在出現警告或錯誤時自動列印狀態訊息

如果在解析配置檔案期間發生警告或錯誤,則logback將自動在控制檯上列印其內部狀態訊息。

如果在解析配置檔案期間發生警告或錯誤,則logback將自動在控制檯上列印其內部狀態資料。

請注意,為避免重複,如果使用者顯式註冊狀態偵聽器(在下面定義),則禁用自動狀態列印。

在沒有警告或錯誤的情況下,如果您仍希望檢查logback的內部狀態,則可以通過呼叫StatusPrinter類的print()來指示logback列印狀態資料。

  • InterStatusDemo.java
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.core.util.StatusPrinter;
import org.slf4j.LoggerFactory;

/**
 * @author binbin.hou
 * @date 2018/11/20 17:27
 */
public class InterStatusDemo {

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

}
  • 日誌資訊
17:28:34,242 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback.groovy]
17:28:34,243 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback-test.xml]
17:28:34,243 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback.xml]
17:28:34,244 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Setting up default configuration.

當然,你可以使用配置的方式去檢視對應的狀態資訊。

  • logback.xml
<configuration>

    <statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" />

</configuration>

自動重新載入配置

Logback-classic可以掃描其配置檔案中的更改,並在配置檔案更改時自動重新配置。

如果指示執行此操作,logback-classic將掃描其配置檔案中的更改,並在配置檔案更改時自動重新配置。

為了指示logback-classic掃描其配置檔案中的更改並自動重新配置,請將 <configuration> 元素的scan屬性設定為true,

如下所示。

<configuration scan="true"> 
</configuration> 

掃描週期

預設情況下,將每分鐘掃描一次配置檔案以進行更改。

您可以通過設定 <configuration> 元素的scanPeriod屬性來指定不同的掃描週期。

可以以毫秒,秒,分鐘或小時為單位指定值。

這是一個例子:

<configuration scan="true" scanPeriod="30 seconds" > 
</configuration> 

如果沒有指定時間單位,則假定時間單位為毫秒,這通常是不合適的。

如果更改預設掃描週期,請不要忘記指定時間單位。

在堆疊跟蹤中啟用打包資料

注意從1.1.4版開始,預設情況下禁用打包資料。

如果指示這樣做,則logback可以包括它輸出的堆疊跟蹤線的每一行的打包資料。

打包資料由jar檔案的名稱和版本組成,從而生成堆疊跟蹤行的類。

打包資料在識別軟體版本問題時非常有用。

但是,計算起來相當昂貴,尤其是在頻繁丟擲異常的應用程式中。

這是一個示例輸出:

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

直接呼叫JoranConfigurator

Logback依賴於名為Joran的配置庫,它是logback-core的一部分。

Logback的預設配置機制在類路徑上找到的預設配置檔案上呼叫JoranConfigurator。

如果您希望因任何原因覆蓋logback的預設配置機制,可以直接呼叫JoranConfigurator。

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;

/**
 * @author binbin.hou
 * @date 2018/11/20
 */
public class JoranConfiguratorDemo {

    private final static Logger logger = LoggerFactory.getLogger(JoranConfiguratorDemo.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();
            final String configFilePath = "";
            configurator.doConfigure(configFilePath);
        } catch (JoranException je) {
            // StatusPrinter will handle this
        }
        StatusPrinter.printInCaseOfErrorsOrWarnings(context);

        logger.info("Entering application.");
        logger.info("Exiting application.");
    }

}

此應用程式獲取當前有效的LoggerContext,建立新的JoranConfigurator,設定它將執行的上下文,重置記錄器上下文,然後最終要求配置程式使用作為引數傳遞給應用程式的配置檔案來配置上下文。 如果出現警告或錯誤,將列印內部狀態資料。

請注意,對於多步配置,應省略 context.reset() 呼叫。

停止 logback-classsic

為了釋放logback-classic使用的資源,停止logback上下文總是一個好主意。

停止上下文將關閉附加到上下文定義的記錄器的所有appender,並以有序的方式停止任何活動執行緒。

import ch.qos.logback.classic.LoggerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author binbin.hou
 * @date 2018/11/20
 */
public class StopLogbackContextDemo {

    private final static Logger logger = LoggerFactory.getLogger(StopLogbackContextDemo.class);

    public static void main(String[] args) {
        // assume SLF4J is bound to logback-classic in the current environment
        LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
        loggerContext.stop();

        logger.info("hello");
    }

}
  • 日誌資訊

logger.info("hello"); 這句話的內容並沒有被列印。

配置檔案語法

正如您在手冊中看到的那樣,仍有大量示例需要遵循,回溯允許您重新定義日誌記錄行為,而無需重新編譯程式碼。

實際上,您可以輕鬆配置日誌記錄,以便禁用應用程式某些部分的日誌記錄,或者直接輸出到UNIX Syslog守護程式,資料庫,日誌視覺化程式或將日誌記錄事件轉發到遠端日誌伺服器,這將記錄日誌根據本地伺服器策略,例如通過將日誌事件轉發到第二個logback伺服器。

本節的其餘部分介紹了配置檔案的語法。

正如將一遍又一遍地證明的那樣,logback配置檔案的語法非常靈活。

因此,無法使用DTD檔案或XML架構指定允許的語法。

然而,配置檔案的基本結構可以描述為<configuration>元素,包含零個或多個<appender>元素,後跟零個或多個<logger>元素,後跟最多一個<root>元素。

標籤是大小寫敏感的

配置記錄器或 logger 元素

此時,您應該至少對級別繼承和基本選擇規則有一些瞭解。

否則,除非你是埃及古物學家,否則物件不會像象形文字那樣對你有意義。

使用<logger>元素配置記錄器。

<logger>元素只接受一個必需的name屬性,一個可選的level屬性和一個可選的additivity屬性,允許值為true或false。

level屬性的值允許一個不區分大小寫的字串值TRACE,DEBUG,INFO,WARN,ERROR,ALL或OFF。

特殊於大小寫不敏感的值INHERITED或其同義詞NULL將強制記錄器的級別從層次結構中的較高級別繼承。

如果您設定記錄器的級別並稍後決定它應該繼承其級別,這會派上用場。

<logger>元素可以包含零個或多個<appender-ref>元素;

這樣引用的每個appender都被新增到指定的logger中。

請注意,與log4j不同,logback-classic在配置給定記錄器時不會關閉也不會刪除任何先前引用的appender。

配置根記錄器或元素

<root>元素配置根記錄器。

它支援單個屬性,即level屬性。 它不允許任何其他屬性,因為additivity標誌不適用於根記錄器。

此外,由於根記錄器已被命名為“ROOT”,因此它也不允許使用name屬性。

level屬性的值可以是不區分大小寫的字串TRACE,DEBUG,INFO,WARN,ERROR,ALL或OFF之一。

請注意,根記錄器的級別不能設定為INHERITED或NULL。

  • 例子

預設根節點,日誌級別為 DEBUG。

指定 com.github.houbb 包下的所有類,都按照 INFO 級別列印日誌。

所有的日誌輸出到命令列,即 STDOUT 對應的 appender。

<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="com.github.houbb" 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>

配置 Appenders

appender使用<appender>元素配置,該元素採用兩個必需屬性name和class。

name屬性指定appender的名稱,而class屬性指定要例項化的appender類的完全限定名稱。

<appender>元素可以包含零個或一個<layout>元素,零個或多個<encoder>元素以及零個或多個<filter>元素。

除了這三個公共元素之外,<appender>元素可以包含與appender類的JavaBean屬性相對應的任意數量的元素。

無縫支援給定logback元件的任何屬性是Joran的主要優勢之一,如後面的章節所述。

appenderSyntax

<layout>元素採用強制類屬性,指定要例項化的佈局類的完全限定名稱。

<appender>元素一樣,<layout>可以包含與佈局例項的屬性對應的其他元素。

由於它是如此常見的情況,如果佈局類是PatternLayout,則可以省略class屬性,如預設類對映規則所指定。

<encoder>元素採用強制類屬性,指定要例項化的編碼器類的完全限定名稱。

由於它是如此常見的情況,如果編碼器類是PatternLayoutEncoder,則可以省略class屬性,如預設類對映規則所指定的那樣。

  • 例子

這樣日誌會同時出輸出命令列和 myApp.log 檔案。

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

Appenders積累

預設情況下,appender是累積的:記錄器將記錄到自身附加的appender(如果有的話)以及附加到其祖先的所有appender。

因此,將相同的appender附加到多個記錄器將導致日誌記錄輸出重複。

<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="com.github.houbb">
        <appender-ref ref="STDOUT" />
    </logger>

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

日誌會被重複輸出。

重寫預設的行為

如果預設累積行為證明不適合您的需要,您可以通過將additivity標誌設定為false來覆蓋它。

因此,記錄器樹中的分支可以將輸出定向到與樹的其餘部分不同的一組appender。

<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="com.github.houbb" additivity="false">
        <appender-ref ref="STDOUT" />
    </logger>

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

注意屬性 additivity="false",這樣配置之後,只會列印一次。

設定變數

設定 context 名稱

如前一章所述,每個記錄器都附加到記錄器上下文。 預設情況下,記錄器上下文稱為“預設”。

但是,您可以在<contextName>配置指令的幫助下設定不同的名稱。

請注意,一旦設定,就無法更改記錄器上下文名稱。 設定上下文名稱是一種簡單而直接的方法,以便區分記錄到同一目標的多個應用程式。

  • logback.xml
<configuration>
    <contextName>logback-learn-context</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>

日誌資訊:

2018-11-20 20:22:47,107 logback-learn-context [main] INFO c.g.h.l.learn.config.AutoConfigDemo - Entering application.
2018-11-20 20:22:47,109 logback-learn-context [main] DEBUG c.g.h.l.learn.config.AutoConfigDemo - Debug info...
2018-11-20 20:22:47,109 logback-learn-context [main] INFO c.g.h.l.learn.config.AutoConfigDemo - Exiting application.

變數替換

注意本文件的早期版本使用術語“屬性替換”而不是術語“變數”。

請考慮這兩個術語是否可以互換,儘管後一術語表達了更清晰的含義。

與許多指令碼語言一樣,logback配置檔案支援變數的定義和替換。

變數有一個範圍(見下文)。 此外,變數可以在配置檔案本身,外部檔案,外部資源中定義,甚至可以動態計算和定義。

變數替換可以發生在配置檔案中可以指定值的任何位置。

變數替換的語法類似於Unix shell的語法。

開頭$ {和結束}之間的字串被解釋為對屬性值的引用。

對於屬性aName,字串“$ {aName}”將替換為aName屬性儲存的值。

因為它們經常派上用場,所以HOSTNAMECONTEXT_NAME變數會自動定義並具有上下文範圍。

鑑於在某些環境中計算主機名可能需要一些時間,其值會被懶惰地計算(僅在需要時)。

此外,可以直接在配置中設定HOSTNAME。

定義變數

變數可以在配置檔案本身中一次定義一個,也可以從外部屬性檔案或外部資源批量載入。

由於歷史原因,用於定義變數的XML元素是<property>
儘管在logback 1.0.7及更高版本中元素<variable>可以互換使用。

下一個示例顯示了在配置檔案開頭宣告的變數。

然後在檔案的下方使用它來指定輸出檔案的位置。

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

USER_HOME 根據不同的作業系統來設定,才更加人性化。

參考資料

https://logback.qos.ch/manual/configuration.html

導航

導航