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
-
Appender控制日誌輸出方式,可以輸出到控制檯、文件、遠程socket服務器、MySQL、PostgreSQL、Oracle以及其他數據庫、JMS、遠程Unix系統日誌
-
多個appender可以附加到一個logger上,一個給定的logger接收到日誌請求後,它會將請求轉發到它下面的appender以及繼承層次更高的appender之上。Appenders也具有繼承性。舉個例子,一個控制檯輸出的appender加入到root logger下面,那麼所有有效日誌請求都會輸出到控制檯。如果文件appender加入到logger A,那麼A以及A的孩子,在收到日誌請求後,會將日誌輸出到文件以及控制檯上
-
通過設置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配置尋找
- classpath下的logback.xml
- classpath下的logbac.groovy
- classpath下的logback.xml
- 通過service-provider loading facility來解析com.qos.logback.classic.spi.Configuration接口實現,這個實現的全名稱配置在META-INF\services\ch.qos.logback.classic.spi.Configurator裏面
- 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。