Java应用层数据链路追踪(附优雅打印日志姿势)
我是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
Java应用层数据链路追踪(附优雅打印日志姿势)的更多相关文章
- 大数据项目中js中代码和java中代码(解决Tomcat打印日志中文乱码)
Idea2018中集成Tomcat9导致OutPut乱码找到tomcat的安装目录,打开logging.properties文件,增加一行代码,覆盖默认设置,将日志编码格式修改为GBK.java.ut ...
- 普通Java项目中使用Sl4j+Log4j2打印日志
因工作需要,采用JavaFx开发了一个windows窗口程序.在开发过程中,由于没有引入日志框架,只能自己手动在控制台打印些信息,给调试带来了很多麻烦:因此决定引入日志框架.由于之前接触的项目 ...
- Java中打印日志,这4点很重要!
目录 一.预先判断日志级别 二.避免无效日志打印 三.区别对待错误日志 四.保证记录完整内容 打印日志,要注意下面4点. 一.预先判断日志级别 对DEBUG.INFO级别的日志,必须使用条件输出或者使 ...
- android112 c代码打印日志,c反编译调用java
activity: package com.itheima.ccalljava; import android.os.Bundle; import android.app.Activity; impo ...
- Java如何打印日志
以下为<正确的打日志姿势>学习笔记. 什么时候打日志 1.程序出现问题,只能通过 debug 功能来定位问题,很大程度是日志没打好.良好的系统,通过日志就能进行问题定位. 2.if-els ...
- 为何要打印日志?C++在高并发下如何写日志文件(附源码)?
为何要打印日志?让程序裸奔不是一件很快乐的事么? 有些BUG就像薛定谔的猫,具有波粒二象性,当你试图去观察它时它就消失了,当你不去观察它时,它又会出现.当你在测试人员面前赌咒发誓,亲自路演把程序跑一遍 ...
- java IDE 中安装 lombok plugin 插件,并使用 @Slf4j 注解打印日志初体验
lombok 插件介绍: IntelliJ IDEA官方插件页面:https://plugins.jetbrains.com/plugin/6317-lombok-plugin 使用lombok之后, ...
- 用SLF4j/Logback打印日志-3
在 用SLF4j/Logback打印日志-1 和 用SLF4j/Logback打印日志-2 中分别介绍了Logback记录日志的基本原理并重点介绍了输出源配置.本篇介绍一些性能和技巧性的东西. 性能 ...
- Java动态,安全追踪工具
Java动态,安全追踪工具 在我们日常的开发中,总是难以避免的要解决线上的问题.如果线上的问题我们在本地调试的时候无论调试多少次发现明明本地调用了这个方法呀,怎么线上就是没调呢?还有就是出了问题的时候 ...
随机推荐
- 学习Java第10天
今天所作的工作: 1.线程 2.网络通信 明天工作安排: 做点教材后的案例,复习所学内容 总结一下,10天的时间,看完了Java从入门到精通,只能说是看完了,这里加一个表情笑哭,应该算是知道Java的 ...
- 被mybatis一级缓存坑了
目录 背景 场景 原因 解法 参考 背景 项目中出现了这样一个问题,就是select出来的数据和数据库里的数据不一样,就非常的奇怪,发现原来是mybatis的缓存导致的,经过查询资料发现这是mybat ...
- C++学习Day 1
c++的函数需要声明才能再写他的定义,声明可以写多次,如果执行在main之前可以不写,全写不会犯错,现在看好像c++的函数定义里没有out,也没有变量的public和private(后面有再改) 声明 ...
- 解决SpringBoot连接Nacos集群报400问题
问题描述 搭建一个Nacos集群,使用 SpringBoot 程序连接 Nacos 集群,在启动的时候报异常,程序启动失败,而后程序假死.详细控制台日志信息如下: failed to req API: ...
- Android Studio 插件(不定期更新)
GsonFormat 根据JSONObject格式的字符串,自动生成实体类参数. 安装 1.Android studio File->Settings-->Plugins -->in ...
- Redis的配置文件redis.conf详解
Redis的配置文件位于redis的安装目录下,一般不要直接操作出厂设置的配置文件,需要对其进行备份.# Redis的配置文件样例: # Redis configuration file exampl ...
- DNS域名解析之正向解析
DNS域名解析之正向解析 1.DNS介绍 2.DNS正向解析实验 1.DNS定义:DNS是"域名系统"的英文缩写.它作为将域名和IP地址相互映射的一个分布式数据库,能够使人更方便地 ...
- 微服务与SpiringBoot
微服务: 微服务是一种架构风格,一般说到微服务都会说"微服务架构",即一个系统的各个功能(如结账,用户等)独立出来,以及各个服务独立出来,每个模块是可独立替换.可独立升级的软件单元 ...
- 【软件实施面试】MySQL和Oracle联合查询以及聚合函数面试总结
软件实施面试系列文章第二弹,MySQL和Oracle联合查询以及聚合函数的面试总结.放眼望去全是MySQL,就不能来点Oracle吗?之前面过不少公司,也做过不少笔试题,现在已经很少做笔试题了.你肚子 ...
- tep集成mitmproxy录制流量自动生成用例
使用 操作过程非常简单,流程如下: ①配置过滤域名 必须配置,不然会有很多无效流量造成数据冗余. ②启动代理 「示例」使用了反向代理,tep自带FastApi启动Mock服务: 「实际」使用正向代理, ...