Springboot+MDC实现全链路日志追踪

场景需求:

有时候某个接口涉及的逻辑很多,比如:查数据库、查redis、远程调用接口,发mq消息,执行业务代码等等。

该接口一次请求的链路很长,如果逐一排查,需要花费大量的时间,这时候,我们已经没法用传统的办法定位问题了。

有没有办法解决这问题呢?

用分布式链路跟踪系统:skywalking。

架构图如下:通过skywalking定位性能问题:在skywalking中可以通过traceId(全局唯一的id),串联一个接口请求的完整链路。可以看到整个接口的耗时,调用的远程服务的耗时,访问数据库或者redis的耗时等等,功能非常强大。

之前没有这个功能的时候,为了定位线上接口性能问题,我们还需要在代码中加日志,手动打印出链路中各个环节的耗时情况,然后再逐一排查。

如果你用过skywalking排查接口性能问题,不自觉的会爱上它的。如果你想了解更多功能,可以访问skywalking的官网:https://skywalking.apache.org/

除了这个,项目中也简单做了日志链路的追踪:

1.定义日志拦截器

package com.icon.config;
    
    import org.apache.commons.lang3.StringUtils;
    import org.slf4j.MDC;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.util.UUID;
    
    /**
     * 定义拦截器拦截日志链路唯一标识traceid的值
     */
    @Component
    public class LogInterceptor implements HandlerInterceptor {
    
        @Value(value = "${trace.id:traceid}")
        private String TRACE_ID;
    
        @Override
        public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) {
            MDC.remove(TRACE_ID);
        }
    
        @Override
        public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) {
        }
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            // 定义日志链路追踪唯一标识的key=traceid 前端UUID没有传递过来,则后台UUID生成
            String traceId = request.getHeader(TRACE_ID);
            if (StringUtils.isBlank(traceId)) {
                traceId = UUID.randomUUID().toString().replace("-", "");
            }
            MDC.put(TRACE_ID, traceId);
            return true;
        }
    }

2.配置拦截器

  package com.hermes.config;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    
    @Configuration
    public class WebMvcConfiguration implements WebMvcConfigurer {
        @Autowired
        private LogInterceptor logInterceptor;
        //配置拦截器
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            //指定拦截器,指定拦截路径
            registry.addInterceptor(logInterceptor).addPathPatterns("/**")
                    .excludePathPatterns("/index.html","/css/**","/fonts/**","/img/**","/js/**");
        }
    }

3.配置logback日志,输出traceid,完成日志链路追踪

    
    <configuration scan="true" scanPeriod="2 seconds" debug="false">
        
        <property name="log.level" value="debug"/>
        <property name="log.maxHistory" value="15"/>
    
        
            <property name="log.filePath" value="/opt/backend.log"/>
    
        
    
    
    
    
        
        <property name="log.pattern" value="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%X{traceid}] [%thread] %logger{50}:%L >> %msg%n"/>
    
        
        <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
                <pattern>${log.pattern}pattern>
            encoder>
        appender>
        
        <appender name="debugAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
            
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <fileNamePattern>${log.filePath}/debug/debug.%d{yyyy-MM-dd}.logfileNamePattern>
                <maxHistory>${log.maxHistory}maxHistory>
            rollingPolicy>
            <encoder>
                <pattern>${log.pattern}pattern>
            encoder>
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <level>DEBUGlevel>
                <onMatch>ACCEPTonMatch>
                <onMismatch>DENYonMismatch>
            filter>
        appender>
        
        <appender name="infoAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
            
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <fileNamePattern>${log.filePath}/info/info.%d{yyyy-MM-dd}.logfileNamePattern>
                <maxHistory>${log.maxHistory}maxHistory>
            rollingPolicy>
            <encoder>
                <pattern>${log.pattern}pattern>
            encoder>
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <level>INFOlevel>
                <onMatch>ACCEPTonMatch>
                <onMismatch>DENYonMismatch>
            filter>
        appender>
        
        <appender name="errorAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
            
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <fileNamePattern>${log.filePath}/error/error.%d{yyyy-MM-dd}.logfileNamePattern>
                <maxHistory>${log.maxHistory}maxHistory>
            rollingPolicy>
            <encoder>
                <pattern>${log.pattern}pattern>
            encoder>
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <level>ERRORlevel>
                <onMatch>ACCEPTonMatch>
                <onMismatch>DENYonMismatch>
            filter>
        appender>
        
        
        
        
        
        
    
        
        <logger name="org.hibernate.SQL" additivity="false" >
            <level value="info" />
            <appender-ref ref="debugAppender"/>
            <appender-ref ref="infoAppender"/>
            <appender-ref ref="errorAppender"/>
        logger>
    
        
        <logger name="org.hibernate.type.descriptor.sql.BasicBinder" additivity="false" level="info" >
            <level value="info" />
            <appender-ref ref="debugAppender"/>
            <appender-ref ref="infoAppender"/>
            <appender-ref ref="errorAppender"/>
        logger>
    
        <root level="info">
            <appender-ref ref="consoleAppender"/>
            <appender-ref ref="debugAppender"/>
            <appender-ref ref="infoAppender"/>
            <appender-ref ref="errorAppender"/>
        root>
    configuration>

测试:

在这里插入图片描述

End

你可能感兴趣的:(编码,java)