基于注解脱敏+链路追踪traceId 快速定位错误

注解脱敏与链路追踪快速定位错误

日常开发中,你如何快速定位问题的?

a. 排除条件

特别是处理并发请求时,通过对每个方法生成traceId(自定义唯一标识符)用于快速定位目标日志,追踪整个系统中的请求流程。

b. 日志脱敏增强

返回值带着敏感信息,要么不返回,要么加密

请求参数带着敏感信息,要么不记录,要么加密

c. 解决方案

服务端入口处可以生成唯一的id,叫做:traceId

日志中均需要输出traceId的值

接口返回值中,添加一个通用的字段: traceld,将上面的traceld作为这个字段的值

这样前端发现接口有问题的时候,直接将这个traceld提供给我们,我们便可以在日志中快速查询出对应的日志。

MDC组件

使用Slf4j.MDC日志功能增强

org.slf4j.MDC是 SLF4J库中的一个组件,MDC提供了一种机制,允许在日志消息中插入上下文信息,这些信息可以跨多个方法调用和线程边界传播。这对于跟踪和调试分布式系统或多线程应用程序中的请求非常有用。

重点:**MDC 允许将键值对与当前线程关联起来(类似ThreadLocal)**然后,可以在我们的日志语句中引用这些值,从而能够更容易地识别和理解日志消息产生的上下文。

例如,你可能会在 Web 应用程序的每个请求开始时,将用户的 ID 或会话 ID 放入 MDC,然后在你的日志语句中引用这个值。这样,当你查看日志时,你可以很容易地看到哪个用户的哪个请求产生了哪些日志消息。

使用方式

Logback学习系列4(Pattern使用方法)https://www.jianshu.com/p/5cfc26caf50d

  • 设置值: MDC.put("userId", "12345");
  • 在日志语句中使用值: logger.info("Processing request for user: {}", MDC.get("userId"));
  • 清除值 MDC.remove("userId")
例子

假设我们正在开发一个电商网站,该网站由多个微服务组成,包括用户服务、订单服务、支付服务等。每个服务都运行在独立的服务器上,并通过REST API相互调用。为了方便调试和监控,我们需要在整个请求处理过程中跟踪每一个请求,并确保所有相关的日志条目都能关联起来。

  1. 当请求到达第一个服务(例如用户服务)时,TraceFilter生成一个唯一的traceId并将其放入MDC中。

  2. 当用户服务需要调用订单服务时,将当前线程中的traceId作为HTTP请求头的一部分传递给下游服务(订单服务)。在订单服务接收到请求时,从请求头中读取traceId并再次放入MDC中。

    // 客户端拦截器:将TraceId注入HTTP头
    public class OpenFeignRequestInterceptor implements RequestInterceptor {
         
         
        @Override
        public void apply(RequestTemplate requestTemplate) {
         
         
            String traceId = MDC.get("traceId"); // 从当前线程上下文中获取TraceId
            requestTemplate.header("X-Trace-ID", traceId); // 注入到HTTP头
        }
    }
    
    // 服务端处理:从HTTP头提取TraceId
    public class TraceFilter implements Filter {
         
         
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
         
         
            String traceId = request.getParameter("X-Trace-ID"); // 从HTTP头获取TraceId
            MDC.put("traceId", traceId); // 写入当前线程上下文
            chain.doFilter(request, response);
        }
    }
    
  3. 在每个服务的日志配置文件中,添加traceId到日志格式中,以便每条日志都包含这个信息。开发人员只需搜索traceId: xyz789即可快速定位问题根源。

    [订单服务] [traceId: xyz789] - 开始创建订单
    [库存服务] [traceId: xyz789] - 扣减库存成功
    [支付服务] [traceId: xyz789] - 支付失败,数据库连接超时
    
  4. 现在,无论请求跨越了多少个服务,只要查看日志,就可以通过traceId轻松地将所有相关的日志条目关联起来,从而快速定位问题或理解系统的运行情况。

核心代码
自定义注解

脱敏注解@NoLogAnnotation 相关方法加上注解后隐藏参数信息,脱敏前 密码没加密时会暴露用户密码等敏感信息

@Target({
   
   ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface NoLogAnnotation {
   
   
    //可以用在参数列表或者方法上,屏蔽不愿意记录的参数
}

日志配置logback.xml展示TraceId

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <!-- 日志输出格式 将MDC中的traceId自动嵌入每条日志(唯一)-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] [traceId:%X{traceId}] - %msg%n</pattern>
        </encoder>
    </appender>

    <logger name="com.zr.study" level="info" />
    <root level="info">
        <appender-ref ref="STDOUT" />
    </root>
</configuration>
链路追踪组件

TraceConfiguration,配置类注入过滤器和切面类进ioc容器

package com.zr.study.trace;
import com.zr.study.aop.ResultTraceIdAspect;
import org.springframework.context.annotation.Bean;
import 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

空说

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值