一、背景
近期遇到同组同学反馈logback-spring.xml文件不生效的问题,由于本人很久没申请过新应用,所以对于配置类的事宜有点陌生(大部分是应用交接维护,直接使用log也没过多关注配置,知道大概但细节有点脱节,虚了),导致自己在排查阶段花了很长时间,本文记录了整个排查思路,包括logback配置、不生效的原因分析等,希望给大家提供一些经验参考。
1.1 Logback简介
SLF4J(Simple Logging Facade for Java)是一个Java的日志API的简单门面,它提供了一个简单统一的记录日志的接口,而具体的日志实现则可以通过不同的日志库来完成。
Logback是一个日志库,Logback被设计为能够与SLF4J无缝集成,也可替代SLF4J,因为Logback的开发者之一是SLF4J的创始人。
二、logback配置
因为pandora-boot默认集成logback,不需要额外logback依赖。
2.1 配置姿势
官方推荐使用logback,排查思路均以logback不生效为主线。
1)指定配置文件路径
application.properties添加配置项logging.config=classpath:logback-spring.xml
2)自定义配置文件
<?xml version="1.0" encoding="UTF-8"?> <configuration scan="true"> <!-- https://github.com/spring-projects/spring-boot/blob/v1.5.13.RELEASE/spring-boot/src/main/resources/org/springframework/boot/logging/logback/defaults.xml --> <include resource="org/springframework/boot/logging/logback/defaults.xml" /> <property name="APP_NAME" value="xxxx" /> <property name="LOG_PATH" value="${user.home}/logs/eleme/${APP_NAME}/" /> <property name="LOG_FILE" value="${LOG_PATH}/application.log" /> <property name="ERROR_LOG_FILE" value="${LOG_PATH}/common-error.log"/> <property name="TRACE_FILE_LOG_PATTERN" value="[%X{requestId}][%X{rpcId}] -%green(%d{yyyy-MM-dd HH:mm:ss.SSS}) ${LOG_LEVEL_PATTERN:-%5p} %magenta(${PID:- }) --- [%t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/> <property name="ERROR_FILE_LOG_PATTERN_D" value="${ERROR_FILE_LOG_PATTERN_D:-%d{yyyy-MM-dd HH:mm:ss.SSS} ${LOG_LEVEL_PATTERN:-%5p} [%X{requestId}] [%X{rpcId}][traceId:%X{EAGLEEYE_TRACE_ID}][%c{2}#%M] %logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/> <appender name="APPLICATION" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_FILE}</file> <encoder> <pattern>${TRACE_FILE_LOG_PATTERN}</pattern> </encoder> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <fileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}.%i.log</fileNamePattern> <maxHistory>7</maxHistory> <maxFileSize>50MB</maxFileSize> <totalSizeCap>20GB</totalSizeCap> </rollingPolicy> </appender> <appender name="ERROR_APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${ERROR_LOG_FILE}</file> <encoder> <pattern>${ERROR_FILE_LOG_PATTERN_D}</pattern> </encoder> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <fileNamePattern>${ERROR_LOG_FILE}.%d{yyyy-MM-dd}.%i.log</fileNamePattern> <maxHistory>7</maxHistory> <maxFileSize>50MB</maxFileSize> <totalSizeCap>20GB</totalSizeCap> </rollingPolicy> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>ERROR</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> </appender> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>${TRACE_CONSOLE_LOG_PATTERN}</pattern> <charset>utf8</charset> </encoder> </appender> <root level="INFO"> <!-- <appender-ref ref="CONSOLE" />--> <appender-ref ref="APPLICATION" /> <appender-ref ref="ERROR_APPENDER" /> </root> </configuration>
2.2 配置可能遇到的一些问题
1)自定义变量不生效?
如果引用外部的变量,只有几个变量适用,比如${PID}、${LOG_FILE}、${LOG_PATH}、${LOG_EXCEPTION_CONVERSION_WORD},其它变量建议定义成property才能正常使用。如上文中的APP_NAME
2)如何看更多报错信息?
可以在启动时加上`-Dlog4j.defaultInitOverride=true`
2.3 完成配置后未生效表象
按照如上配置后,可能出现自定义的Appender不生效,即指定目录下只有service_stdout.log,无自定义的file配置。
所有的文件都会输出到service_stdout.log,因为在appctl.sh中,默认start_pandora_boot方法中已指定输出到"$SERVICE_OUT" 2>&1 "&" ,这里是无问题,核心在于自定义的logback-spring.xml如何分发。
三、不生效原因分析
3.1、远程debug
- 首先要开启远程debug,
JPDA_OPTS="-agentlib:jdwp=transport=$JPDA_TRANSPORT,address=$JPDA_ADDRESS,server=y,suspend=$JPDA_SUSPEND" - idea启动Remote JVM Debug
3.2、查看logback appender
执行命令LoggerFactory.getLogger("ROOT"),查看ROOT下的aai(AppenderAttachableImpl作用是管理和处理与日志记录器相关联的多个Appender对象),发现并不是logback-spring.xml自己定义的Appender对象,意味着被覆盖或优先级有所不同。
这里也走了弯路,不断debug源码找问题,包括org.springframework.boot.context.logging.LoggingApplicationListener#initialize其中logback-spring.xml已被加载。
回头看了下官方文档,提示可能包冲突导致的问题。
3.3 排查日志冲突问题
牢记官方这个图的顺序:
- 理论上使用logback,就要排除SLF4J-Log4j12;
- 因为jcl-over-slf4j与 commons-logging冲突, 需要排除commons-logging;
如果跟pom无冲突, 子pom.xml也要排除,使用Dependency Analyzer事半功倍。
排除过程中采用最小原则,避免影响其它业务代码。
3.4 double check
执行命令LoggerFactory.getLogger("ROOT"),再次查看ROOT实例下的aai;
与`logback-spring.xml`定义的appender一样, 同时定义的file也被正常初始化了。
四、总结
1、仔细阅读spring-boot官方文档,自己踩过的坑绝不是独一无二的。
2、引入二方包时养成最小原则,善用exclusion(虽然这只是美好愿望,希望排查时不要泪两行)。
参考文章:
PandoraBoot文档: https://mw.alibaba-inc.com/products/pandoraboot/_book/log-config.html
来源 | 阿里云开发者公众号
作者 | 率领