当前位置: 首页 > 后端技术 > Java

如何在每条日志中记录CAT客户端的RootMessageId?

时间:2023-04-01 22:24:27 Java

什么是RootMessageId?为了理解RootMessageId,首先简单介绍一下CAT的数据结构设计。CAT客户端会将所有的消息封装成一个完整的消息树(MessageTree),其中可能包括Transaction、Event、Heartbeat、Metric等多种类型的消息。具体如下:事务:适用于记录程序跨系统边界的访问行为,如远程调用、数据库调用等,也适用于执行时间较长的业务逻辑监控。Transaction用来记录一段代码的执行时间和次数Event:用来记录一件事情发生的次数,比如记录系统异常。与事务相比,它缺少时间统计,开销也比事务小。、系统负载等指标:用于记录业务指标。指标可以包括指标的记录数、记录的平均值和记录的总和。业务指标的最小统计粒度为1分钟。其中,Transaction类型的消息可以作为消息树的节点,而其他的Messages只能作为消息树的叶子节点,即Transaction是一个可嵌套的递归结构。例如:消息树的每个节点都有一个属性messageId,用于唯一表示节点本身,其组成为:{domain}-{ip}-{timestamp}-{self-incrementingindex}。还有另外两个属性,即parentMessageId和rootMessageId。parentMessageId表示父节点的messageId;rootMessageId表示整个消息树根节点的messageId。这两个属性在CAT的调用链分析和分布式调用链分析中起到了关键作用。为什么会记录在日志中?根据RootMessageId,可以追踪到某个请求的整个分布式调用链,结合各个日志可以快速定位性能消耗的症结,从而进行有针对性的性能优化。做性能优化更方便,尤其是TP95、TP99等指标。偶尔的错误是最麻烦的。只能先从日志中寻找线索,但是在海量的日志中很难找到有bug的请求。通过上游API提供的RootMessageId,可以快速过滤掉该次请求的所有日志,更快速方便的定位在线bug。它记录在日志中的什么位置?当然,日志的每一句都会记录RootMessageId。有同学会说,这个日志也记录的太多了。当你发现线上问题无法定位时,你会觉得日志太少了。其实记录日志不怕多,就怕不全。现在硬盘很便宜,弄个几TB是没有问题的。此外,您还可以设置日志清理策略。如何记录在日志中?说了那么多,终于到了今天的压轴戏。有很多方法可以实现记录到日志中。这里使用了MDC(MappedDiagnosticContexts)。顾名思义,它的目的就是为了方便在线诊断问题。是我们经常使用的logback和log4j目前支持的一个方法和工具类。只需要在每次请求的入口调用MDC.put方法,将rootMessageId赋值给它即可。是不是很简单?示例代码://在Filter中,从header中获取context信息,包括messageId,parentMessageId,rootMessageIdCatContextcatContext=newCatContext();catContext.addProperty(Cat.Context.ROOT,request.getHeader(CatConstants.CAT_HTTP_HEADER_ROOT_MESSAGE_ID));catContext.addProperty(Cat.Context.PARENT,request.getHeader(CatConstants.CAT_HTTP_HEADER_PARENT_MESSAGE_ID));catContext.addProperty(Cat.Context.CHILD,request.getHeader(CatConstants.CAT_HTTP_HEADER_CHILD_MESSAGE_ID));if(catContext.getProperty(ROCat.)==null){//如果调用链顶端没有上下文信息,需要生成上下文信息Cat.logRemoteCallClient(catContext);}else{Cat.logRemoteCallServer(catContext);}MDC.put("traceId",catContext.getProperty(Cat.Context.ROOT));如果不知道如何集成CAT调用链,可以看前面的《SpringBoot集成CAT调用链实例》,然后在设置日志输出格式的配置文件中加入[%X{traceId}]。Logback的xml配置示例:[%d{yyyy-MM-ddHH:mm:ss.SSS}][%线程][%X{traceId}][%-5level][%-40.36logger{40}:%-4.4line]-%msg%nlog4j的属性配置示例:log4j.rootCategory=INFO,stdout,info,errorlog4j.rootLooger=warn,stdout,info,errorlog4j.appender.stdout=org.apache.log4j.ConsoleAppenderlog4j.appender.stdout.layout=org.apache.log4j.PatternLayoutlog4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-ddHH:mm:ss,SSS}[%-5p][%线程][%X{traceId}]方法:%l-%m%n