迁移到SpringBoot 08 - 日志

SpringBoot默认的日志配置通常来说足够满足要求:日志记录到控制台,也能够配置日志的级别,样式等等。但是其也有些不足:没有了之前logback提供的热更新日志配置的功能。

logback有个非常好用的配置是“scan”,当“scan=true”的时候默认一分钟刷新一次配置。这样可以自动更新系统的日志级别。对于在线系统可以方便修改日志级别获取更加详细的日志,方便定位错误。这样可以保证服务不中断的情况下调整日志级别获取更多日志信息。但是默认的SpringBoot配置中不支持这种选项。

1. 多配置支持

改造方案是使用logback。但是有一点需要注意的是不能够使用通常用的 logback.xml这个文件名来进行配置。因为这个文件名被logback自动扫描,无法做到不同环境不同配置。可以使用logging.config这个配置项,来进行环境不同的设定:

在application.yaml中,如下配置:

1
2
3
# Set logback configuration file
logging:
config: classpath:logback-default.xml

2. 配置文件

下面是最后使用的配置文件的一个例子,可以供以后项目参考。

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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
<?xml version="1.0" encoding="UTF-8"?>

<configuration debug="false" scan="true" >
<!-- 定义全局的变量 //-->
<property name="cap.logger.level" value="info"/>
<property name="cap.logger.level.server" value="debug"/>
<property name="cap.logger.outputdir" value="/opt/cap/cap-uid-logs"/>

<!-- 定义一些converionRule -->
<!-- clr 定义色彩 -->
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
<!-- wex 异常处理用的 -->
<conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
<!-- wex 异常处理用的 -->
<conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />

<jmxConfigurator />

<contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
<resetJUL>true</resetJUL>
</contextListener>

<!-- Standard syslog/console used by root appenders -->
<appender name="syslog" class="ch.qos.logback.classic.net.SyslogAppender">
<syslogHost>${PUBLIC_IP}</syslogHost>
<facility>LOCAL7</facility>
<suffixPattern>[%-5level] [%logger{0}] - %msg%n</suffixPattern>
</appender>

<!-- console输出,有色彩支持的 //-->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<!--<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">-->
<!--<pattern>[%date] [%-5level] [%logger{0}] - %msg%n</pattern>-->
<!--</encoder>-->
<encoder>
<pattern>${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}</pattern>
</encoder>
</appender>

<!-- accessFile。使用标准的springboot格式输出,方便阅读。 //-->
<appender name="accessFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- daily rollover -->
<fileNamePattern>${cap.logger.outputdir}/access_%d{yyyy_MM_dd}.log</fileNamePattern>
<!-- keep 30 days' worth of history capped at 3GB total size -->
<maxHistory>90</maxHistory>
</rollingPolicy>
<append>true</append>
<encoder>
<pattern>${FILE_LOG_PATTERN:-%d{yyyy-MM-dd HH:mm:ss.SSS} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}</pattern>
</encoder>
</appender>

<!-- 使用JSON格式。方便管理平台分析。Use JSONLayout, UID Admin may analysis it //-->
<appender name="errorFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- daily rollover -->
<fileNamePattern>${cap.logger.outputdir}/error_%d{yyyy_MM_dd}.log</fileNamePattern>
<!-- keep 30 days' worth of history capped at 3GB total size -->
<maxHistory>90</maxHistory>
</rollingPolicy>
<append>true</append>
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="com.eveus.common.logger.JSONLayout" />
</encoder>
</appender>

<!-- 使用JSON格式。方便管理平台分析。Use JSONLayout, UID Admin may analysis it //-->
<appender name="kafkaErrorFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- daily rollover -->
<fileNamePattern>${cap.logger.outputdir}/kafka_error_%d{yyyy_MM}.log</fileNamePattern>
<!-- keep 30 days' worth of history capped at 3GB total size -->
<maxHistory>90</maxHistory>
</rollingPolicy>
<append>true</append>
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="com.eveus.common.logger.JSONLayout" />
</encoder>
</appender>

<!-- third party library logger level -->
<logger name="org.springframework" level="${cap.logger.level}" />
<logger name="org.apache.cxf" level="${cap.logger.level}" />
<logger name="ch.qos.logback" level="${cap.logger.level}" />
<logger name="com.notnoop.apns" level="${cap.logger.level}" />
<logger name="org.springframework.security" level="${cap.logger.level}"/>
<logger name="org.springframework.transaction" level="${cap.logger.level}" />
<logger name="org.springframework.jdbc" level="${cap.logger.level}" />

<!-- UID server logger -->
<!-- change level to debug to show sql -->
<logger name="com.eveus.cloudauth.dao" level="info"/>
<!-- LoggerAspect, Used for API & Service logging -->
<logger name="com.eveus.common.logger" level="debug"/>
<!-- KafkaConsumer -->
<logger name="com.eveus.common.kafka" level="info"/>
<!-- AccessLogger -->
<logger name="com.eveus.cloudauth.service.impl.jms.AccessLogService" level="info"/>

<!-- The following needs detail log in development stage -->
<logger name="com.eveus.cloudauth.api" level="${cap.logger.level.server}"/>
<logger name="com.eveus.cloudauth.service" level="${cap.logger.level.server}"/>
<logger name="com.eveus" level="${cap.logger.level.server}" />

<!-- kafka error logger -->
<logger name="com.eveus.common.kafka.KafkaProducer" level="error">
<appender-ref ref="kafkaErrorFile"/>
</logger>

<root level="${cap.logger.level}">
<appender-ref ref="console"/>
<appender-ref ref="accessFile"/>
<appender-ref ref="errorFile"/>
</root>
</configuration>

3. 部署方式

SpringBoot项目打包的时候会把配置文件一同打包到jar文件中。 这样修改logback配置文件会比较麻烦。所以在部署的时候会把配置文件解压出来,和jar文件放到同一个目录中。这是利用了SpringBoot配置文件加载的一个特性。官方文档介绍如下:

SpringApplication will load properties from application.properties files in the following locations and add them to the Spring Environment(SpringBoot会按照顺序从下面的路径中加载配置文件):

  • A /config subdirectory of the current directory. (当前目录内的/config目录)
  • The current directory (当前目录)
  • A classpath /config package (classpath中的/config文件夹)
  • The classpath root (classpath根目录)
    The list is ordered by precedence (properties defined in locations higher in the list override those defined in lower locations).

利用这个特性,在部署的时候将配置文件解压出来,放到当前目录下(和jar文件统计目录),这样它的优先级高于在jar包中的配置文件。

最后还需要在启动命令中增加配置,指定logback的配置文件,方法是指定logging.config这个Java环境变量:

1
-Dspring.profiles.active=chanpayprd -Dlogging.config=file:/opt/cap/cap-uid/logback-chanpayprd.xml

附录、参考资料

热评文章