跨系统传递 traceId(日志)

2023-05-16

 

" 新项目查日志太麻烦,多台机器之间查来查去,还不知道是不是同一个请求的。打印日志时使用 MDC 在日志上添加一个 traceId,那这个 traceId 如何跨系统传递呢? "

 

1

背景

同样是新项目开发的笔记,因为使用的是分布式架构,涉及到各个系统之间的交互

 

几行代码轻松搞定跨系统传递 traceId

 

 

这时候就会遇到一个很常见的问题:

 

  1. 单个系统是集群部署,日志分布在多台服务器上;
  2. 多个系统的日志在多台机器,但是一次请求,查日志更是难上加难。

 

几行代码轻松搞定跨系统传递 traceId

 

解决方案

  1. 使用 SkyWalking traceid 进行链路追踪;
  2. 使用 Elastic APM 的 trace.id 进行链路追踪;
  3. 自己生成 traceId 并 put 到 MDC 里面。

 

2

MDC

 

MDC(Mapped Diagnostic Context)是一个映射,用于存储运行上下文的特定线程的上下文数据。因此,如果使用log4j进行日志记录,则每个线程都可以拥有自己的MDC,该MDC对整个线程是全局的。属于该线程的任何代码都可以轻松访问线程的MDC中存在的值。

 

如何使用 MDC

  1. log4j2-spring.xml 的日志格式中添加 %X{traceId} 配置。
<Property name="LOG_PATTERN">
    [%d{yyyy-MM-dd HH:mm:ss.SSS}]-[%t]-[%X{traceId}]-[%-5level]-[%c{36}:%L]-[%m]%n
</Property>
<Property name="LOG_PATTERN_ERROR">
    [%d{yyyy-MM-dd HH:mm:ss.SSS}]-[%t]-[%X{traceId}]-[%-5level]-[%l:%M]-[%m]%n
</Property>

<!-- 省略 -->

<!--这个输出控制台的配置-->
<Console name="Console" target="SYSTEM_OUT" follow="true">
    <!--输出日志的格式-->
    <PatternLayout charset="UTF-8"  pattern="${LOG_PATTERN}"/>
</Console>

 

  1. 新增拦截器

拦截所有请求,从 header 中获取 traceId 然后放到 MDC 中,如果没有获取到,则直接用 UUID 生成一个。

 

@Slf4j
@Component
public class LogInterceptor implements HandlerInterceptor {
    
    private static final String TRACE_ID = "traceId";

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception arg3) throws Exception {
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView arg3) throws Exception {
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        String traceId = request.getHeader(TRACE_ID);
        if (StringUtils.isEmpty(traceId)) {
            MDC.put(TRACE_ID, UUID.randomUUID().toString());
        } else {
            MDC.put(TRACE_ID, traceId);
        }


        return true;
    }
    
}

 

  1. 配置拦截器
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Resource
    private LogInterceptor logInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(logInterceptor)
                .addPathPatterns("/**");
    }
}

 

跨服务之间如何传递 traceId

  • FeignClient

因为这边使用的是 FeignClient 进行服务之间的调用,只需要新增请求拦截器即可

 

@Configuration
public class FeignInterceptor implements RequestInterceptor {

    private static final String TRACE_ID = "traceId";

    @Override
    public void apply(RequestTemplate requestTemplate) {

        requestTemplate.header(TRACE_ID, MDC.get(TRACE_ID));

    }
}

 

  • Dubbo

如果是 Dubbo 可以通过扩展 Filter 的方式传递 traceId

 

  1. 编写 filter
@Activate(group = {"provider", "consumer"})
public class TraceIdFilter implements Filter {

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {


        RpcContext rpcContext = RpcContext.getContext();


        String traceId;

        if (rpcContext.isConsumerSide()) {

            traceId = MDC.get("traceId");

            if (traceId == null) {
                traceId = UUID.randomUUID().toString();
            }

            rpcContext.setAttachment("traceId", traceId);

        }

        if (rpcContext.isProviderSide()) {
            traceId = rpcContext.getAttachment("traceId");
            MDC.put("traceId", traceId);
        }

        return invoker.invoke(invocation);
    }
}

 

  1. 指定 filter
src
 |-main
    |-java
        |-com
            |-xxx
                |-XxxFilter.java (实现Filter接口)
    |-resources
        |-META-INF
            |-dubbo
                |-org.apache.dubbo.rpc.Filter (纯文本文件,内容为:xxx=com.xxx.XxxFilter)

 

截图如下:

几行代码轻松搞定跨系统传递 traceId

 

 

测试结果如下:

 

几行代码轻松搞定跨系统传递 traceId

 

 

" dubbo filter 相关源码地址在文末,也可以关注公众号,发送 traceid 获取。 "

 

其他方式

当然如果小伙伴们有使用 SkyWalking 或者 Elastic APM 也可以通过以下方式进行注入:

 

  1. SkyWalking

 

<dependency>
    <groupId>org.apache.skywalking</groupId>
    <artifactId>apm-toolkit-log4j-2.x</artifactId>
    <version>{project.release.version}</version>
</dependency

 

然后将 [%traceId] 配置在 log4j2.xml 文件的 pattern 中即可

 

  1. Elastic APM
    1. 在启动时指定 enable_log_correlation 为 true
    2. 将 %X{trace.id} 配置在 log4j2.xml 文件的 pattern 中

 

3

扩展

 

统一日志采集

 

虽然有了 traceId 可以进行全链路追踪查询日志,但是毕竟也是在多台服务器上,为了提高查询效率,可以考虑将日志汇总到一起。

常用的使用方法就是基于 ELK 的日志系统:

  1. 使用 filebeat 采集日志报送到 logstash
  2. logstash 进行分词过滤等处理,输出到 Elasticsearch
  3. 使用 Kinbana 或者自己开发的可视化工具从 Elasticsearch 查询日志

 

几行代码轻松搞定跨系统传递 traceId

 

 

结束语

本文主要记录近期开发过程中的遇到的一点问题,希望对小伙伴也有所帮助。不足之处,欢迎指正。如果小伙伴有其他的建议或者观点欢迎留言讨论,共同进步。

 

相关资料

[1] Log4j 2 API:

https://logging.apache.org/log4j/2.x/manual/thread-context.html

[2] SkyWalking:

https://github.com/apache/skywalking/tree/master/docs/en/setup/service-agent/java-agent

[3] Elastic APM:

https://www.elastic.co/guide/en/apm/agent/java/current/log-correlation.html

[4] Dubbo filter:

http://dubbo.apache.org/zh-cn/docs/dev/impls/filter.html

[5] 本文 Dubbo filter demo:

https://github.com/liuzhihangs/trace

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

跨系统传递 traceId(日志) 的相关文章

  • 常用的法律检索类网站

    1 中国裁判文书网 xff1a http wenshu court gov cn xff0c 共公布全国各级法院生效裁判文书1 2亿篇 xff0c 可以检索 查看 下载裁判文书 2 中国司法案例网 xff1a http anli court
  • 重要代码备份

    文书 xff1a button 61 document getElementsByClassName 34 a xzBox 34 for let i 61 0 i lt 61 14 i 43 43 setTimeout 61 gt butt
  • 在 Visio 绘图中剪裁线条和形状

    编辑绘图或图表 在 34 开始 34 选项卡上 xff0c 单击 34 编辑 34 组中 34 选择 34 xff0c 然后单击 列表中的 34 全 选 34 单击 34 开发工具 34 选项卡 在 34 形状设计 34 组中 xff0c
  • 定时器/计数器介绍

    第一次在学习定时器的时候模模糊糊 xff0c 在做过一些题目之后对定时器有了更新的理解 xff0c 现在整理一下 xff0c 做笔记使用 目录 一 基础知识 定时器的作用 xff1a 定时器的实质 xff1a 定时器的工作原理 xff1a
  • Win10下安装Framework 3.5

    不同于 VC 43 43 运行库 xff0c NET Framework 是支持向下兼容的 xff0c 即 xff1a NET Framework 4 8 向下兼容至 4 0 NET Framework 3 5 SP1 向下兼容至 2 0
  • linux串口通信

    linux下串口通信与管理 linux下的串口与windows有一些区别 xff0c 下面将介绍一下linux下串口通信管理 查看是否支持USB串口 xff1a lsmod grep usbserial 如果没有信息 xff1a sudo
  • UP-magic的口袋机arm挂载u盘

    查看U盘信息 fdisk l mount t vfat dev mmcblk0p1 mnt sdcard 挂载U盘 mount命令格式 xff1a mount 参数 设备名称 挂载点 其他参数 mount t vfat dev sdb1 m
  • dell t630服务器风扇控制笔记记录(耗时一天)

    1 打开虚拟控制台得用IE xff1b 2 Dell PowerEdge T640 加装显卡之后风扇狂转问题解决 知乎 感谢知乎Billy xff0c 操作步骤 xff1a 1 查看iDrac版本 xff0c 必须在3 30 30 30及以
  • 安装autogpt中出现的问题及安装autogpt的小白教程

    ImportError DLL load failed while importing numpy ops The specified module could not be found 解决方案 xff1a Latest supporte
  • UBUNTU下NFS配置(用于嵌入式开发)

    1 NFS简介 NFS xff08 Network File System xff09 即网络文件系统 xff0c 是FreeBSD支持的文件系统中的一种 xff0c 它允许网络中的计算机之间共享资源 在NFS的应用中 xff0c 本地NF
  • Ubuntu 18.04 下 uhd+gnuradio 安装指南

    sudo apt get y install git swig cmake doxygen build essential libboost all dev libtool libusb 1 0 0 libusb 1 0 0 dev lib
  • 跨网的数据交换解决方案

    一 什么是跨网 跨网是指在互联网与局域网之间不能直接连通的网络 这些局域网可以是保密性较高的单独的局域网 xff0c 也可以是公安网 军网等 二 为什么要跨网传输 以公安网为例 xff0c 公安网对数据安全的要求较高 xff0c 所以不与互
  • urllib2.urlopen超时问题

    原帖地址 xff1a http hi baidu com yss1983 item 933fbe45a09c43e01381da06 问题描述 xff1a 没有设置timeout参数 xff0c 结果在网络环境不好的情况下 xff0c 时常
  • iOS Objective-C 正则表达式指南

    1 语法 2 模式 2 1 Search 43 NSString getDomainOfEmailAddress NSString email NSString re 61 64 34 lt 61 64 A Za z0 9 43 A Za
  • C语言学习(五)链表的格式与操作示例

    链表是为克服数组的缺点 xff0c 在内存空间中离散存储 xff0c 但需要一个指针记住下一个结点的地址 xff0c 以便可以将链表结点连接起来 链表与数组的比较 xff1a 数组 优点 xff1a 存取速度快 缺点 xff1a 插入和删除
  • iOS: Xcode 工程配置: Header Search Paths

  • weak & asign

    Why does Apple use assign rather than weak to store a delegate http stackoverflow com questions 20419317 why does apple
  • iOS Category中增加实例变量

    为 NSString增加一个 url的 NSString属性 NSString 43 url h span class hljs preprocessor style color rgb 136 0 0 import span class
  • Ubuntu 下旋转显示器屏幕

    Ubuntu 下旋转显示器屏幕 之前说到 xff0c 我喜欢把显示器竖过来看网页和电子书 xff0c 查了一下在Ubuntu里面旋转屏幕的方法 xff0c 据说用 xrandr o left 就可以了 不过我运行之后 xff0c 遇到了这个
  • iOS 静态库中使用宏定义区分iPhone模拟器与真机

    问题描述 一般项目中 xff0c 可以使用宏定义来判断模拟器还是真机 xff0c 这无疑是有效的 if TARGET IPHONE SIMULATOR define SIMULATOR 1 elif TARGET OS IPHONE def

随机推荐