一、背景
最近在给项目搭建日志平台的时候,采用的方案是 SkyWalking
+ ELK
日志平台,但发现 ELK 日志平台中的日志没有 Trace ID
,导致无法追踪代码报错的整体链路。
空哥提示:
Trace ID
是分布式追踪中用来唯一标识一个服务请求或事务的 ID。在微服务架构中,一个请求可能会经过多个服务节点,Trace ID 帮助追踪和关联整个请求链路中的所有日志和性能数据。
既然 SkyWalking 提供了日志的链路追踪,为什么 ELK 没有链路追踪 ID 呢? 带着这个疑问我们继续往下看。
SkyWalking 和 ELK 是如何联系在一起的?我们一步一步往下看。
SkyWalking 本来就带有链路追踪,而且通过搭建 SkyWalking-UI 服务就可以以通过界面来查看日志。
SkyWalking 整体架构如下:
FROM http://skywalking.apache.org/
整体的架构图如下所示,
流程如下:
那么这两款日志平台有很多类似之处,直接用其中一种不行吗?
SkyWalking 优点是服务性能分析和链路追踪,但也有不足之处。
Skywalking 监控 Java、Golang、Node、.NET 语言的链路都是采用了 SDK 或者 Agent 的方式将数据上报到 Skyalking 后端,不过都是采用 gRPC 的方式和后端交互,比如我们项目是 Java 项目,SkyWalking Agent 采集到后端的 Java 日志后进行上报。而对于 Nginx 则需要写 Lua 脚本来和 SkyWalking AOP 服务通信,对于 MySQL 日志也需要单独写脚本来上报日志。
下图分别为 SkyWalking 和 Kibana 的可视化界面
当然是可以,但是 ELK 并没有日志追踪的能力,需要借助其他工具来实现,以下是常见的做法。
通过 SkyWalking 的自定义日志布局类 TraceIdPatternLogbackLayout,将分布式追踪系统中的追踪 ID(Trace ID)嵌入到日志中。
在 logback-spring.xml 日志配置文件中配置控制台打印的时候使用带有 SkyWalking 的 TraceId 的日志布局。如下代码所示,使用了 TraceIdPatternLogbackLayout 日志布局,然后在日志格式中加入了 [%tid],就能将 trace id 打印出来。
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- 定义一个带有TraceId的日志布局 -->
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
<pattern>${CONSOLE_LOG_PATTERN:-%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) [%tid] %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}</pattern>
</layout>
<root level="debug">
<appender-ref ref="STDOUT" />
</root>
</configuration>
程序运行期间就会在控制台窗口打印出 trace id,如下所示:
然后通过 Filebeat 和 Logstash 将日志采集并上传到 Elasticsearch。如下图索索,Kibana 根据 trace id 来查看链路日志。
MDC 的方案就是自己生成一个随机 ID 作为 traceId,然后 put 到 MDC 里面。如下代码所示:
MDC.put("traceId", UUID.randomUUID().toString());
MDC(Mapped Diagnostic Context)用于存储运行上下文的特定线程的上下文数据。MDC 主要依赖于线程局部存储(Thread-Local Storage),这意味着每个线程都有自己独立的 MDC 数据。属于该线程的任何代码都可以轻松访问线程的 MDC 中存在的值。
使用方式和原理可以看空哥之前写的一篇文章:
从 1.5 开始搭建一个微服务框架——链路追踪 traceId
先贴个原理图给大家看看:
Kibana 可查看某一条日志相近的多条日志,如下图所示,点击 View surrounding documents 按钮即可。
然后就能看到与之时间相近的多条日志
但是这种方式不易准确辨别出相关联的上下文的日志。不易辨别的原因如下:
SkyWalking和 ELK 各自在 APM 与日志管理领域发挥着重要作用,尽管原生 ELK 不直接支持链路追踪,但通过与 SkyWalking 的集成,可以互补优势,共同提升微服务架构下的可观测性。