logback原理與配置

Logback體系結構

Logback體系結構

Logback包括三個模塊,logback-core、logback-classic、logback-access
Logback-core是另外兩個模塊的基礎,classic模塊繼承自core模塊,classic模塊對應於log4j的改進版本,由於Logback-classic模塊實現了SLF4jAPI,可以輕鬆的切換日誌框架,比如log4j或者java.util.logging,
Log-access模塊與Servlet容器集成可以提供HTTP訪問日誌,

Logger, Appenders and Layouts
Logback建立於三個主要的類之上:Logger、Appender以及Layout.這三個類齊心協力可以使開發者根據日誌類型、日誌級別輸出日誌信息,控制輸出格式以及控制輸出位置

Logger context
Logback會管理它下面的各個Loggers,Logger具有繼承關係,通過點號,來分割名稱,如果一個Logger a名稱是另外一個Logger b名稱的前綴,那麼a是b的祖先

日誌繼承級別

給定一個Logger,它的日誌級別是沿着繼承層次向上找一個非空的日誌級別,繼承層次最高的是root logger

下面給定幾個例子來說明這個機制。
Example 1

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

Example 2

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

Example 3

Logger name Assigned level Effective level
root DEBUG DEBUG
X INFO INFO
X.Y none INFO
X.Y.Z ERROR ERROR

Example 4

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

日誌輸出選擇規則
日誌級別有5個,分別爲TRACE,DEBUG,INFO,WARN,ERROR,以級別大小排序是TRACE<DEBUG<INFO<WARN<ERROR,如果日誌級別設置爲q,代碼中輸出級別是p,只有p>=q,日誌纔會真正輸出出來

例如:設置日誌輸出級別爲INFO級別,代碼輸出爲DEBUG,那麼日誌不會輸出
在這裏插入圖片描述
在這裏插入圖片描述
將代碼輸出的日誌級別調整爲ERROR後可以正常輸出:
在這裏插入圖片描述

Appenders and Layouts

  1. Appender控制日誌輸出方式,可以輸出到控制檯、文件、遠程socket服務器、MySQL、PostgreSQL、Oracle以及其他數據庫、JMS、遠程Unix系統日誌

  2. 多個appender可以附加到一個logger上,一個給定的logger接收到日誌請求後,它會將請求轉發到它下面的appender以及繼承層次更高的appender之上。Appenders也具有繼承性。舉個例子,一個控制檯輸出的appender加入到root logger下面,那麼所有有效日誌請求都會輸出到控制檯。如果文件appender加入到logger A,那麼A以及A的孩子,在收到日誌請求後,會將日誌輸出到文件以及控制檯上

  3. 通過設置appender additivity爲false,可以取消appender的繼承性
    下面的表格說明了,通過設置這個flag改變了appender繼承性

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.

修改日誌輸出格式
通常默認的日誌輸出樣式可能不是我們想要的,Logback提供了很多日誌樣式參數,可以按照我們的需求來輸出日誌。控制日誌輸出樣式的是PatternLayout
例如,轉化模式是”%-4relative [%thread] %5-level %logger{32} - %msg%n”將會輸出如下內容
176 [main] DEBUG manual.architecture.HelloWorld2 - Hello world.

  • 第一個字段是從程序啓動到打印這條日誌所花時間
  • 第二個字段是提出日誌請求的線程名
  • 第三個字段是日誌請求級別,
  • 第四個字段是logger名稱
  • 第五個字段是日誌輸出內容

Logback推薦在日誌輸出之前做一次日誌能否輸出的判斷,

if(logger.isDebugEnabled()) { 
  logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));
}

如果少了判斷,直接輸出,那麼無論日誌是否輸出,都會有構造信息參數的花費,將i轉換爲字符串,array數組轉換爲字符串
加上判斷,即使日誌真的會輸出,這個判斷的代價是很小的,可以忽略不計

推薦使用佔位符的方式發起日誌請求
例如

Object entry=new SomeObject();
Logger.debug(“the entry is {}”,entry);
比 logger.debug(“the entry is “+entry+””)的方式更好

前者比後者快百分之30左右

Logback配置

Logback配置尋找

  1. classpath下的logback.xml
  2. classpath下的logbac.groovy
  3. classpath下的logback.xml
  4. 通過service-provider loading facility來解析com.qos.logback.classic.spi.Configuration接口實現,這個實現的全名稱配置在META-INF\services\ch.qos.logback.classic.spi.Configurator裏面
  5. Logback使用默認的BasicConfiguration,默認直接輸出到控制檯上

快啓動:
解析用戶自定義的xml文件需要100ms的時間,如果這個時間佔用了系統啓動時間,可以通過service-provider loader facility的方式在一個合適的啓動點加載配置文件

如果沒有指定任何配置文件,那麼logback會調用BasicConfiguration來最小化配置,它會將ConsoleAppender附加到root logger,輸出格式使用PatternLayoutEncoder來設置輸出格式爲%d{HH:mm:ss.SSS} [%thread]

%-5level %logger{36} - %msg%n. 16:06:09.031 [main] INFO
chapters.configuration.MyApp1 - Entering application. 16:06:09.046
[main] DEBUG chapters.configuration.Foo - Did it again! 16:06:09.046
[main] INFO chapters.configuration.MyApp1 - Exiting application.

使用logback-test.xml或者logback.xml自動配置
默認會使用logback.xml文件或者logback-test.xml文件,如果二者都不存在時,使用BasicConfiguration。
這個類等同於如下配置

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

出現warning和error時會自動打印狀態信息,也可以使用logback使用的api來打印狀態信息,具體如下:

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

運行上述程序,可以看到idea輸出如下信息:

09:43:28,939 |-INFO in ch.qos.logback.classic.LoggerContext[default] -
Could NOT find resource [logback.groovy] 09:43:28,939 |-INFO in
ch.qos.logback.classic.LoggerContext[default] - Could NOT find
resource [logback-test.xml] 09:43:28,940 |-INFO in
ch.qos.logback.classic.LoggerContext[default] - Found resource
[logback.xml] at
[file:/E:/ideaWorkspace/testlog/target/classes/logback.xml]
09:43:29,061 |-INFO in
ch.qos.logback.classic.joran.action.ConfigurationAction - debug
attribute not set 09:43:29,112 |-INFO in
ch.qos.logback.core.joran.action.AppenderAction - About to instantiate
appender of type [ch.qos.logback.core.ConsoleAppender] 09:43:29,122
|-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming
appender as [STDOUT] 09:43:29,156 |-INFO in
ch.qos.logback.core.joran.action.NestedComplexPropertyIA - Assuming
default type [ch.qos.logback.classic.encoder.PatternLayoutEncoder] for
[encoder] property 09:43:29,262 |-INFO in
ch.qos.logback.classic.joran.action.RootLoggerAction - Setting level
of ROOT logger to DEBUG 09:43:29,262 |-INFO in
ch.qos.logback.core.joran.action.AppenderRefAction - Attaching
appender named [STDOUT] to Logger[ROOT] 09:43:29,263 |-INFO in
ch.qos.logback.classic.joran.action.ConfigurationAction - End of
configuration. 09:43:29,266 |-INFO in
ch.qos.logback.classic.joran.JoranConfigurator@1ccd51b - Registering
current configuration as safe fallback point

命令行指定配置文件:
Java -Dlogback.configurationFile=/path/to/config.xml chapters.configuration.MyApp1
不過命令行方式,只能識別.xml文件或者.groovy文件,其他格式文件將被忽略

通過代碼的方式指定配置文件

public class ServerMain {
    public static void main(String args[]) throws IOException, InterruptedException {
       // must be set before the first call to  LoggerFactory.getLogger();
       // ContextInitializer.CONFIG_FILE_PROPERTY is set to "logback.configurationFile"
       System.setProperty(ContextInitializer.CONFIG_FILE_PROPERTY, /path/to/config.xml);
       ...
    }   
}

需要注意的是,指定系統屬性之後,再創建日誌實例,纔會使設置系統屬性生效

自動重載配置文件
Logback默認不會自動重載配置文件,不過通過在配置文件中加入scan屬性,可以使logback週期性的加載配置文件
如下

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

默認情況下,logback會每分鐘加載一次配置文件,如果需要更改時間頻率,可以使用scanPeriod屬性配置

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

配置文件默認的時間單位是毫秒

在堆棧跟蹤信息中輸出包信息

在1.1.4版本中,包信息不會被輸出
如果設置爲輸出,輸出信息如下:

14:28:48.835 [btpool0-7] INFO c.q.l.demo.prime.PrimeAction - 99 is
not a valid value java.lang.Exception: 99 is invalid at
ch.qos.logback.demo.prime.PrimeAction.execute(PrimeAction.java:28)
[classes/:na] at
org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:431)
[struts-1.2.9.jar:1.2.9] at
org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:236)
[struts-1.2.9.jar:1.2.9] at
org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:432)
[struts-1.2.9.jar:1.2.9] at
javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
[servlet-api-2.5-6.1.12.jar:6.1.12] at
org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:502)
[jetty-6.1.12.jar:6.1.12] at
ch.qos.logback.demo.UserServletFilter.doFilter(UserServletFilter.java:44)
[classes/:na] at
org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1115)
[jetty-6.1.12.jar:6.1.12] at
org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:361)
[jetty-6.1.12.jar:6.1.12] at
org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:417)
[jetty-6.1.12.jar:6.1.12] at
org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:230)
[jetty-6.1.12.jar:6.1.12

可以在configuration標籤加入packagingData屬性的方式輸出包信息。

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

通過代碼的方式:

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

配置文件語法規則

Logbac配置文件語法是很靈活的,可以通過xml文件的方式進行定義,最基礎的定義方式是元素下有0個或者多個元素,緊接着0個或者多個元素,緊接着最多一個元素
在這裏插入圖片描述

root是特殊的logger,它是頂級logger,它上面所有的appender會被它下面的logger所繼承,它下面的logger如果沒有聲明日誌輸出級別,那麼也會繼承這個日誌級別,如果設置了日誌輸出級別,使用子logger使用自己的日誌輸出級別
舉例說明這個規則:
Idea項目目錄結構如下:
在這裏插入圖片描述
Logback.xml裏面內容如下:

<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.xyz" level="INFO">
    </logger>
    
    <root level="debug">
        <appender-ref ref="STDOUT" />
    </root>
</configuration>

Testhierarchy類中內容如下:

package com.xyz.log.test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Testhierarchy {


    public static void main(String[] args) {
        Logger logger=LoggerFactory.getLogger(Testhierarchy.class);
        logger.info("test info");
        logger.debug("test debug");
        logger.error("test error");
        logger.warn("test warn");

    }
}

對應輸出如下:
在這裏插入圖片描述
TestHierarchy類中LoggerFactory創建出來的Logger對象在配置文件中尋找Logger層級,找到了包定義爲com.xyz的logger A,A的日誌輸出級別爲INFO,Appender從root繼承,是STDOUT,輸出到控制檯。結果驗證了這一規則

修改logback.xml文件,加入一個新的logger

<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.xyz" level="INFO">
    </logger>
    <logger name="com.xyz.log" level="DEBUG">
    </logger>

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

再次運行,得到如下結果
在這裏插入圖片描述
DEBUG級別以上日誌都輸出到了控制檯,說明Testhierarchy中的logger根據配置文件定義的logger,找到了包定義爲com.xyz.log的logger作爲父logger,繼承了日誌輸出級別爲DEBUG,appender爲STDOUT,並輸出到控制檯。

配置Appenders

Appender通過元素進行定義,通常包括兩個屬性name和class,name屬性標誌這個appender,class屬性指定這個appender實現的全限定名。元素必須包括0個或者1個元素,0個或者多個元素,0個或者多個元素。
下面這個圖說明了整體的架構
在這裏插入圖片描述

元素也可以指定多種實現方式,只需要設置實現類的全限定名,在不設置的情況下,默認是PatternLayout。
元素同樣如此,默認實現是PatternLayoutEncoder
在logback配置文件中可以設置多個appender,同時掛到一個logger上。
舉例如下:
Logback.xml文件中內容如下:


test.log

    <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>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
</appender>

<root level="debug">
    <appender-ref ref="STDOUT" />
    <appender-ref ref="FILE"/>
</root>
定義兩個Appender,一個輸出到控制檯,一個輸出到文件,兩個Appender都加到root上 定義一個測試類TestMultiOutput類內容如下,
package com.xyz.log.test;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class TestMultiOutput {


    public static void main(String[] args) {
        Logger logger= LoggerFactory.getLogger(TestMultiOutput.class);
        logger.debug("test  Multi-output");
    }
}

觀察輸出結果:
控制檯輸出爲:
在這裏插入圖片描述
文件test.log輸出如下:

在這裏插入圖片描述

Appenders疊加性

子logger具有一個appender A,父logger比如root也具有這個Appender A。這樣子logger會有兩個Appender A。
修改logback.xml文件,

<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.xyz" level="debug">
    
</logger>
<root level="debug">
    <appender-ref ref="STDOUT" />

</root>
新增一個TsetCumulative類,內容如下:
package com.xyz.log.test;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class TestCumulative {

    public static void main(String[] args) {
        Logger logger= LoggerFactory.getLogger(TestCumulative.class);
        logger.debug("test  cumulative");
    }
}

最終運行結果如下:
在這裏插入圖片描述

取消appenders疊加性的方式是通過設置logger的additivity屬性爲false
修改locback.xml文件

<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.xyz" level="debug" additivity="false">
    <appender-ref ref="STDOUT" />
</logger>
<root level="debug">
    <appender-ref ref="STDOUT" />

</root>
運行輸出,可以得到如下結果: ![在這裏插入圖片描述](https://img-blog.csdnimg.cn/20190926150304927.png)

變量定義

通過元素定義
設置appender日誌文件輸出路徑時,將文件的目錄設置爲一個變量

在Appender中只要使用這個變量就好了

<configuration>

  <property name="OUTPUT_DIR" value="/home/test " />

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

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

這樣輸出日誌時,會將日誌輸出到/home/test/test.lgo中進行保存

也可以通過命令行的方式傳入變量

Java -DOUTPUT_DIR=”/home/test” Test

如果參數有很多個,可以通過配置文件的方式引入變量。配置文件中可以這樣定義變量

OUTPUT_DIR =/home/test

變量的作用域

變量作用域分爲三個級別,local、context、system
Local:變量只在配置文件內部有效
Context: 這個變量在應用上下文中有效,例如在日誌事件中
System:JVM系統屬性級別

配置文件支持條件判斷

日誌輸出配置通常在測試環境、開發環境、生產環境有不同的輸出,如果每個環境都配置一個logback.xml文件,那麼會顯得比較臃腫,logback配置文件支持條件判斷的方式定義xml文件

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

條件判斷的參數只能是context級別或者system級別,通過property()方法獲取這個參數值,
isDefined()方法可以用來檢查一個屬性是否被定義,isNull()方法可以來檢測參數是否爲空

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

Appenders

Appender定義

:負責將寫日誌事件的任務下發到各個component、
實現方式:實現ch.qos.logback.core.Appender接口

package ch.qos.logback.core;
  
import ch.qos.logback.core.spi.ContextAware;
import ch.qos.logback.core.spi.FilterAttachable;
import ch.qos.logback.core.spi.LifeCycle;
  

public interface Appender<E> extends LifeCycle, ContextAware, FilterAttachable {

  public String getName();
  public void setName(String name);
  void doAppend(E event);
  
}

其中最爲重要的方法是doAppend()方法,這個方法負責將日誌事件以一種合適的格式輸出到一個輸出設備中

Appenders負責最終輸出日誌事件。不過它會將這個日誌事件下發到event或者layout中,讓它們來格式化輸出。每一個layout/encoder只能關聯一個appender。一些appenders有固定內置的時間格式,這樣他們就不需要layout/encoder。舉例說明,SocketAppender會在傳輸數據之前將日誌事件序列化

Logback-core
Logback-core是其他模塊的基石,logback-core中的模塊支持擴展,通過暴露一些參數,用戶可以設置自已喜好的風格

OutputStreamAppender
OutpuStreamAppender可以將時間添加到java.io.OutputStream中,這個類爲其他appender提供了基本的功能,下面是基本的配置參數

屬性名 類型 描述
encoder Encoder 決定日誌輸出到OutputStreamAppender的方式
immediateFlush Boolean 默認值爲true,保證日誌事件可以馬上寫出,而且不會因爲應用的退出而導致數據丟失,這個參數設置爲false,可以提高接近4倍的日誌吞吐量,但是可以在應用意外退出時,沒有輸出到硬盤的數據會丟失

下面有一個關於Appender的繼承層次類圖
在這裏插入圖片描述

ConsoleAppender

ConsoleAppender可以將日誌輸出到控制檯,通過System.out或者System.err的方式,System.out是默認方式。ConsoleAppender通過用戶設置的encoder格式化日誌輸出樣式
下面是它的一些配置參數

參數名 參數類型 描述
encoder Encoder 決定輸出的樣式
target String 選擇使用System.out還是System.err輸出,默認是System.out
withJansi boolean 默認爲false,如果設置true,可以支持ANSI顏色的代碼,不過windows下需要導入org.fusesource.jansi:jansi:1.8jar包

ConsoleAppender配置實例:

<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>%-4relative [%thread] %-5level %logger{35} - %msg %n</pattern>
    </encoder>
  </appender>

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

FileAppender

FileAppender是OutputStreamAppender的子類,可以將日誌寫到文件中去,文件位置可以通過File選項指定,支持追加或者覆蓋的方式。
下面是它的一些常用屬性

屬性名 類型 描述
append boolean 默認爲true,採用追加方式寫入文件,false的話會覆蓋寫入
encoder Encoder 決定日誌輸出樣式
file String 定義日誌輸出到文件的名稱,如果文件不存在,會進行創建,需要注意的是,在Windows機器上,文件名要注意轉義符,比如c:\temp\test.log,中兩個\t會翻譯爲tab鍵,如果要想要的文件,可以將\替換爲\或者/.
prudent boolean 在prudent模式下,FileAppender會很安全的輸出到特定文件,即使有運行在其他JVM上的FileAppender實例也輸出到同一個文件中,默認prudent模式是false.Prudent模式下文件以追加方式進行日誌寫入Prudent模式依賴文件排他鎖,這樣會導致比簡單的寫一個日誌輸出事件多三倍的性能消耗,當prudent模式關閉,每秒鐘可以有100000個事件處理吞吐量,打開的話就只剩下33000。每秒產生100個或者更多的IO操作的應用應該避免使用prudent模式
immediateFlush boolean 默認爲true,可以保證日誌輸出不會因爲應用的意外退出而丟失數據,如果丟失數據是可以容忍的,那麼將這個參數設置爲false,可以提高日誌吞吐量

FileAppender配置實例

<configuration>

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>testFile.log</file>
    <append>true</append>
    <!-- set immediateFlush to false for much higher logging throughput -->
    <immediateFlush>true</immediateFlush>
    <!-- encoders are assigned the type
         ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
    <encoder>
      <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
    </encoder>
  </appender>
        
  <root level="DEBUG">
    <appender-ref ref="FILE" />
  </root>
</configuration>

設置文件名(時間戳)

在應用開發階段或者短聲明週期的應用,需要每次應用啓動時產生新的日誌文件,使用元素可以輕鬆的解決這個問題

<configuration>

  <!-- Insert the current time formatted as "yyyyMMdd'T'HHmmss" under
       the key "bySecond" into the logger context. This value will be
       available to all subsequent configuration elements. -->
  <timestamp key="bySecond" datePattern="yyyyMMdd'T'HHmmss"/>

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <!-- use the previously created timestamp to create a uniquely
         named log file -->
    <file>log-${bySecond}.txt</file>
    <encoder>
      <pattern>%logger{35} - %msg%n</pattern>
    </encoder>
  </appender>

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

timestamp元素有兩個必須要寫的屬性key和datePattern,以及一個可選屬性timeReference。Key屬性可以作爲timestamp的名稱,下面的配置可以使用這個名稱進行引用這個timestamp,dataPattern屬性將當前時間轉換爲特定樣式的字符串。date定義方式遵從SimpleDateFormat。
timeReference決定使用哪個時間,比如想使用應用啓動時間,那麼可以將timeReference屬性設置爲contextBirth

<configuration>
  <timestamp key="bySecond" datePattern="yyyyMMdd'T'HHmmss" 
             timeReference="contextBirth"/>
  ...
</configuration>

RollingFileAppender

RollingFileAppender繼承於FileAppender,主要作用是爲了回滾日誌文件,比如,RollingFileAppender可以在某些條件滿足的情況下將日誌寫入到一個log.txt文件當中,改變輸出目標到另外一個文件

RollingFileAppender有兩個重要的子模塊,RollingPolicy和TriggeringPolicy,RollingPolicy負責回滾時需要做的事情,TriggeringPolicy則負責什麼時候觸發一次回滾

RollingFileAppender需要同時設置RollingPolicy和TriggeringPolicy,如果RollingPolicy實現了TriggeringPolicy接口,那麼只需要顯示的設置RollingPolicy就好了
下面是RollingFileAppender的屬性:

屬性名 類型 描述
file String 和FileAppender的file一樣
append boolean 和FileAppender的append一樣
encoder Encoder 和OutputStreamAppender一樣
rollingPolicy RollingPolicy 指定RollingFileAppender的行爲當發生了回滾時
triggeringPolicy TriggeringPolicy 什麼時候觸發回滾
prudent boolean FixedWindowRollingPolicy不支持 RollingFileAppender使用TimeBasedRollingPolicy時,使用prudent模式會有兩個限制:1. 在prudent模式中,文件壓縮不支持2. FileAppender的file屬性不能指定,因爲多數操作系統不支持在另外一個線程打開它的時候更改文件名

TimeBasedRollingPolicy

TimeBasedRollingPolicy是最爲常用的回滾策略,它基於時間定義回滾策略,比如可以按照天或者月。TimeBasedRollingPolicy同時負責觸發回滾以及回滾操作,它同時實現了RollingPolicy和TriggeringPolicy接口
下面是它的一些常用的屬性配置

屬性名 屬性類型 描述
fileNamePattern String fileNamePattern指定了回滾日誌文件名稱,它應該由文件名稱加上一個日期轉換符%d.%d轉換符可能包含一個date-and-time的模式定義,如果沒有定義會使用默認的yyyy-MM-dd,也就是年月日的方式,回滾的週期是從fileNamePattern值推斷而來 RollingFileAppender的file屬性可以設置或者不設置,如果設置了file屬性,那麼可以分離日誌文件以及壓縮日誌文件的位置,當前日誌總是被輸出到file屬性定義的位置,當前日誌文件不會更改自己的文件名。如果你不設置file屬性名稱,那麼,日誌文件名稱會根據fileNamePattern計算出來date-and-time模式,是定義在%d{}花括號裏面的,它根據SimpleDateFormat的方式進行定義,在fileNamePattern中/和\會被翻譯爲文件分隔符多個%d符號當有多個%d符號時,一個%d爲主,其他爲輔,主%d決定回滾週期,其他的%d被標記爲備用的,以aux標記多個%d可以以目錄結構的方式組織壓縮文件。比如下面的模式定義組織日誌目錄以年月爲基礎,每天回滾一次日誌/var/log/%d{yyyy/MM, aux}/myapplication.%d{yyyy-MM-dd}.logTimeZone指定回滾的時區,只需要傳遞時區參數到模式定義中,比如:aFolder/test.%d{yyyy-MM-dd-HH, UTC}.log
maxHistory int maxHistory屬性控制需要保存多久的日誌文件
totalSizeCap int totalSizeCap屬性控制所有日誌文件的最大大小總和,當最大大小被超越時,最老的日誌將會被刪除。totalSizeCap屬性需要maxHistory屬性同時被設置,maxHistory屬性會先起作用
cleanHistoryOnStart boolean 啓動應用會清除所有舊的日誌

fileNamePattern參數值

filenamePattern 回滾調度 示例
/wombat/foo.%d 使用默認模式yyyy-MM-dd每天晚上做一次回滾 file屬性沒有設置:2019年8月25號,日誌會輸出到/wombat/foo.2019-08-25,到了8月26號,日誌輸出到/wombat/foo.2019-08-26file屬性設置爲/wombat/foo.txt:2019年8號25號,日誌會輸出到/wombat/foo.txt,到了半夜,foo.txt會改名爲/wombat/foo.2019-08-25。到了2019年8月26日,一個新的/wombat/foo.txt會再次創建出來,日誌會輸出到foo.txt,到了半夜會將日誌改名爲/wombat/foo.2019-08-26/wombat/%d{yyyy/MM}/fo.txt 每個月月初回滾 file屬性沒有設置:2019年8月期間,日誌會輸出到/wombat/2019/08/foo.txt,過了8月,到了9月份,日誌會輸出到/wombat/2019/09/foo.txtfile屬性設置爲/wombat/foo.txt.在8月份,日誌會輸出到/wombat/foo.txt到了31日半夜,日誌會移動到/wombat/2019/08/foo.txt
/wombat/foo.%d{yyyy-ww}.log 每個星期開始回滾一次日誌 同上
/wombat/foo%d{yyyy-MM-dd_HH}.log 每個小時開始回滾一次 同上
/wombat/foo%d{yyyy-MM-dd_HH-mm}.log 每分鐘開始回滾一次 同上
/foo/%d{yyyy-MM,aux}/%d.log 每天回滾一次,壓縮文件位於年月下面 第一個%d被標註爲輔助%d,第二個%d省略了具體模式,這樣默認會每天回滾一次日誌,並且日誌文件會在年月組成的二級目錄下面

TimeBasedRollingPolicy文件壓縮

TimeBasedRollingPolicy支持自動文件壓縮,如果fileNamePattern選項以.gz或者.zipj結尾,那麼將會啓用壓縮

文件名模式 回滾調度 實例
/wombat/foo.%d.gz 每天回滾一次,並且使用GZIP來壓縮文件 file屬性沒有設置:2019年8月25日,日誌輸出到/wombat/foo.2019-08-25,到了半夜,日誌文件壓縮爲/wombat/foo.2019-08-25.gz。到了26日,日誌輸出到/wombat/foo.2019-08-26file屬性設置爲/wombat/foo.txt:在2019年08月25日,日誌輸出到/wombat/foo.txt,到了半夜,日誌會壓縮並更名爲/wombat/foo.2019-08-25.gz,到了26日,新的/wombat/foo.txt文件會被創建出來,並且日誌會輸出到這個新的文件上面,到了26日半夜,/wombat/foo.txt會被壓縮且更名爲/wombat/foo.2019-08-26.gz以此類推

fileNamePattern屬性有兩方面的作用:第一,計算回滾週期,其二,計算壓縮文件名。
兩種不同的fileNamePattern屬性可能有相同的回滾週期,但是文件名不一樣,比如: yyyy-MM和yyyy@MM

通過同時設置file屬性,可以擁有兩個日誌存放位置,一個是有效日誌文件的位置,另外一個是日誌壓縮文件的位置。

日誌壓縮的時機不是真正基於設置的時間,而是日誌事件到達的時機,比如晚上23點30分到24點0分這段時間沒有任何日誌事件到來,那麼觸發日誌壓縮的時間點會是23點30分。
TimeBasedRollingPolicy配置實例:


logFile.log


logFile.%d{yyyy-MM-dd}.log

  <!-- keep 30 days' worth of history capped at 3GB total size -->
  <maxHistory>30</maxHistory>
  <totalSizeCap>3GB</totalSizeCap>

</rollingPolicy>

<encoder>
  <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>

SizeAndTimeBasedRollingPolicy

通過日期壓縮日誌文件的同時限制每個日誌文件的大小。

<configuration>
  <appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>mylog.txt</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
      <!-- rollover daily -->
      <fileNamePattern>mylog-%d{yyyy-MM-dd}.%i.txt</fileNamePattern>
       <!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->
       <maxFileSize>100MB</maxFileSize>    
       <maxHistory>60</maxHistory>
       <totalSizeCap>20GB</totalSizeCap>
    </rollingPolicy>
    <encoder>
      <pattern>%msg%n</pattern>
    </encoder>
  </appender>


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

</configuration>

FixedWIndowRollingPolicy

定長窗口回滾策略會根據每輪迴滾,修改日誌文件名,保持回滾日誌總數量,新文件按照fileNamePattern定義的名字新建,舊的日誌名進行滑動修改。

下面是FixedWindowRollingPolicy的一些屬性:

屬性名 屬性類型 描述
minIndex int 窗口索引的最小值
maxIndex Int 窗口索引的最大值
fileNamePattern String 代表FixedWindowRollingPolicy在更名日誌文件時使用的模式,必須包括%d,代表插入到當前窗口的索引位置。

例如,使用MyLogFile%i.log作爲模式,窗口最小值1,最大值3,經過三輪的回滾,那麼將會產生MyLogFile1.log,MyLogFile2.log以及MyLogFile3.log
壓縮選項也可以通過模式指定,比如將fileNamePattern設置爲MyLogFile%i.log.zip意味着壓縮文件將會被壓縮爲zip格式,gz格式也是支持的

大的窗口是不建議使用的,當窗口大於20時,現有的實現會將窗口縮小到20.

這裏有具體的例子,將窗口的minIndex設置爲1,maxIndex設置爲3,fileNamePattern屬性設置爲foo%i.log,file屬性設置爲foo.log

日誌回滾次數 日誌輸出目標 壓縮日誌文件 描述
0 foo.log - 沒有發生日誌回滾,直接輸出到foo.log
1 foo.log foo1.log 第一次回滾,foo.log更名爲foo1.log,一個新的foo.log文件被創建,併成爲輸出目標
2 foo.log foo1.log, foo2.log 第二輪迴滾,foo1.log更名爲foo2.log,foo.log更名爲foo1.log。新的foo.log創建,併成爲新的輸出目標
3 foo.log foo1.log foo2.log, foo3.log 第三輪迴滾,foo2.log更名爲foo3.log,foo1.log更名爲foo2.log,foo.log更名爲foo1.log。新的foo.log創建,併成爲日誌輸出目標
4 foo.log foo1.log,foo2.log,foo3.log 第四輪日誌回滾,刪除foo3.log,其他日誌文件將會依次遞增自己的文件名,新的日誌文件foo.log創建,併成爲輸出目標

FixedWindowRollingPolicy配置示例

<configuration>
  <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>test.log</file>

    <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
      <fileNamePattern>tests.%i.log.zip</fileNamePattern>
      <minIndex>1</minIndex>
      <maxIndex>3</maxIndex>
    </rollingPolicy>

    <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
      <maxFileSize>5MB</maxFileSize>
    </triggeringPolicy>
    <encoder>
      <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
    </encoder>
  </appender>
        
  <root level="DEBUG">
    <appender-ref ref="FILE" />
  </root>
</configuration>

Triggering policy

TriggeringPolicy實現負責在合適的時候讓RollingFileAppender進行日誌回滾

TriggeringPolicy接口只包括一個方法

package ch.qos.logback.core.rolling;

import java.io.File;
import ch.qos.logback.core.spi.LifeCycle;

public interface TriggeringPolicy<E> extends LifeCycle {

  public boolean isTriggeringEvent(final File activeFile, final <E> event);

}
isTriggeringEvent()方法接受日誌文件,以及日誌事件作爲參數,具體的實現決定了日誌回滾是否會發生。
最常用的日誌觸發策略是TimeBaseRollingPolicy,同時它也是一個回滾策略

SizeBasedTriggeringPolicy

SizeBasedTriggeringPolicy觀察當前日誌文件的大小,如果它的大小超過了特定大小,那麼它會釋放一個信號提示RollingFileAppender應該對現有的日誌文件進行一次回滾

SizeBasedTriggeringPolicy只接受一個參數,maxFileSize,默認大小爲10MB

可以自定義文件大小,比如5000000,5000KB,5MB和2GB等等

下面是RollingFileAppender配合使用SizebasedTriggeringPolicy的配置,它會讓日誌文件達到5MB的時候做一次回滾

<configuration>
  <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>test.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
      <fileNamePattern>test.%i.log.zip</fileNamePattern>
      <minIndex>1</minIndex>
      <maxIndex>3</maxIndex>
    </rollingPolicy>

    <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
      <maxFileSize>5MB</maxFileSize>
    </triggeringPolicy>
    <encoder>
      <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
    </encoder>
  </appender>
        
  <root level="DEBUG">
    <appender-ref ref="FILE" />
  </root>
</configuration>

此外還有ServerSocketAppender、SSLServerSocketAppender、SMTPAppender、DBAppender、SyslogAppender、SiftingAppender、AsyncAppender。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章