本次讲解非微服务日志链路追踪,下一篇文章在介绍微服务链路追踪
日志链路追踪主要用于定位请求日志
TraceID:TraceID标记了 浏览器发起的某个请求, 这个TraceID可在服务端从接收请求到 响应请求中流转,甚至接力传递给下游应用中流转,用于唯一标记和定外这次请求。
第一步:创建一个springcloud项目
创建一个过滤器,主要生成TraceID和销毁TraceID
代码如图所示:
import org.slf4j.MDC;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
import java.util.UUID;
@Component
@Order(1)
@WebFilter(urlPatterns = "/*", filterName = "logMdcFilter")
public class LogMdcFilter implements Filter {
private static final String UNIQUE_ID = "traceId";
@Override
public void init(FilterConfig filterConfig) {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
boolean bInsertMDC = insertMDC();
try {
chain.doFilter(request, response);
} finally {
if(bInsertMDC) {
MDC.remove(UNIQUE_ID);
}
}
}
@Override
public void destroy() {
}
private boolean insertMDC() {
UUID uuid = UUID.randomUUID();
String uniqueId = uuid.toString().replace("-", "");
MDC.put(UNIQUE_ID, uniqueId);
System.out.println("-----traceId-----"+ uniqueId);
return true;
}
}
第二步:在resource下创建logback-spring.xml文件,添加 [%X{traceId}] 即可
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<contextName>febs</contextName>
<property name="log.path" value="D://mnt/log/server_log/docker/eureka"/>
<property name="log.maxHistory" value="15"/>
<property name="log.colorPattern"
value="%magenta(%d{yyyy-MM-dd HH:mm:ss}) %highlight(%-5level) %yellow(%thread) %green(%logger) %msg%n"/>
<property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5level %thread [%X{traceId}] %logger %msg%n"/>
<!--输出到控制台-->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<!-- 日志级别过滤INFO以下 -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<encoder>
<pattern>${log.colorPattern}</pattern>
</encoder>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!--输出到文件-->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/info/info.%d{yyyy-MM-dd}.log</fileNamePattern>
<MaxHistory>${log.maxHistory}</MaxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/error/error.%d{yyyy-MM-dd}.log</fileNamePattern>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="file_debug" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/debug/debug.%d{yyyy-MM-dd}.log</fileNamePattern>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="file_warn" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/warn/warn.%d{yyyy-MM-dd}.log</fileNamePattern>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARN</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="sql" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sql/mybatis-sql.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${log.path}/sql/mybatis-sql.log.%d{yyyy-MM-dd}</FileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%thread|%d{yyyy-MM-dd HH:mm:ss.SSS}|%level|%logger{36}|%m%n</pattern>
</encoder>
</appender>
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<!--显示日志-->
<logger name="org.springframework.jdbc.core" additivity="false" level="DEBUG" >
<appender-ref ref="console" />
</logger>
<root level="info">
<appender-ref ref="file_info"/>
<appender-ref ref="file_error"/>
<appender-ref ref="file_debug"/>
<appender-ref ref="file_warn"/>
</root>
</configuration>
第四步:创建一个controller,编写一些接口,并打印info和error错误
@RequestMapping("/list")
@RequiresPermissions("spellwords:appspellwordstudentbook:list")
public R list(@RequestParam Map<String, Object> params){
logger.info("=------test测试-----"+ MDC.get("traceId"));
PageUtils page = appSpellWordStudentBookService.queryPage(params);
logger.info("=------test测试结束002-----"+ MDC.get("traceId"));
String str = null;
System.out.println(str.getBytes());
return R.ok().put("page", page);
}
此处有两行info打印日志和一行抛出异常的代码
第五步:启动查看日志
启动Application查看日志
info日志打印如下,红色标识的为traceId:027468ffe9464f7389e831238931f1be
2021-05-15 09:56:08 INFO http-nio-8303-exec-2 [027468ffe9464f7389e831238931f1be] com.xxx.spellwords.controller.AppSpellWordStudentBookController =------test测试-----027468ffe9464f7389e831238931f1be
2021-05-15 09:56:08 INFO http-nio-8303-exec-2 [027468ffe9464f7389e831238931f1be] com.xxx.spellwords.controller.AppSpellWordStudentBookController =------test测试结束002-----027468ffe9464f7389e831238931f1be
error日志打印如下,红色标识为traceId:027468ffe9464f7389e831238931f1be
2021-05-15 09:56:08 ERROR http-nio-8303-exec-2 [027468ffe9464f7389e831238931f1be] com.xxx.exception.RRExceptionHandler null
java.lang.NullPointerException: null
at com.xxx.spellwords.controller.AppSpellWordStudentBookController.list(AppSpellWordStudentBookController.java:58)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:879)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
可以看出配置完毕,最后使用阿里云日志服务采集日志或者使用elk,通过平台来查询日志,具体日志配置操作看我以前博客
对于异步线程问题后续继续写