SpringBoot自定义logback日志配置

目录
  1. 1. 一、application.properties系统配置logback日志
    1. 1.1. 1.1、SpringBoot默认的日志配置
    2. 1.2. 1.2、添加依赖
    3. 1.3. 1.3、application.properties简单配置日志相关属性
    4. 1.4. 1.4、两种配置方式总结
  2. 2. 二、自定义日志配置logback-spring.xml
    1. 2.1. 2.1、日志记录框架的默认自定义配置文件名称
    2. 2.2. 2.2、SpringBoot推荐使用logback-spring.xml
    3. 2.3. 2.3、logback配置文件的节点属性简介
  3. 3. 三、<springProfile>多环境输出日志文件
  4. 4. 四、 解决 logback.xml 配置文件不生效的问题
  5. 5. 五、 不同的包(业务日志)输出到不同日志文件
    1. 5.1. 1. 定义日志输出文件
    2. 5.2. 2. 定义logger
    3. 5.3. 3. 定义logger变量
    4. 5.4. 4. 记录日志

前言:默认情况下,SpringBoot内部使用logback作为系统日志实现的框架,将日志输出到控制台,不会写到日志文件。如果在application.properties或application.yml配置,这样只能配置简单的场景,保存路径、日志格式等。复杂的场景(区分 info 和 error 的日志、每天产生一个日志文件等)满足不了,只能自定义配置文件logback-spring.xml。

一、application.properties系统配置logback日志

1.1、SpringBoot默认的日志配置

日志记录器(Logger)的行为是分等级的,日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出。

默认情况下,SpringBoot内部使用logback作为系统日志实现的框架,将日志输出到控制台,不会写到日志文件。Spring boot从控制台打印出来的日志级别默认只有INFO及以上级别,可以在application.properties中修改日志级别logging.level.root=WARN。

SpringBoot默认配置好了日志, 只要启动 Spring Boot 项目就会在控制台输出日志信息。

 从上图可以看到,日志输出的内容如下:

  • 时间日期:精确到毫秒
  • 日志级别:ERROR,WARN,INFO,DEBUG,TRACE
  • 进程ID
  • 分隔符:— 标识实际日志的开始
  • 线程名:方括号括起来(可能会截断控制台输出)
  • Logger名:通常使用源代码的类名
  • 日志内容

控制台格式化输出内容:

1
2
# 格式化,只输出日期和内容
logging.pattern.console= "%d -%p -%m" %n

打印参数: Log4J采用类似C语言中的printf函数的打印格式格式化日志信息,如下:

%m       输出代码中指定的消息
%p       输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL
%r       输出自应用启动到输出该log信息耗费的毫秒数
%c       输出所属的类目,通常就是所在类的全名
%t       输出产生该日志事件的线程名
%n       输出一个回车换行符,Windows平台为“\\r\\n”,Unix平台为“\\n”
%d       输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如%d{yyy MMM dd HH:mm:ss,SSS},输出类似:2018年6月15日22:10:28,921
%l       输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。举例:estlog4.main(TestLog4.java: 10)

1.2、添加依赖

Spring Boot为我们提供了很多默认的日志配置,所以,只要将spring-boot-starter-logging作为依赖加入到pom.xml,则“开箱即用”。实际开发中我们不需要直接添加该依赖,你会发现spring-boot-starter其中包含了 spring-boot-starter-logging,该依赖内容就是 Spring Boot 默认的日志框架 logback。

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>

1.3、application.properties简单配置日志相关属性

下面介绍几种在application.properties就可以配置的日志相关属性。

(1)控制台输出

Spring Boot中默认配置INFO、WARN和ERROR级别的日志只输出到控制台。

我们可以在application.properties中修改日志级别logging.level.root=WARN,这样核心Logger(包含嵌入式容器、hibernate、spring)会输出更多内容,还有自己应用的日志就会输出为DEBUG级别。

(2)文件输出

①使用application.properties默认配置

默认情况下,Spring Boot将日志输出到控制台,不会写到日志文件。如果要编写除控制台输出之外的日志文件,则需在application.properties中设置logging.file或logging.path属性。

  • logging.file:设置文件,可以是绝对路径,也可以是相对路径。如:logging.file=my.log

  • logging.path:设置目录,会在该目录下创建spring.log文件,并写入日志内容,如:logging.path=/var/log

如果只配置 logging.file,会在项目的当前路径下生成一个 xxx.log 日志文件;

如果只配置 logging.path,在 /var/log文件夹生成一个日志文件为 spring.log。

注:二者不能同时使用,如若同时使用,则只有logging.file生效

默认情况下,日志文件的大小达到10MB时会切分一次,产生新的日志文件,默认级别为:ERROR、WARN、INFO。

②使用logback-spring.xml自定义配置

如果在application.propertiesapplication.yml配置,这样只能配置简单的场景,保存路径、日志格式等。复杂的场景(区分 info 和 error 的日志、每天产生一个日志文件等)满足不了,只能自定义logback配置,SpringBoot官方推荐使用logback-spring.xml作为logback框架的自定义日志配置文件。

1.4、两种配置方式总结

SpringBoot工程自带 logback和 slf4j的依赖,所以重点放在编写配置文件上:

  • application.properties或 application.yml (系统层面)

  • logback-spring.xml(自定义文件方式)

第一种方式比较简单,可做的事情也比较简单,比如:只能配置日志文件的输出路径、日志文件的格式、日志的级别等。

第二种方式比较复杂,对日志的处理比较好,生产上推荐这种,运行维护好。如有以下需求:
a、区分 debug、info、error 等类型的日志,并分别输出到不同的日志文件。
b、对日志文件进行维护,如每天产生一个日志文件,并设置日志文件的大小和保留天数等。

二、自定义日志配置logback-spring.xml

由于日志服务一般都在ApplicationContext创建前就初始化了,它并不是必须通过Spring的配置文件控制。因此通过系统属性和传统的Spring Boot外部配置文件依然可以很好的支持日志控制和管理。在类路径下放置自定义日志配置xml文件,SpringBoot就不会使用它本身的默认日志配置了。

2.1、日志记录框架的默认自定义配置文件名称

下图是SpringBoot官方文档的提示内容,意思是:根据您的日志记录系统,将加载相应的文件使用。即如果我们使用logback日志框架,那么可以使用logback-spring.xml、logback-spring.groovy、logback.xml、logback.groovy之一作为配置文件来加载。

根据不同的日志系统,你可以按如下规则组织配置文件名,并且放在src/main/resources下面就能被正确加载:

  • Logback:logback-spring.xml, logback-spring.groovy, logback.xml, logback.groovy
  • Log4j:log4j-spring.properties, log4j-spring.xml, log4j.properties, log4j.xml
  • Log4j2:log4j2-spring.xml, log4j2.xml
  • JDK (Java Util Logging):logging.properties

2.2、SpringBoot推荐使用logback-spring.xml

SpringBoot官方推荐使用logback-spring.xml作为logback框架的自定义日志配置文件(例如:使用logback-spring.xml而不是logback.xml),因为带-spring后缀的配置文件可以使用SpringBoot提供的一些高级功能,如profile多环境日志输出。

将所有日志都存储在一个文件中文件大小也随着应用的运行越来越大并且不好排查问题,正确的做法应该是将 error日志和其他系统输出日志分开,并且不同级别的日志根据时间段进行记录存储。

在 src/main/resources 下创建 logback-spring.xml 文件,分开记录系统输出日志和Error日志:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml" />

<!--彩色日志输出格式-->
<property name="CONSOLE_LOG_PATTERN" value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%level){blue} %clr(${PID}){magenta} %clr([%thread]){orange} %clr(%logger){cyan} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
<!--非彩色日志输出格式-->
<property name="PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n" />

<!--dev文件路径:src同级目录logs,如果上级目录不存在会自动创建-->
<property name="DEV_FILE_PATH" value="./logs" />
<!-- pro文件路径 -->
<property name="PRO_FILE_PATH" value="/opt/prod/logs" />

<!-- appender是configuration的子节点,是负责写日志的组件。 -->
<!-- ConsoleAppender:把日志输出到控制台 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- 默认情况下,每个日志事件都会立即刷新到基础输出流。 这种默认方法更安全,因为如果应用程序在没有正确关闭appender的情况下退出,则日志事件不会丢失。
但是,为了显着增加日志记录吞吐量,您可能希望将immediateFlush属性设置为false -->
<!--<immediateFlush>true</immediateFlush>-->
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
<!-- 控制台也要使用UTF-8,不要使用GBK,否则会中文乱码 -->
<charset>UTF-8</charset>
</encoder>
</appender>

<!-- RollingFileAppender:滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 -->
<!-- 以下的大概意思是:1.先按日期存日志,日期变了,将前一天的日志文件名重命名为XXX%日期%索引,新的日志仍然是project_info.log -->
<!-- 2.如果日期没有发生变化,但是当前日志的文件大小超过10MB时,对当前日志进行分割 重命名-->
<appender name="fileAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--日志文件路径和名称-->
<!-- <File>logs/project_info.log</File> -->
<!--是否追加到文件末尾,默认为true-->
<!-- <append>true</append> -->
<encoder>
<!--格式化输出:%d表示日期,%thread表示线程,%-5level:级别从左显示五个字符宽度,%logger{36}:logger是class的全名,后面的数字代表限制最长的字符,
%msg:日志消息,%n换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
<!--滚动策略按照时间滚动-->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 日志文件的名字会根据fileNamePattern的值,每隔一段时间改变一次 -->
<fileNamePattern>${DEV_FILE_PATH}/output-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
<!-- each file should be at most 10MB, keep 60 days worth of history, but at most 1GB -->
<!--单个文件大小,默认值是10MB-->
<maxFileSize>10MB</maxFileSize>
<!--日志文件保留天数-->
<maxHistory>60</maxHistory>
<!--用来指定日志文件的上限大小,到了这个值就会删除旧日志,哪怕没到60天也要删除多余的日志 -->
<totalSizeCap>1GB</totalSizeCap>
</rollingPolicy>
</appender>

<!-- 按照每天生成错误日志文件 -->
<appender name="errorAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 此日志文件只记录ERROR级别的 -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
<!--输出日志到src同级目录logs中的error.log文件中-->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!--基于大小和时间的轮转策略,当日志内容超出文件大小限制后,会自动生成一个文件来继续记录和重命名-->
<fileNamePattern>${DEV_FILE_PATH}/error-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
<!-- each file should be at most 10MB, keep 60 days worth of history, but at most 1GB -->
<maxFileSize>10MB</maxFileSize>
<maxHistory>60</maxHistory>
<totalSizeCap>1GB</totalSizeCap>
</rollingPolicy>
</appender>

<!--开发环境:打印控制台-->
<springProfile name="dev">
<root level="INFO">
<appender-ref ref="consoleAppender" />
<appender-ref ref="fileAppender" />
<appender-ref ref="errorAppender" />
</root>
</springProfile>

<!--生产环境:输出到文件-->
<springProfile name="pro">
<!-- root日志以INFO级别输出,指定日志信息输出到哪个地方-->
<root level="INFO">
<appender-ref ref="consoleAppender" />
<appender-ref ref="fileAppender" />
<appender-ref ref="errorAppender" />
</root>
</springProfile>

</configuration>

输出结果:

非彩色日志:

彩色日志:

2.3、logback配置文件的节点属性简介

Appender是负责写日志的组件,设置日志信息的去向,常用的有以下几个:

  • ch.qos.logback.core.ConsoleAppender (控制台)
  • ch.qos.logback.core.rolling.RollingFileAppender (文件大小到达指定尺寸的时候产生一个新文件)
  • ch.qos.logback.core.FileAppender (文件)

其中,<springProfile> 标签的 name 属性对应 application.properties 中的 spring.profiles.active 的配置。即 spring.profiles.active 的值可以看作是日志配置文件中对应的 springProfile 是否生效的开关。

(1) logger

用来设置某一个包或者具体的某一个类的日志打印级别、以及指定appender。logger仅有一个name属性,一个可选的level和一个可选的additivity属性。

  • name:用来指定受此logger约束的某一个包或者具体的某一个类。
  • level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,还有一个特殊值INHERITED或者同义词NULL,代表强制执行上级的级别。如果未设置此属性,那么当前logger将会继承上级的级别。
  • additivity:是否向上级logger传递打印信息。默认是true。

logger可以包含零个或多个appender-ref元素,标识这个appender将会添加到这个logger。

(2)root

也是logger元素,但是它是根logger。只有一个level属性,因为已经被命名为”root”。

  • level:用来设置打印级别,大小写无关:TRACE,DEBUG,INFO,WARN,ERROR,ALL和OFF,不能设置为INHERITED或者同义词NULL。默认是DEBUG。

root可以包含零个或多个appender-ref元素,标识这个appender将会添加到这个logger。rootLogger指定日志信息输出到哪个地方,可以同时指定多个输出目的地。

三、<springProfile>多环境输出日志文件

SpringBoot官方建议使用logback-spring.xml作为logback框架的自定义日志配置文件,使用logback-spring.xml而不是logback.xml,因为带-spring后缀的配置文件可以使用使用Spring扩展profile支持,提供profile多环境日志输出得功能。

Logback 配置文件中的 <springProfile>节点指令允许您根据配置文件激活参数(active) 选择性的包含和排查部分配置信息。根据不同环境来定义不同的日志输出,在 logback-spring.xml中使用 <springProfile>节点来定义,方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<!-- 测试环境+开发环境. 多个使用逗号隔开. -->
<springProfile name="test,dev">

<!--用来设置某一个包或者具体的某一个类的日志打印级别,可以让控制台输出debug-->
<logger name="com.hs" level="debug" />

<!-- 利用logback输入mybatis的sql日志,additivity=false代表禁止默认累计的行为,即com.sailing.springbootmybatis.mapper中的日志只会记录到日志文件中
如果不加 additivity="false" 则此logger会将输出转发到自身以及祖先的logger中,就会出现日志文件中sql重复打印-->
<logger name="com.sailing.springbootmybatis.mapper" level="DEBUG" additivity="false">
<appender-ref ref="INFO_FILE"/>
<appender-ref ref="ERROR_FILE"/>
</logger>

<!--
root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性,可以包含零个或多个appender元素。
-->
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="INFO_FILE" />
<appender-ref ref="WARN_FILE" />
<appender-ref ref="ERROR_FILE" />
</root>
</springProfile>

<!--生产环境:输出到文件-->
<springProfile name="pro">
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="DEBUG_FILE" />
<appender-ref ref="INFO_FILE" />
<appender-ref ref="ERROR_FILE" />
<appender-ref ref="WARN_FILE" />
</root>
</springProfile>

为何root配置的INFO,logger特殊指定的包/类日志DEBUG级别,最后也能打印出来?

答案:因为没有设置addtivity="false" ,如下即可。

1
<logger name="包名/类名" level="DEBUG" addtivity="false" />

logger有一个属性addtivity="true" 默认就是true,标识向上级传递日志(INFO是DEBUG的上级)。只有显示指定为false时,才不会向上级输出。

(1)可以启动服务的时候指定 profile (如不指定使用默认),如指定prod 的方式为:

java -jar xxx.jar –spring.profiles.active=prod

(2)也可以在yml配置文件中指明当前环境是什么环境,否则启动会报错,如下:

四、 解决 logback.xml 配置文件不生效的问题

问题描述:在resources目录下建立logback-spring配置文件后,只能打印控制台日志,不能创建日志文件。疯狂修改配置文件的内容,就连常用的重启、清除缓存都试过了,但是日志配置依然不生效。所以就查找原因,既然不是配置文件内部的问题,那就是配置文件根本就没起效果。

原因追溯:意外发现SpringBoot项目打包后的target/classes没有包含logback-spring.xml,这就是logback.xml 配置不起作用的根本原因。

 然后发现之前在pom.xml中加了个resources目录下文件的过滤配置,没有保留logback日志文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!--添加打包过滤的配置文件规则,定义资源过滤,用来保证配置文件打包生成到target中-->
<resources>
<resource>
<directory>src/main/resources</directory>
<!-- 开启过滤替换功能,用于替换resources里的变量-->
<filtering>true</filtering>
<!--按需保留需要的profile文件-->
<includes>
<include>application-${spring.profiles.active}.yaml</include>
<include>application.properties</include>
<include>application.properties</include>
</includes>
</resource>
</resources>

解决方案:保留logback-spring.xml和logback.xml配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!--添加打包过滤的配置文件规则,定义资源过滤,用来保证配置文件打包生成到target中-->
<resources>
<resource>
<directory>src/main/resources</directory>
<!-- 开启过滤替换功能,用于替换resources里的变量-->
<filtering>true</filtering>
<!--按需保留需要的profile文件-->
<includes>
<include>application-${spring.profiles.active}.yaml</include>
<include>application.properties</include>
<include>application.properties</include>
<include>logback.xml</include>
<include>logback-spring.xml</include>
</includes>
</resource>
</resources>

现在target-classes下有了logback.xml配置文件,相关日志正常生效。

五、 不同的包(业务日志)输出到不同日志文件

1. 定义日志输出文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!-- 业务日志输出 -->
<appender name="biz_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- <file>${log.path}/biz_info.log</file> -->
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/biz-info.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志保留最大60个 -->
<maxHistory>60</maxHistory>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>

maxHistory: 参数表示保留日志文件的最大个数
{yyyy-MM-dd}: 参数表示按天分割文件,{yyyy-MM-dd-HH}表示按小时分割文件。因为时间格式化出来的字符串和之前的字符串不相同,则重新生成一个文件。此时生成文件名中,还需要增加-%i
cleanHistoryOnStart:设置为true,表示启动的时候清除多余的日志。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<!-- 日志存放路径 -->
<property name="log.path" value="log/posonline/" />
<!-- 日志输出格式 -->
<property name="log.pattern"
value="%d{yyyy-MM-dd HH:mm:ss.SSS} - [%25.25(%thread)] - [%-5level] - %-30.30(%logger{30}) : %msg%n" />

<!-- 业务日志输出 -->
<appender name="biz_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- <file>${log.path}/biz_info.log</file> -->
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -%i -->
<fileNamePattern>${log.path}/biz-info.%d{yyyy-MM-dd}-%i.log</fileNamePattern>
<!-- 日志保留最大 60个 -->
<maxHistory>60</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>

timeBasedFileNamingAndTriggeringPolicy:按文件大小进行切分。

2. 定义logger

1
2
3
4
<!--业务日志-->
<logger name="biz_info" level="info" additivity="false">
<appender-ref ref="biz_info"/>
</logger>

 additivity="false"表示这里的日志不写入root对应的logger。

3. 定义logger变量

1
private static final Logger log = LoggerFactory.getLogger("biz_info");

需要记录日志的类,定义logger变量。

4. 记录日志

1
log.info("列表显示");

按照正常的方式记录日志即可。

参考链接:
Springboot日志框架Logback的使用及配置
SpringBoot配置logback - 云+社区 - 腾讯云
logback日志配置(控制台日志、输出日志、错误日志)
Springboot-logbackc彩色日志配色方案
Logback日志这样配置,让你性能提升10倍!