如何为Logback日志添加唯一追踪ID
作者:Mistra丶
本文介绍了如何为Logback日志添加唯一追踪ID,以便在测试和调试时更容易定位报错信息,通过创建过滤器和修改配置文件,可以在每个请求的日志中添加唯一的ID,并将其返回给前端,这样,当用户反馈报错时,开发人员可以根据ID快速定位和解决问题
为Logback日志添加唯一追踪ID
平常在测试的时候,不容易定位报错信息,这个时候给日志加上唯一的追踪ID,查找日志的时候就非常方便了。
像这样:
每个请求打印的日志都会有不同的ID,哪个请求出错,根据ID来定位日志就行了。
这个ID还会返回给前端,前端发现报错让后台找原因的话只需要给个ID,后台开发人员就能根据
环境:
- SpringBoot - 2.1.5.RELEASE
- JDK8
一、创建过滤器
- LogMDCFilter.java
public class LogMDCFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { String requestIdKey = "requestId"; String requestId = UUID.randomUUID().toString(); MDC.put(requestIdKey, requestId); String levelName = "logLevel"; String value = servletRequest.getParameter(levelName); if (StringUtils.isNotBlank(value)) { //org.slf4j.MDC MDC.put(levelName, value.toUpperCase()); } try { filterChain.doFilter(servletRequest, servletResponse); } finally { MDC.remove(requestIdKey); MDC.remove(levelName); } } @Override public void destroy() { } }
- DebugLogTurboFilter.java
public class DebugLogTurboFilter extends TurboFilter { @Override public FilterReply decide(Marker marker, Logger logger, Level level, String format, Object[] params, Throwable t) { int levelInt = level.toInt(); String levelName = MDC.get("logLevel"); if (StringUtils.isBlank(levelName) || "DEBUG,INFO,TRACE,WARN".indexOf(levelName) == -1) { return FilterReply.NEUTRAL; } if ((Level.TRACE.levelStr.equals(levelName) && levelInt >= Level.TRACE_INT) || (Level.DEBUG.levelStr.equals(levelName) && levelInt >= Level.DEBUG_INT) || (Level.INFO.levelStr.equals(levelName) && levelInt >= Level.INFO_INT) || (Level.WARN.levelStr.equals(levelName) && levelInt >= Level.WARN_INT)) { return FilterReply.ACCEPT; } return FilterReply.DENY; } }
二、注册过滤器
- FilterConfiguration.java
@Configuration public class FilterConfiguration { @Bean public FilterRegistrationBean logFilterRegistration() { FilterRegistrationBean registration = new FilterRegistrationBean(); //注入过滤器 registration.setFilter(new LogMDCFilter()); //拦截规则 registration.addUrlPatterns("/*"); //过滤器名称 registration.setName("logMDCFilter"); //过滤器顺序 registration.setOrder(0); return registration; } }
三、Logback.xml
<?xml version="1.0" encoding="UTF-8"?> <configuration> <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%date{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36}:%line - %msg %X{requestId}%n </pattern> </encoder> </appender> //上面的 DebugLogTurboFilter <turboFilter class="com.example.common.config.DebugLogTurboFilter"> </turboFilter> <appender name="rollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>/home/logs/merchant/common-merchant.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <fileNamePattern>/home/logs/merchant/history/merchant.%d{yyyy-MM-dd HH}.%i.log</fileNamePattern> <maxHistory>30</maxHistory> <maxFileSize>3MB</maxFileSize> </rollingPolicy> <encoder> <pattern>%date{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36}:%line - %msg %X{requestId}%n </pattern> </encoder> </appender> <!-- project default level --> <logger name="com.version" level="DEBUG"/> <logger name="org.springframework.web.servlet.handler" level="INFO"/> <logger name="com.example.user.mapper" level="DEBUG"/> <!--log4jdbc --> <logger name="org.springframework.jdbc.core.JdbcTemplate" level="INFO"/> <root level="INFO"> <appender-ref ref="console"/> <appender-ref ref="rollingFile"/> </root> </configuration>
注意配置中的{requestId}占位符,这个就会替换为生成的唯一日志ID。
四、返回值封装
- ResponseModel.java
public class ResponseModel implements Serializable { private static final long serialVersionUID = -8972819161141262263L; @ApiModelProperty(value = "是否处理成功", name = "success", example = "true") private Boolean success; @ApiModelProperty(value = "返回码", name = "code", example = "200") private Integer code; @ApiModelProperty(value = "处理消息", name = "msg", example = "处理成功") private String msg; @ApiModelProperty(value = "返回数据", name = "data", example = "{}") private Object data; private String requestId = MDC.get("requestId"); }
代码写完了,前端每次请求,如果有返回值的话,都会收到唯一日志ID,如图:
可以根据requestId,通过此命令在日志文件中查找对应的日志
cat common-user.log | grep -C 10 f11819ea-6169-4c13-8032-979a88977575
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。