栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Springboot traceId请求链路追踪

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Springboot traceId请求链路追踪

文章目录
  • 一、请求链路追踪是什么?
  • 二、使用步骤
    • 1. 相关知识点
    • 2. 代码实现
    • 3. 测试一下效果
  • 三、总结:下一节咱们来说对全局响应体包装和traceId链路追踪的结合。都看到这里了,麻烦各位老铁给个赞吧。


一、请求链路追踪是什么?

能标识一次请求的完整流程,包括日志打印、响应标识等,以便于出现问题可以快速定位并解决问题。

二、使用步骤 1. 相关知识点
  1. ThreadLocal:一种保证一种规避多线程访问出现线程不安全的方法,当我们在创建一个变量后,如果每个线程对其进行访问的时候访问的都是线程自己的变量这样就不会存在线程不安全问题。
  2. MDC:(Mapped Diagnostic Context,映射调试上下文)是 log4j 和 logback 提供的一种方便在多线程条件下记录日志的功能,基于ThreadLocal实现的一种工具类。
  3. 拦截器:基于拦截器对每个请求注入traceId。

2. 代码实现
  1. 封装TraceId工具类:
public class TraceIdUtil {
    private static final String TRACE_ID = "traceId";

    public static void set() {
        MDC.put(TRACE_ID, generate());
    }

    public static String get() {
        return MDC.get(TRACE_ID);
    }

    public static void remove() {
        MDC.remove(TRACE_ID);
    }

    public static String generate() {
        return UUID.randomUUID().toString().replace("-", "").substring(0, 16);
    }
}

  1. springboot环境注入工具类
public class PropertySourcesUtil {

    private static final String NAME = "aop.yinfeng";

    private static ConfigurableEnvironment environment;
    private static SpringApplication application;

    public static void setEnvironment(ConfigurableEnvironment environment) {
        if (PropertySourcesUtil.environment == null) {
            PropertySourcesUtil.environment = environment;
        }
    }

    public static SpringApplication getApplication() {
        return application;
    }

    public static void setApplication(SpringApplication application) {
        PropertySourcesUtil.application = application;
    }

    public static void set(String key, Object value) {
        getSourceMap().put(key, value);
    }

    public static Object get(String key) {
        return getSourceMap().get(key);
    }

    public static Map getSourceMap() {
        PropertySource propertySource = environment.getPropertySources().get(NAME);
        Map source;
        if (propertySource == null) {
            source = new linkedHashMap();
            propertySource = new MapPropertySource(NAME, source);
            environment.getPropertySources().addLast(propertySource);
        }
        source = (Map) propertySource.getSource();
        return source;
    }
}

  1. 支持配置的日志实体类:
@Data
@ConfigurationProperties(prefix = "aop.logging")
public class LogProperties {

    private String logDir;
    // 因为logback和log4j的日志格式略有不同,所以提供2种打印格式
    private String logbackPattern = "%d{yyyy-MM-dd HH:mm:ss.SSS} %X{traceId} %-5level %logger{30} : %msg%n";
    private String log4jPattern = "%d{yyyy-MM-dd HH:mm:ss.SSS} %X{traceId} %-5level %clr{%-30.30c{1.}}{cyan} : %msg%n";
}


  1. 环境增强注入配置:因为请求链路追踪在各个服务中比较常用,所以以starter的形式进行封装,在spring环境加载后进行配置注入。
public abstract class AbstractEnvironmentPostProcessor implements EnvironmentPostProcessor {

    private static final String DEV = "dev";
    private static final String STG = "stg";
    private static final String PRD = "prd";

    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        PropertySourcesUtil.setEnvironment(environment);
        final List profiles = Arrays.asList(environment.getActiveProfiles());
        if (profiles.contains(PRD)) {
            doPrd(environment, application);
        } else if (profiles.contains(STG)) {
            doStg(environment, application);
        } else {
            doDev(environment, application);
        }
        onProfile(environment, application);
    }

    protected void doPrd(ConfigurableEnvironment environment, SpringApplication application) {
    }

    protected void doStg(ConfigurableEnvironment environment, SpringApplication application) {
    }

    protected void doDev(ConfigurableEnvironment environment, SpringApplication application) {
    }

    protected void onProfile(ConfigurableEnvironment environment, SpringApplication application) {
    }
}
@EnableConfigurationProperties(LogProperties.class)
public class LogEnvAdvice extends AbstractEnvironmentPostProcessor {

    @Override
    protected void onProfile(ConfigurableEnvironment environment, SpringApplication application) {
        final Binder binder = Binder.get(environment);
        final BindResult bindResult = binder.bind("aop.logging", Bindable.of(LogProperties.class));
        LogProperties logProperties = new LogProperties();
        if (bindResult.isBound()) {
            logProperties = bindResult.get();
        }
        // 配置日志打印格式
        if (isLogback(application)) {
            PropertySourcesUtil.set("logging.pattern.console", logProperties.getLogbackPattern());
            PropertySourcesUtil.set("logging.pattern.file", logProperties.getLogbackPattern());
            return;
        }
        PropertySourcesUtil.set("logging.pattern.console", logProperties.getLog4jPattern());
        PropertySourcesUtil.set("logging.pattern.file", logProperties.getLog4jPattern());
    }

    
    private boolean isLogback(SpringApplication application) {
        final LoggingSystem loggingSystem = LoggingSystem.get(application.getClassLoader());
        return LogbackLoggingSystem.class.equals(loggingSystem.getClass());
    }
}

  1. 在spring.factory文件配置log环境注入类
org.springframework.boot.env.EnvironmentPostProcessor=com.yinfeng.common.enviroment.LogEnvAdvice

  1. 配置拦截器,在每个请求进入时注入traceId,因为基于threadLocal实现,所以需要在请求完成后进行手动清除,否则gc会扫描不到
public class LogInterceptor implements HandlerInterceptor {

   @Override
   public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
       TraceIdUtil.set();
       return true;
   }
}
public class InterceptorAdvice implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    	// 将拦截器注入到容器中
        final InterceptorRegistration registration = registry.addInterceptor(new LogInterceptor()).order(Integer.MIN_VALUE);
        registration.addPathPatterns("/**");
    }
}


3. 测试一下效果

到此为止,通过traceId追踪请求链路代码基本完成,下面咱们来测认识一下

  1. 在pom文件中引入咱们的starter

    com.yinfeng
    common-starter
    1.0.0
    
        
            org.mybatis
            mybatis
        
        
            com.github.jsqlparser
            jsqlparser
        
    

  1. 通过knife4j接口文档发送请求
  2. 查看日志:可以看到咱们所有的业务日志打印都会带上traceId,方便咱们快速定位问题
三、总结:下一节咱们来说对全局响应体包装和traceId链路追踪的结合。都看到这里了,麻烦各位老铁给个赞吧。
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/292048.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号