Files
rikako-note/spring/logback/logback.md
2024-08-06 21:35:24 +08:00

723 lines
30 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Logback
## Introduce
`logback-classic`模块需要classpath下存在`slf4j-api.jar`, `logback-core.jar`, `logback-classic.jar`
logback使用示例如下
```java
package chapters.introduction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HelloWorld1 {
public static void main(String[] args) {
Logger logger = LoggerFactory.getLogger("chapters.introduction.HelloWorld1");
logger.debug("Hello world.");
}
}
```
`HelloWorld1`类定义在`chapters.introduction`包下其引入了slf4j中的`Logger``LoggerFactory`类。
在上述示例中并没有引入任何logback的类在使用日志的大多数场景中只需要引入slf4j的api类即可。
## Logback Architecture
logback目前结构分为3个模块`logback-core``logback-classic``logback-access`
`logback-core`是其他两个模块的基础,`classic`模块拓展了`core`模块。`classic`模块实现了slf4j api因而在使用slf4j时可以在logback和其他日志系统之间轻松切换。而`access`模块和servlet容器做了集成可以通过http对日志进行访问。
### Logger, Appender, Layout
logback基于3个主要的类构成`Logger`, `Appender`, `Layout``Logger`类属于logback-classic模块Appender和Layout类则是属于logback-core模块。
#### Log Context
在logback-classic中每个logger都关联了一个`Log Context`log Context负责创建logger并且log context将创建的logger按照树状结构排列。
Logger都拥有名称其名称大小写敏感并遵循分层的命名规则
> 如果一个logger的名称其名称加上`.`后形成的字符串为另一个logger的前缀那么可称后一个logger是前一个logger的后代。如果一个logger和后代logger之间没有其他的logger那么可以称前一个logger是后一个logger的parent。
例如,名称为`"com.foo"`的logger是名称为`"com.foo.Bar"`的parent。
root logger是位于最顶层的logger其可以通过如下方式进行获取
```java
Logger rootLogger = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
```
其他所有的logger也可以通过`getLogger`方法进行获取该方法接收logger name来作为参数`Logger`接口具有如下方法:
```java
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都会被指定一个log levellevel可以是`TRACE, DEBUG, INFO, WARN, ERROR`中的一个,其定义在`ch.qos.logback.classic.Level`类中。如果指定logger没有被指定level那么其会从`离其最近并且被指定level的先祖logger`中继承level。
为了保证所有logger都可以继承levelroot logger一定会被指定log level。默认情况下level为`debug`
> log level顺序为
>
> `TRACE < DEBUG < INFO < WARN < ERROR`
#### 获取Logger
在通过`LoggerFactory.getLogger`获取logger对象时如果向方法传入相同的名称那么会获得相同的logger对象。
通常应在每个class中指定一个loggerlogger name为class的全类名。
#### Appender
在logback中允许将日志打印到多个目的地在logback中目的地被称为`Appender`。目前目的地可以是console、文件、remote socket server、数据库、JMS等。
对每个logger都可以关联不止一个Appender。
`addAppender`将会将Appender关联到指定的logger。每个被允许打印的log请求都会被发送到该logger关联的所有Appender中并且log请求还会被发送到树结构更高的Appender中。在logger结构中Appender是增量继承的后代logger会继承先祖logger的Appender。
如果为root logger指定一个console appender并且为L指定一个file appender那么对于L和L的后代logger打印日志的请求不仅会被发送到console还会被打印到文件中。
> 可以手动指定logger L增量继承appender的标志为false那么L和其所有后代logger都不会继承L先祖logger的appender。
>
> 默认情况下appender是否增量继承的标志默认值为true
#### Layout
如果想要指定日志打印的格式可以将Layout对象和logger相关联。`PatternLayout`可以通过c语言`printf`的格式来指定打印格式。
`PatternLayout`若指定conversion pattern为`%-4relative [%thread] %-5level %logger{32} - %msg%n`,其会按如下格式打印消息:
```
176 [main] DEBUG manual.architecture.HelloWorld2 - Hello world.
```
#### 参数化打印
可以通过如下形式来进行参数化打印
```java
Object entry = new SomeObject();
logger.debug("The entry is {}.", entry);
```
只有当前消息被评估应该打印时,才会通过消息模板来构造消息,将`{}`替换为entry的实际值。
## Logback Configuration
### logback配置顺序
1. 如果`logback.configurationFile`系统变量设置
2. 如果1步骤失败会尝试在classpath中寻找`logback-test.xml`
3. 如果2步骤失败会尝试在classpath中寻找`logback.xml`
> #### 通过命令行System Properties设置logback配置文件位置
> 可以通过向命令行传递`-Dlogback.configurationFile=/path/to/config.xml`来设置logback配置文件的位置
### 通过xml形式配置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} -%kvp- %msg%n</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="STDOUT" />
</root>
</configuration>
```
### 自动加载配置文件更新
logback支持对配置文件的变动进行扫描并且对扫描到的变动进行自动配置。为了令logback支持配置自动更新需要为`configuration`元素配置scan属性示例如下所示
```xml
<configuration scan="true">
...
</configuration>
```
在开启配置自动更新时,默认会每间隔`1 minute`就扫描配置变动。可以通过`scanPeriod`属性自定义扫描周期,周期单位可以是`milliseconds, seconds, minutes, hours`。示例如下所示:
```xml
<configuration scan="true" scanPeriod="30 seconds" >
...
</configuration>
```
> 如果在没有为scanPerod属性值指定单位时默认单位为ms
### xml配置文件语法
一个基础的xml配置文件可以包含如下结构
1. 一个`<configuration>`元素
1. 0或多个`<appender>`元素
2. 0或多个`<logger>`元素
3. 最多一个`<root>`元素
#### `<logger>`
`<logger>`元素用于配置logger其接收一个必填的`name`属性,一个可选的`level`属性,一个可选的`additivity`属性。
- `additivity`属性的值可以为true或者false。
- `level`属性的值可以为`TRACE, DEBUG, INFO, WARN, ERROR, ALL, OFF`,是大小写不敏感的。
- 如果想要从上级继承level可以将level属性的值设置为`INHERITED`或是`NULL`
`logger`元素中可以包含0个或多个`<appender-ref>`元素这样每个引用的appender都会被加入到logger中。
#### `<root>`
`root`元素用于配置root logger其只支持一个属性`level`。由于root元素已经被命名为`ROOT`,故而也不允许指定`name`属性。
`<root>`元素的`level`属性只能被赋值为`TRACE, DEBUG, INFO, WARN, ERROR, ALL, OFF`,不能被赋值为`INHERITED`或是`NULL`.
和logger元素一样root元素中也能包含0个或多个`<appender-ref>`元素。
```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} -%kvp- %msg%n</pattern>
</encoder>
</appender>
<logger name="chapters.configuration" 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>
```
#### `Appender`
`<appender>`元素用于配置Appender其接收两个必填属性`name``class`。其中,`name`属性指定了appender的名称`class`属性则是指定了appender Class的全类名。
`appender`元素可以包含0或多个`<layout>`元素0或多个`<encoder>`元素0或多个`<filter>`元素。除了可以包含上述公共元素外,还`appender`元素还可以包含任意数量javaBean属性相关的元素
#### `Layout`
`<layout>`元素接收一个必填`class`属性值为Layout类的全类名。和appender元素一样layout也可以包含javaBean属性相关的元素。如果layout class为`PatternLayout`那么class属性可以省略。
#### `encoder`
`<encoder>`元素接收一个必填的class属性值为Encoder的全类名。如果encoder类为`PatternLayoutEncoder`那么class属性可以省略。
当想要向多个appender中输出日志时只需要在logger中定义多个appender即可示例如下
```xml
<configuration>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>myApp.log</file>
<encoder>
<pattern>%date %level [%thread] %logger{10} [%file:%line] -%kvp- %msg%n</pattern>
</encoder>
</appender>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%kvp %msg%n</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="FILE" />
<appender-ref ref="STDOUT" />
</root>
</configuration>
```
上述配置中定义了两个appender`FILE``STDOUT``FILE` appender将日志打印到`myApp.log`文件中。`STDOUT` appender则是将日志打印到控制台。
root logger通过`<appender-ref>`标签来引用appender每个appender都有其自己的encoderencoder通常在appender之间并不共享。同样的layout也不会在多个appender之间共享。
> 由于logger不仅会将日志发送到其自身的logger并且还会将日志发送给其先祖logger的appender故而将相同的appender共享给拥有上下级关系的logger将会导致日志的重复打印。
可以通过设置`additivity`属性来设置后代logger不继承先祖logger的appender配置示例如下所示
```xml
<configuration>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>foo.log</file>
<encoder>
<pattern>%date %level [%thread] %logger{10} [%file : %line] -%kvp- %msg%n</pattern>
</encoder>
</appender>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%msg%n</pattern>
</encoder>
</appender>
<logger name="chapters.configuration.Foo" additivity="false">
<appender-ref ref="FILE" />
</logger>
<root level="debug">
<appender-ref ref="STDOUT" />
</root>
</configuration>
```
### 变量替换
可以以`${VAR_NAME}`的形式来使用变量替换,且`HOSTNAME``CONTEXT_NAME`变量是默认定义的。
如下示例展示了如何定义变量:
```xml
<configuration>
<variable name="USER_HOME" value="/home/sebastien" />
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>${USER_HOME}/myApp.log</file>
<encoder>
<pattern>%kvp %msg%n</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="FILE" />
</root>
</configuration>
```
变量除了可以在配置文件中定义还可以通过System Properties进行传递
```shell
java -DUSER_HOME="/home/sebastien" MyApp2
```
```xml
<configuration>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>${USER_HOME}/myApp.log</file>
<encoder>
<pattern>%kvp %msg%n</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="FILE" />
</root>
</configuration>
```
当存在多个变量时,可以单独为变量定义一个文件:
```xml
<configuration>
<variable 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>%kvp %msg%n</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="FILE" />
</root>
</configuration>
```
```properties
USER_HOME=/home/sebastien
```
除了通过`<variable>`元素的file属性指定变量文件位置外还可以通过`variable`元素的resource属性指定classpath下的文件路径
```xml
<configuration>
<variable resource="resource1.properties" />
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>${USER_HOME}/myApp.log</file>
<encoder>
<pattern>%kvp %msg%n</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="FILE" />
</root>
</configuration>
```
#### 变量作用域
一个变量可以被定义在如下作用域:
- LOCAL SCOPE: 具有local作用域的变量生命周期为从其文件定义该变量的位置开始一直到该配置文件的末尾
- CONTEXT SCOPE: 具有context作用域的变量在context存在期间一直存在直到context执行clear操作
- SYSTEM SCOPE: 具有system作用域的变量将会添加到jvm的system properties中生命周期和jvm相同直到该变量被清空
在变量替换时变量首先从local scope中查找其次到context scope中找再其次到system scope中找最后到os环境变量中找。
`<variable>`元素中可以含有`scope`属性,其值可以为`local`,`context``system`。如果没有指定scope属性默认是`local`
```xml
<configuration>
<variable scope="context" name="nodeId" value="firstNode" />
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>/opt/${nodeId}/myApp.log</file>
<encoder>
<pattern>%kvp %msg%n</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="FILE" />
</root>
</configuration>
```
在上述示例中,尽管`nodeId`变量被定义为context scope其在每个logging event中都可以使用。
#### 为变量赋值默认值
可以按`"${aName:-golden}"`的方式为指定返回的默认值当aName变量未定义时返回值为`golden`
#### 变量嵌套
在定义变量时,支持变量的嵌套:
```properties
USER_HOME=/home/sebastien
fileName=myApp.log
destination=${USER_HOME}/${fileName}
```
并且,表达式也支持嵌套变量:
`"${${userid}.password}"`表达式在`userid`变量为`asahi`的情况下,表示`asahi.password`变量的值
在为变量指定默认值时,默认值也可以通过变量来指定,例如`${id:-${userid}}`,在`id`变量未定义时,会返回`userid`变量的值。
### 条件处理配置文件
logback配置文件支持通过`<if>`,`<then>`,`<else>`元素来条件指定配置。条件处理需要`janino`库。
条件处理语法如下:
```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>
```
条件为java表达式且只允许访问system properties和context properties。`proerpty()`方法或`p()`方法将会返回变量的值,例如`p('k')``property('k')`将会返回变量`k`的值。如果`k`变量未定义,将会返回空字符串。
`isDefined`方法则是可以用来检查指定变量是否被定义。并且,可以通过`isNull`方法来检查指定变量的值是否为空。
```xml
<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} -%kvp- %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} -%kvp- %msg %n</pattern>
</encoder>
</appender>
<root level="ERROR">
<appender-ref ref="FILE" />
</root>
</configuration>
```
## Appender
logback把日志事件的写操作委托给了Appender组件。Appender必须实现`ch.qos.logback.core.Appender`接口,接口主要方法如下:
```java
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方法负责将日志输出到对应的输出设备。
appender是命名实体故而其可以通过name来进行引用。Appender实现了FilterAttachable接口故而可以将一个或多个filter关联到appender。
appender负责将日志事件打印到输出设备但是appender可以将日志的格式化操作委托给`Layout``Encoder`对象。每个layout或encoder都只会关联一个appender一些logger拥有内置的固定format格式对于用于内置固定format的appender其不需要encoder或layout。
> 例如SocketAppender并没有encoder或layout其只是将日志事件序列化并且通过网络传输序列化后的数据
### AppenderBase
`ch.qos.logback.core.AppenderBase`是一个实现了Appender接口的抽象类其针对appender中的部分接口提供了实现。logback中内置的所有apender实现都实现了该抽象类。
`AppenderBase`类实现了doAppend方法并留下了`append`方法供实现类进行实现。AppenderBase类中doAppend方法被synchronized修饰多线程环境下doAppend方法的调用是阻塞的。
### Logback Core
logback core是其他logback模块的基础。其内置了如下开箱即用的Appender。
#### OutputStreamAppender
`OutputStreamAppender`会将日志事件追加到`java.io.OutputStream`中,该类为其他基于`OutputSteamAppender`的appender提供了基础。
ConsoleAppender和FileAppender都继承了OutputStreamAppender。
#### ConsoleAppender
ConsoleAppender会将日志追加到console`System.out``System.err`中,前者是默认的目标设备。`ConsoleAppender`通过用户指定的`encoder`来对日志事件进行格式化。
ConsoleAppender拥有如下property
- encoder : `Encoder`类型
- target : 字符串类型,值为`System.out``System.err`
- withJansi : boolean类型默认为false、
如下为ConsoleAppender的使用示例
```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>%-4relative [%thread] %-5level %logger{35} -%kvp- %msg %n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="STDOUT" />
</root>
</configuration>
```
#### FileAppender
`FileAppender``OutputStreamAppender`的子类,将日志事件打印到文件中。目标文件通过`File`选项来指定,如果指定文件已经存在,是否清空文件内容或将日志追加到文件末尾,取决于`append`属性。
FileAppender拥有如下property
- append: boolean类型当文件已经存在时如果设置为true日志追加到文件末尾如果日志设置为false已存在文件的内容将会被清空。默认该属性被设置为true
- encoderEncoder类型
- file字符串类型为写入文件的文件名如果文件不存在那么文件会被创建。如果该路径值中存在不存在的目录FileAppender会自动创建目录。
- bufferSizeFileSize类型当immediateFlush属性被设置为false时可以通过bufferSize选项将会设置output buffer的大小。bufferSize的默认值为8192。在定义FileSize类型时可以按`KB, MB, GB`来指定,只需要以`5MB`形式指定即可。在没有指定后缀单位时,默认为字节
- prudent: 当prudent属性设置为true时会将`append`属性设置为true。prudent依赖与排他的file lock在开启prudent后写日志开销通常是prudent关闭开销的3倍。
> ##### Immediate flush
> 默认情况下每个log事件都会立即刷新到outputstream中这样可以避免日志的丢失如果日志刷新存在延迟那么应用在未刷新的情况下当即可能会使缓存中的日志丢失
>
> 当时,如果要提高吞吐量,可以将`immediateFlush`property设置为false。
配置示例如下所示:
```xml
<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} -%kvp- %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="FILE" />
</root>
</configuration>
```
##### `<timestamp>`
对于短期应用,可能会期望在每次程序运行时,都创建唯一的日志文件。可以通过`<timestamp>`元素来实现该需求,示例如下:
```xml
<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} -%kvp- %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="FILE" />
</root>
</configuration>
```
timestamp元素接收两个必填属性`key``datePattern`,并接收一个非必填的属性`timeReference`
- datePattern 格式和`SimpleDateFormat`相同
- timeReference : 默认情况下timestamp元素的值为当前配置文件被解析的事件也可以将其设为`contextBirth`即context创建时间
#### RollingFileAppender
`RollingFileAppender`继承了FileAppender并且支持了滚动日志的能力。RollgingAppender拥有如下子组件
- `RollingPolicy`:负责如何执行日志滚动操作
- `TriggeringPolicy`:负责决定是否/何时出发日志滚动
RollingFileAppender同时需要RollingPolicy和TriggerPolicy组件但是如果RollingPolicy实现了TriggerPolicy接口那么只需要RollingPolicy即可。
如下是RollingFileAppender的属性
- file: 值为String类型如果日志只被写到RollingPolicy指定的目标设备那么file属性可以为空
- append是否追加
- encoder同FileOutputStream
- rollingPolicy值为`RollingPolicy`类型
- triggeringPolicy值为`TriggeringPolicy`类型
- prudent
##### RollingPolicy
`RollingPolicy`负责日志滚动过程,其中涉及文件移动和重命名。
RollingPolicy接口展示如下
```java
package ch.qos.logback.core.rolling;
import ch.qos.logback.core.FileAppender;
import ch.qos.logback.core.spi.LifeCycle;
public interface RollingPolicy extends LifeCycle {
public void rollover() throws RolloverFailure;
public String getActiveFileName();
public CompressionMode getCompressionMode();
public void setParent(FileAppender appender);
}
```
其中,各方法代表含义如下:
- rollober: 将当前日志文件归档
- getActiveFileName计算当前日志文件的文件名实时日志将会被写入到其中
- getCompressionMode: 决定压缩模式
- setParent设置关联的FileAppender
##### TimeBasedRollingPolicy
TimeBasedRollingPolicy是最常用的rollingPolicy其基于时间来执行滚动操作可以通过其设置按天或按月滚动。
TimeBasedRollingPolicy同时实现了RollingPolicy和TriggeringPolicy接口。
TimeBasedRollingPolicy接收一个必填的`fileNamePattern`参数,并且拥有可选填参数:
- `fileNamePattern`: 该属性定义了已经被滚动(已被归档)文件的文件名,该属性的应该含有文件名,并且在适当位置加上`%d转换说明符`(%d{yyyy-MM-dd})。
> ##### %d转换说明符
> %d转换说明符包含一个date-and-time格式的字符串该格式和SimpleDateFormat相同。如果该date-and-time被省略那么默认为yyyy-MM-dd.
>
> 可以在fileNamePattern中含有多个%d转换说明符但是只能有一个`主%d转换说明符`,主%d转换说明符用于推断滚动周期。其他说有的%d转换说明符都需要通过`aux`来进行修饰(`%d{yyyy/MM, aux}`)。
>
> 示例如下
>
> `/var/log/%d{yyyy/MM, aux}/myapplication.%d{yyyy-MM-dd}.log`.
滚动周期的值将会从date-and-time表达式来推断。
RollingFileAppender中file属性可以被省略或设置为null。如果为RollingFileAppender设置了file属性那么可以解耦当前日志和已经被归档的日志。如果file属性的值那么当前日志路径就是file文件的值此时当前日志的路径不会随着日期的变动而改变。
但是在省略file属性的情形下那么当前日志文件路径将会根据fileNamePattern来计算
- `maxHistory`: `maxHistory`指定了保留归档日志的最大数量,会对旧日志进行异步删除。
如果将maxHistory设置为0将会禁用旧日志删除。默认情况下maxHistory被设置为0。
- `totalSizeCap``totalSizeCap`控制了所有归档日志文件的最大大小,当最大小超过阈值时,最老的文件将会被删除。`totalSizeCap`需要`maxHistory`属性也被设置通常totalSizeCap都在maxHistory之后被应用。
默认情况下totalSizeCap被设置为0代表不会有总大小的阈值限制。
- `cleanHistoryOnStart`如果该属性被设置为true当appender启动时归档日志将会被清除。
TimeBasedRollingPolicy支持文件自动压缩如果`fileNamePattern`后缀以`.gz``.zip`结尾,文件压缩将会自动被应用。
示例如下
```
/wombat/foo.%d.gz
```
上述示例当前日志被输出到`/wombat/foo.yyyy-MM-dd`文件中,但是在第二天触发归档后,文件将会被压缩到`/wombat/foo.yyyy-MM-dd.gz`中。
TimeBasedRollingPolicy示例如下
```xml
<configuration>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logFile.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- daily rollover -->
<fileNamePattern>logFile.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 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} -%kvp- %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="FILE" />
</root>
</configuration>
```
#### SizeAndTimeBasedRollingPolicy
SizeAndTimeBasedRollingPolicy支持配置单个日志文件的最大大小其除了支持%d转换符外还支持%i转换符%i转换符也是必填的。每当当前日志文件达到最大文件大小时其都会递增`%i`序列号并且旧日志文件将会被归档。序列号从0开始。
SizeAndTimeBasedRollingPolicy还包含如下属性
- `maxFileSize`:每当当前日志文件达到`maxFileSize`指定的大小时其都会递增序列号序列号默认为0.
maxFileSize为FileSize类型可以通过`KB, MB, GB`等单位来指定。
- `checkIncrement`检查当前日志文大小的间隔时间默认为60s
```xml
<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>
```
#### Encoder
通常PatternLayoutEncoder其pattern可以指定为如下形式
```xml
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<Pattern>
%d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M - %msg%n
</Pattern>
</encoder>
```