平常在测试的时候,不容易定位报错信息,这个时候给日志加上唯一的追踪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,通过此命令在日志文件中查找对应的日志