共计 3764 个字符,预计需要花费 10 分钟才能阅读完成。
我是 3y,一年 CRUD
教训用十年的 markdown
程序员👨🏻💻长年被誉为优质八股文选手
明天来聊些大家都用得上的货色:数据链路追踪 。之前引入了零碎的监控来疾速定位利用操作系统上的问题,而业务问题呢?在这篇文章中你能够看到用注解的形式打印日志,也能看到 简易版 的全链路追踪是怎么实现的。
不多 BB,开始吧
01、注解日志打印
日志的搭建我在 austin 最开始的前几篇曾经有提及了,之前始终在等我的基友 @蛮三刀酱 他的日志组件库上传到 Maven 库,好让我应用应用下。在最近,他曾经更新了两个版本,而后传到了 Maven 库了,所以我就来接入了
这个组件库做的事件就是应用 注解 的形式来打印日志信息,并反对 SpEL 解析、 自定义上下文 以及 自定义函数 。它反对的货色听起来很牛逼,但说白了就是 让记录日志的形式做得更装逼。咱们写个破代码还能装逼,这谁受得了!这谁顶得住!
当初我曾经把注解在办法上定义了,当该办法被调用时,它打印了以下的日志:
看起来很好用,对不对?通过一个注解,我就能把 办法的入参 信息打印进去,有 bizType
和bizId
给咱们自定义,那就能够很不便地 定位 出打印日志的中央了,并且他还 贴心 把response
返回值也输入到日志上。
至多在这个接口上,这十分合乎我这个场景的需要,咱们再通过一张图略微重温下这个 send
接口到底做了什么事:
在 接口层面 打印入参信息以及返回值就能定位到很多问题(懂的都懂 ),应用注解还 不必烦扰 到咱们失常的业务代码就能打印出这么好的日志信息了(这个逼是装上了)
它的实现原理并不简单,感兴趣的小伙伴能够拉代码本人看看,先看 readmd
再看代码!!
GitHub:https://github.com/qqxx6661/logRecord
总的来说,他通过 SpEL 表达式 来读取到 #sendRequest
入参对象的信息,而注解解析则用的是 Spring AOP
。至于 自定义上下文 以及 自定义函数 我在这是没用到的,至多在 austin 我的项目场景下,我感觉都没什么用。哦,对了,它还能将日志输入到别的管道(MQ)。惋惜的是,我这场景也用不到。
在目前的实现下,我 就只有这个接口 能用到该组件,我抵赖他在某些场景是很好用。
但它是 有局限性 的:打印的日志信息跟 办法参数强相干 :如果要打印 办法参数以外的变量 那须要用到 上下文 Context
或者 自定义函数
。自定义函数的应用姿态是有局限性的,咱们并不能把日志所波及的变量都抽取到某函数上。如果用上下文 Context 的话,还是得 嵌入业务代码 里,那为啥不间接拼装好日志打呢?
我一度狐疑是不是我的应用姿态不对,跟基友探讨了下,我的利用场景下还得本人抽取 LogUtils
进行日志打印。
02、数据链路追踪
从下面的接口打印的日志以及能很快地排查出 接入层 的问题了,其实重头戏其实是在 解决层 上,回顾下解决层目前做的事件:
在解决层上会有不少的 平台过滤规定 ,这些过滤规定大多都不是针对于音讯模板的,而是针对于 userId(接收者) 的。在这个处理过程中,记录下 每个音讯模板中的每个用户的执行状况 就尤其重要了。
1、定位和排查问题。如果客户反馈用户收不到短信,个别状况下都在这个解决的过程中导致的(可能是被去重,可能是调用接口出问题)
2、对模板执行的整体链路数据分析。一个音讯模板一天发送的量级,中途被 每个规定 过滤的量级,胜利下发的量级以及音讯最初被点击的量级。除了点击数据,其余的数据都起源解决层
基于下面的背景,我设计了一套埋点的规定,在解决 要害链路上 打上对应的点位📝
目前点位的信息是不全的,随着零碎的欠缺和接入各个渠道,这里的点位信息还会持续减少,只有咱们认为有哪些地方是须要记录下来的,就能够减少。
可能看到这里你会感觉有些形象,我申请一次接口打印下日志就容易懂啦:
// 1、接入层打印日志(returnStr 打印处理结果,而 msg 打印出入参信息)2022-01-08 15:44:53.512 [http-nio-8080-exec-7] INFO com.java3y.austin.utils.LogUtils -
{"bizId":"1","bizType":"SendService#send","logId":"34df87fc-0489-46c1-b39f-cafd7652f55b",
"msg":"{\"code\":\"send\",\"messageParam\":{\"extra\":null,\"receiver\":\"13288888888\",\"variables\":{\"title\":\"yyyyyy\",\"contentValue\":\"66661641627893157\"}},\"messageTemplateId\":1}","operateDate":1641627893512,"returnStr":"{\"code\":\"00000\",\"msg\":\" 操作胜利 \"}","success":true,"tag":"operation"}
// 2、解决层打印入口日志(示意胜利生产到 Kafka 的音讯 state=10)2022-01-08 15:44:53.622 [org.springframework.kafka.KafkaListenerEndpointContainer#6-0-C-1] INFO com.java3y.austin.utils.LogUtils -
{"businessId":1000000120220108,"ids":["13288888888"],"state":10,"timestamp":1641627893622}
// 3、解决层打印入口日志(示意胜利生产到 Kafka 的原始日志)2022-01-08 15:44:53.622 [org.springframework.kafka.KafkaListenerEndpointContainer#6-0-C-1] INFO com.java3y.austin.utils.LogUtils -
{"bizType":"Receiver#consumer","object":{"businessId":1000000120220108,"contentModel":{"content":"66661641627893157"},"deduplicationTime":1,"idType":30,"isNightShield":0,"messageTemplateId":1,"msgType":10,"receiver":["13288888888"],"sendAccount":66,"sendChannel":30,"templateType":10},"timestamp":1641627893622}
// 4、解决层打印逻辑过滤日志(state=20,示意这条音讯因为配置了抛弃,曾经抛弃掉)2022-01-08 15:44:53.623 [pool-8-thread-3] INFO com.java3y.austin.utils.LogUtils -
{"businessId":1000000120220108,"ids":["13288888888"],"state":20,"timestamp":1641627893622}
我打印日志的外围逻辑是:
- 在 入口侧(这里包含接口的入口以及刚生产 Kafka 的入口)须要打印出原始的信息。原始信息有了,才好对问题进行定位和排查,至多帮忙咱们复现
- 在处理过程中应用 某个标识 来表明解决的过程(10 代表胜利生产 Kafka,20 代表该音讯曾经被抛弃 …),并且 日志的格局是对立 的这样后续咱们能够对立荡涤该日志信息
至于打日志的过程就很简略了,只有抽取一个 LogUtils
类就好咯:
那对于点击是怎么追踪的呢?其实也好办,在 下发的链接 上拼接 businessId
就好了。只有咱们能拿到点击的数据,在链接上就能够判断是否存在 track_code_bid
字符,进而找到是哪个用户点击了哪个模板音讯。
无论是打点日志还是原始日志,businessId
会跟随着音讯的生命周期始终。而 businessId 的形成只是通过 音讯模板内容 + 工夫 而成
03、后续
当初曾经打印出对应的数据链路信息了,但这是不够的,这只是将数据链路信息写到了服务器的本地上,还须要思考以下的状况:
1、运行利用的服务器个别是集群,日志数据会记录到不同的机器上,排查和定位问题只能登录各个服务器查看
2、链路的数据须要 实时 ,通过提供 Web 后盾的界面性能疾速让 业务方自助 查看整个流程
3、链路的数据须要离线保留用于对数据的剖析以及留备份(本地日志往往寄存不超过 30 天)
前面这些性能都会一一实现,优先会接入 ELK 来有对立查问日志信息的入口以及配置相干的 业务 监控或告警,敬请期待。
点个赞一点都不过分吧?我是 3y,下期见。
关注我的微信公众号【Java3y】除了技术我还会聊点日常,有些话只能轻轻说~ 【对线面试官 + 从零编写 Java 我的项目】继续高强度更新中!求 star!!原创不易!!求三连!!
austin 我的项目源码 Gitee 链接:gitee.com/austin
austin 我的项目源码 GitHub 链接:github.com/austin