怎么把CAT客户端的RootMessageId记录到每条日志中?
什么是rootmessageid?
为了理解rootmessageid先简单介绍一下cat的数据结构设计。cat客户端会将所有消息都封装为一个完整的消息树(messagetree),消息树可能包括transaction、event、heartbeat、metric等类型的消息。具体如下:
- transaction:适合记录跨越系统边界的程序访问行为,比如远程调用,数据库调用,也适合执行时间较长的业务逻辑监控,transaction用来记录一段代码的执行时间和次数
- event:用来记录一件事发生的次数,比如记录系统异常,它和transaction相比缺少了时间的统计,开销比transaction要小
- heartbeat:表示程序内定期产生的统计信息, 如cpu利用率, 内存利用率, 连接池状态, 系统负载等
- metric:用于记录业务指标、指标可能包含对一个指标记录次数、记录平均值、记录总和,业务指标最低统计粒度为1分钟
欢迎关注微信公众号:万猫学社,每周一分享java技术干货。
其中,transaction类型的消息可作为消息树节点,而其他消息只可作为消息树的叶子节点,也就是transaction是一个可嵌套的递归结构。比如:
消息树的每一节点都有一个属性messageid,用来唯一表示节点本身,其构成为:{domain}-{ip}-{timestamp}-{自增index}。另外还有两个属性,分别是parentmessageid, rootmessageid。parentmessageid表示父节点的messageid;rootmessageid则表示整个消息树的根节点的messageid。这两个属性在之后cat的调用链分析与分布式调用链分析中发挥了关键作用。
欢迎关注微信公众号:万猫学社,每周一分享java技术干货。
为什么在日志中记录?
根据rootmessageid可以追踪某一个请求的整个分布式调用链,结合每一条日志快速定位耗费性能的症结,做针对性的性能优化。更加方便地做性能优化,特别是tp95、tp99等指标。
遇到偶尔发生的bug,是最让人头疼的,只有先从日志中找线索,但是在海量的日志中找到出现bug的那一个请求是很困难的。有了上游api提供的rootmessageid,就可以快速过滤出那次请求的所有日志, 更快速更方便地定位线上bug。
欢迎关注微信公众号:万猫学社,每周一分享java技术干货。
在日志的什么地方记录?
当然是每一句日志上都记录rootmessageid了。有的同学会说,这日志也记录的太多了。当发现线上问题无法定位时,你就会狠日志太少了。其实记录日志不怕多,就怕不全。现在硬盘很便宜了,搞个几t没有问题,另外还可以设置日志清理策略。
欢迎关注微信公众号:万猫学社,每周一分享java技术干货。
怎么记录到日志中?
前面说了那么多,终于到了今天的压轴大戏了。实现记录到日志有很多种方式,这里使用的是mdc(mapped diagnostic contexts)。顾名思义,其目的是为了便于我们诊断线上问题而出现的方法工具类,目前我们经常使用的logback和log4j都是支持的。
欢迎关注微信公众号:万猫学社,每周一分享java技术干货。
只需要在每个请求的入口调用mdc.put方法,把rootmessageid赋值进去就可以了,是不是很简单?示例代码:
//在filter里,从header里获取上下文信息,包括messageid、parentmessageid、rootmessageid catcontext catcontext = new catcontext(); 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(cat.context.root) == null) { //如果调用链的顶端,没有上下文信息,需要生成上下文信息 cat.logremotecallclient(catcontext); } else { cat.logremotecallserver(catcontext); } mdc.put("traceid", catcontext.getproperty(cat.context.root));
如果你还不知道怎么集成cat调用链,可以看看之前的《springboot集成cat调用链实例》
然后,在设置日志输出格式的配置文件里增加[%x{traceid}]
。
logback的xml配置示例:
<?xml version="1.0" encoding="utf-8" ?> <configuration scan="true"> <appender name="console" class="ch.qos.logback.core.consoleappender"> <layout class="ch.qos.logback.classic.patternlayout"> <pattern>[%d{yyyy-mm-dd hh:mm:ss.sss}] [%thread] [%x{traceid}] [%-5level] [%-40.36logger{40}:%-4.4line] - %msg%n</pattern> </layout> </appender> <root level="info"> <appender-ref ref="console" /> </root> </configuration>
log4j的properties配置示例:
log4j.rootcategory=info,stdout,info,error log4j.rootlooger=warn,stdout,info,error log4j.appender.stdout=org.apache.log4j.consoleappender log4j.appender.stdout.layout=org.apache.log4j.patternlayout log4j.appender.stdout.layout.conversionpattern=%d{yyyy-mm-dd hh:mm:ss,sss} [%-5p] [%thread] [%x{traceid}] method:%l - %m%n
欢迎关注微信公众号:万猫学社,每周一分享java技术干货。