关于SpringBoot中的日志配置

一. 常用日志框架

日志作为线上问题追踪、业务逻辑统计分析的必要组成成分,在BS应用中必不可少。目前常用的Java日志框架主要包含Log4j,Log4j 2,Commons Logging,Slf4j,Logback,Jul:

  • log4j: Apache Log4j是一个基于Java的日志记录工具。它是由Ceki Gülcü首创的,现在则是Apache软件基金会的一个项目。 Log4j是几种Java日志框架之一
  • log4j2: Apache Log4j 2是apache开发的一款Log4j的升级产品
  • commons-logging: Apache基金会所属的项目,是一套Java日志接口,之前叫Jakarta Commons Logging,后更名为Commons Logging
  • slf4j: (Simple Logging Facade for Java) 它是一个针对于各类Java日志框架的统一Facade抽象, 不是具体的日志解决方案,它只服务于各种各样的日志系统
    【slf4j配合log4j、logback进行使用,可以理解为slf4j是标准,log4j和logback是实现】
  • logback: 一套日志组件的实现(slf4j阵营),新一代日志框架,它效率更高、能够适应诸多的运行环境,同时天然支持SLF4J
  • jul :(Java Util Logging),自Java1.4以来的官方日志实现

二. springBoot中的日志

Spring Boot在所有内部日志中使用Commons Logging,但是默认配置也提供了对常用日志的支持,如:Java Util Logging,Log4J, Log4J2和Logback。每种Logger都可以通过配置使用控制台或者文件输出日志内容。

默认情况下,Spring Boot会用Logback来记录日志,并用INFO级别输出到控制台。
下述内容,将以logback为例,简述springboot中日志的配置。

1. 添加日志依赖

logback其依赖的jar包含:slf4j-api-1.6.0.jar、logback-core-0.9.21.jar、logback-classic-0.9.21.jar、logback-access-0.9.21.jar

1
2
3
4
5
<!-- 实际开发中我们不需要直接添加该依赖, spring-boot-starter中已包含 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-logging</artifactId>
</dependency>

2. 属性文件配置

spring-boot-starter-logging已提供了开箱即用的起步配置,除此之外,我们还可以进行一些自定义配置

1
2
3
4
5
6
7
8
9
10
11
#logging.file与logging.path不可同时使用,否则仅前者会失效
# 日志文件名称,默认为spring.log
logging.file=dyportalserver
# 日志文件目录
logging.path=C://log//dyportalserver

#对指定包、类进行打印级别设置
logging.level.com.dayang=DEBUG
logging.level.root=WARN
#引入不满足日志配置文件命名规范的文件
logging.config=classpath:logging-config.xml

3. 自定义日志配置

根据不同的日志框架,需要按照指定的命名规则,才能正确的被spring加载:

  • 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

三. 关于logback文件的配置

Spring Boot官方推荐优先使用带有-spring的文件名作为你的日志配置(如使用logback-spring.xml,而不是logback.xml),命名为logback-spring.xml的日志配置文件,spring boot可以为它添加一些spring boot特有的配置项

1. 主要的节点

  • configuration:根节点,包含scan、scanPeriod、debug三个属性
  • scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true
  • scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟
  • debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false
  • property:configuration的子节点,用于定义变量值,包含name、value两个属性
  • logger:configuration的子节点,用来设置某一个包或者具体的某一个类的日志打印级别
  • name:(必选) 受此logger约束的某一个包或者具体的某一个类的全路径
  • level:打印级别,大小写无关
  • addtivity:是否向上级logger传递打印信息。默认是true
    可以包含零个或多个元素,标识这个appender将会添加到这个logger)
  • root:configuration的子节点,也是元素,但是它是根logger,只有level属性
  • appender:configuration的子节点,用于定义一个日志输出格式(打印地方、输出样式)
  • name:该appender的唯一标识
  • class:该appender类实例的完整类名称(即appender的类型)
  • ConsoleAppender:输出到控制台
  • RollingFileAppender【常用】:滚动记录文件(记录到文件,打到指定条件(时间,大小),转移到另一个文件)
  • FileAppender:输出到文件
  • SocketAppender/SSLSocketAppender:输出日志到远程实例(明码/加密)
  • ServerSocketAppender/SSLSeverSocketAppender:被动连接远程日志服务器(它监听来自客户端的连接请求)
  • SMTPAppender: 邮件发送
  • DBAppender:可以将日志事件插入到3张数据表中:logging_event,logging_event_property,logging_event_exception

2. 一个控制台输出appender示例

1
2
3
4
5
6
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
       <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
       <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
    </encoder>
</appender>

3. 一个错误日志文件appender示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<appender name="error_file" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>ERROR</level>
        </filter>
                <!-- 日志文件名称 -->
        <File>${LOG_PATH}/error.log</File>
                <!-- 滚动策略 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_PATH}/error-%d{yyyyMMdd}.log.%i
            </fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>500MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <maxHistory>2</maxHistory>
        </rollingPolicy>
                <!-- 编码格式 -->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} -%msg%n</Pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
    </appender>

4. logger配置示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- 子节点2:root【用来指定最基础的日志输出级别(必选)】只有一个level属性 -->
    <root level="info">
        <appender-ref ref="info_file" />
        <appender-ref ref="error_file" />
    </root>
       <root level="error">
        <appender-ref ref="error_file" />
    </root>     
    <!-- 子节点3:logger 【用来设置某一个包或者具体的某一个类的日志打印级别、以及指定<appender>】
              - name(必选):受此logger约束的某一个包或者具体的某一个类
              - level:打印级别,大小写无关
              - addtivity:是否向上级logger传递打印信息。默认是true
     -->
    <logger name="com.dayang" level="DEBUG">
              <appender-ref ref="console" />
       </logger>

5. 一个TimeBasedRollingPolicy滚动策略详解

1
2
3
4
5
6
7
8
9
10
11
<!—基于时间的滚动策略 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
     <!—yyyyMMdd表示滚动频率为一天 -->
    <fileNamePattern>${LOG_PATH}/info-%d{yyyyMMdd}.log.%i</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!—单个文件最大大小为500M-->
        <maxFileSize>500MB</maxFileSize>
     </timeBasedFileNamingAndTriggeringPolicy>
       <!—最长保留30天->
     <maxHistory>30</maxHistory>
</rollingPolicy>

四. 项目实践

1. application配置

  • application.properties配置

    1
    2
    3
    4
    5
    6
    ######################## 日志相关配置   ##############################
    # 日志文件目录
    logging.path=C://log//dyportalserver
    logging.level.com.dayang=info
    # 日志文件名称,默认为spring.log
    logging.config=classpath:logback-spring.xml
  • application-dev.properties配置
    实现生产环境info级别,开发环境debug级别

    1
    2
    3
    ######################## 日志相关配置   ##############################
    # 日志级别修改
    logging.level.com.dayang=info

    2. Logback配置

  • 单个日志文件大小:10M

  • 日志文件最大留存天数:2天

  • 本地留存日志最大大小1G 【2、3两要求取交集】

  • 日志打印级别读取动态配置。默认为debug

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
95
96
97
98
99
100
101
102
<?xml version="1.0" encoding="UTF-8"?>
<!-- 根节点configuration:
     - scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true
     - scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟
     - debug:当此属性设置为true时,将打印出<u>logback</u>内部日志信息,实时查看<u>logback</u>运行状态。默认值为false
 -->
<configuration  scan="true" scanPeriod="60 seconds" debug="false">
     <!-- 上下文名称contextName,默认为default -->
    <contextName><u>logback</u></contextName>
    <!-- 定义变量值property(变量会被插入logger上下文,可以通过${}形式获取)-name:变量名称 value:变量值  -->
     <!-- 读取application.properties文件中的logging.path配置值 -->
     <springProperty scope="context" name="LOG_PATH" source="logging.path" defaultValue="C://log/dyportalserver"/>
     <springProperty scope="context" name="LOG_lEVEL" source="logging.level.com.dayang" defaultValue="DEBUG"/>
    <!--子节点1:appender【格式化日志输出节点】
      - name:名称
      - class:输出策略,有如下几种
      - ConsoleAppender:输出到控制台
      - RollingFileAppender【常用】:滚动记录文件(记录到文件,打到指定条件(时间,大小),转移到另一个文件)
      - FileAppender:输出到文件
      - SocketAppender/SSLSocketAppender:输出日志到远程实例(明码/加密)
      - ServerSocketAppender/SSLSeverSocketAppender:被动连接远程日志服务器(它监听来自客户端的连接请求)
      - SMTPAppender:邮件发送
      - DBAppender:可以将日志事件插入到3张数据表中:logging_event,logging_event_property,logging_event_exception     
    -->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%<u>msg</u>:日志消息,%n是换行符 %L行号-->
            <pattern>%d{yyyyMM-dd HH:mm:ss}|%-5level|[%thread] %logger{36}[%L] -%msg%n</pattern>
        </encoder>
    </appender>

  
    <appender name="info_file" class="ch.qos.logback.core.rolling.RollingFileAppender">
      <!-- 日志名称 -->
        <File>${LOG_PATH}/info.log</File>
        <!-- 日志级别 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
             <level>${LOG_LEVEL}</level>
         </filter>
        <!-- 滚动策略 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/info-%d{yyyyMMdd}.log.%i</fileNamePattern>
            <!-- 单个文件最大值 -->
            <maxFileSize>10MB</maxFileSize>
            <!-- 归档文件最大值 -->
            <totalSizeCap>1GB</totalSizeCap>
            <!-- 最大保留日期,单位为滚动单位 -->
            <maxHistory>2</maxHistory>
            <!-- appender启动时删除归档,默认为false,即轮转时异步删除 -->
            <cleanHistoryOnStart>true</cleanHistoryOnStart>
            <!--TriggeringPolicy 的实现用于通知RollingFileAppender 何时轮转-->
            <!-- <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>10MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy> -->
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d{yyyyMM-dd HH:mm:ss}|%-5level|[%thread] %logger{36}[%L] -%msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
    </appender>

     <appender name="error_file" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>ERROR</level>
        </filter>
        <File>${LOG_PATH}/error.log</File>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/error-%d{yyyyMMdd}.log.%i</fileNamePattern>
            <!-- 单个文件最大值 -->
            <maxFileSize>10MB</maxFileSize>
            <!-- 归档文件最大值 -->
            <totalSizeCap>1GB</totalSizeCap>
            <!-- 最大保留日期,单位为滚动单位 -->
            <maxHistory>2</maxHistory>
            <!-- appender启动时删除归档,默认为false,即轮转时异步删除 -->
            <cleanHistoryOnStart>true</cleanHistoryOnStart>
            <!--TriggeringPolicy 的实现用于通知RollingFileAppender 何时轮转-->
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d{yyyyMM-dd HH:mm:ss}|%-5level|[%thread] %logger{36}[%L] -%msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
    </appender>
   

    <!-- 子节点2:root【用来指定最基础的日志输出级别(必选)】只有一个level属性-->
    <root level="info">
        <appender-ref ref="info_file" />
        <appender-ref ref="error_file" />
    </root>
     <root level="error">
        <appender-ref ref="error_file" />
    </root>     
    <!-- 子节点3:logger 【用来设置某一个包或者具体的某一个类的日志打印级别、以及指定<appender>】
      - name(必选):受此logger约束的某一个包或者具体的某一个类
      - level:打印级别,大小写无关
      - addtivity:是否向上级logger传递打印信息。默认是true
     -->
    <logger name="com.dayang" level="DEBUG">
      <appender-ref ref="console" />
     </logger>
</configuration>

五. 集成actuator实现动态修改日志级别

Spring Boot 1.5.x中引入的一个新的控制端点:/loggers,该端点将为我们提供动态修改Spring Boot应用日志级别的强大功能。该功能的使用非常简单,它依然延续了Spring Boot自动化配置的实现,所以只需要在引入了spring-boot-starter-actuator依赖的条件下就会自动开启该端点的功能
详情可参见如下文档
Spring Boot Actuator监控端点小结

1. pom配置

引入actuator依赖

1
2
3
4
5
6
7
8
<dependency>            
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

2. 自定义接口来监控日志级别的变化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

@RestController
@SpringBootApplication
public class Application {

private Logger logger = LoggerFactory.getLogger(getClass());

@RequestMapping(value = "/test", method = RequestMethod.GET)
public String testLogLevel() {
logger.debug("Logger Level :DEBUG");
logger.info("Logger Level :INFO");
logger.error("Logger Level :ERROR");
return "";
}

public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}

3. 查询日志级别[GET]

URL示例:
[GET] http://10.10.0.120:9010/gateway/dyportalserver/monitor/loggers/com.dayang

URL解释:

4. 修改日志级别[POST]

URL示例:
[POST] http://10.10.0.120:9010/gateway/dyportalserver/monitor/loggers/com.dayang

URL解释:

六. FAQ

1. 为什么springBoot官方推荐优先使用带有-spring的文件名作为你的日志配置?

2. 为什么选择logback日志框架?

logback是log4j作者推出的新日志系统,原生支持slf4j通用日志api,允许平滑切换日志系统,并且对简化应用部署中日志处理的工作做了有益的封装

3. logback.xml中,root和logger两个节点之间的关系?

root与logger为父子关系,Logger的appender根据参数additivity决定是否要叠加root的appender,logger的级别是其自身定义的级别,和root的级别没什么关系

4. application文件中的logging.path属性与logging.file属性

Spring Boot中的logging.path和logging.file这2个属性,只需要配置其中之一即可,如果同时配置,则使用logging.file属性;当配置了loggin.path属性时,将在该路径下生成spring.log文件;当配置了loggin.file属性时,将在指定路径下生成指定名称的日志文件

5. logback.xml中标签的使用

坚持原创技术分享,您的支持将鼓励我继续创作!