Skywalking 是一款优秀的国产 APM 工具,包括了分布式追踪、性能指标分析、应用和服务依赖分析等。ELK 是一个完整的集中式日志系统,提供日志的收集、传输、存储、分析等一整套解决方案。将 Skywalking 的 trace id 集成到 ELK 可以打通两款工具,根据 trace id 搜索出整条链路上的所有日志,可以快速定位问题。下文通过目前最流行的两款 java 日志工具 logback 和 log4j2,介绍具体集成方案,并在最后通过 demo 演示集成效果。
【Note】有关 ELK 和 Skywalking 的安装配置不是本文重点,未做介绍,不会的可寻求度娘。Logback 和 log4j2 的使用和配置可参考本专栏中的文章:“JAVA 应用日志最佳实践”。
Logback 集成 Skywalking Trace ID
apm-toolkit-logback 是一款 skywalking 的 logback 插件,通过它可以将 trace id输出到日志中。实际使用中也很方便,两步就可以完成:
- 在 pom 文件中增加 maven 依赖
- 修改 logback 配置文件,添加 trace id
Maven 依赖
代码语言:txt复制<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-logback-1.x</artifactId>
<version>8.1.0</version>
</dependency>
apm-toolkit-logback 插件最新版为 8.1.0,更多版本可在maven中央仓库查找:https://mvnrepository.com/artifact/org.apache.skywalking/apm-toolkit-logback-1.x
Logback 配置
Logback 配置文件中,在 pattern 中添加 %tid,就可以在日志行中输出调用链ID。下面的示例为本文 demo 中 的 BMS-WEB 的logback 配置。
代码语言:txt复制<appender name="fileAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/logs/bms-web.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>/logs/bms-web-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
<MaxHistory>20</MaxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>500MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
<!-- 日志格式中添加 %tid 即可输出 trace id -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %tid %t %logger{36}: %msg%n</pattern>
</layout>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
Log4j2 集成 Skywalking Trace ID
apm-toolkit-log4j 是 skywalking 提供的支持 log4j2 的插件,配置上和 logback 类似,添加 maven 依赖,修改 log4j2 的配置文件即可。
Maven 依赖
代码语言:txt复制<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId> apm-toolkit-log4j-2.x</artifactId>
<version>8.1.0</version>
</dependency>
apm-toolkit-log4j 插件最新版为 8.1.0,更多版本可在maven中央仓库查找:https://mvnrepository.com/artifact/org.apache.skywalking/apm-toolkit-log4j-2.x
Log4j2 配置
相对Logback,Log4j2的配置很简单,只需要在配置文件中直接引用 %traceId 即可。下面的示例为本文 demo 中 的 store-service 的log4j2 配置。
代码语言:txt复制<Appenders>
<RollingFile name="fileLog" fileName="/logs/store-service.log" filePattern="store-service-%d{yyyy-MM-dd}-%i.log">
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
<!-- 日志格式中添加 %traceId 即可输出 trace id -->
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %traceId %t %logger{36}: %msg%n"/>
<Policies>
<TimeBasedTriggeringPolicy/>
<SizeBasedTriggeringPolicy size="500 MB"/>
</Policies>
</RollingFile>
</Appenders>
Logstash 解析 Trace ID
通过 grok 自定义正则表达式,可以从日志行中抽取出 trace id,就可以在 es 中建立索引,方便日志检索。由于 skywalking 的 trace id 占用了固定的 54 个字符,因而这里简单使用 (?<trace_id>[0-9a-f.]{54}
即可抽取出 trace id。下面的配置示例为本文中 demo 的具体配置(使用 filebeat 作为日志输入)。
input {
beats {
port => 5044
codec => "json"
}
}
filter {
grok {
match => {
# 从原始日志中解析出 trace_id 等其它需要的字段
"message" => "^(?<timestamp>d{4}-d{2}-d{2}sd{2}:d{2}:d{2}.d{3})s(?<level>w{4,5})s TID:s*(?<trace_id>[0-9a-f.]{54})s%{DATA:thread}s%{DATA:class}:%{GREEDYDATA:content}$"
}
}
mutate {
remove_field => "message" # 删除原始日志内容节省存储和带宽
}
}
output {
elasticsearch {
hosts => ["http://xxx.xxx.xxx.xxx:9200"]
index => "bms-log" # ES 重建立索引
}
}
至此,基于 java 应用的日志配置就完成了,下面通过具体的例子展示下实际效果。
Demo
如下图所示,Demo 例子中包含两个服务:BMS-Web 和 Store-service,BMS-Web 接受 HTTP 请求,并转发给后台 Store-service 进行处理。BMS-Web 使用了 logback 日志包,Store-service 使用了 log4j2,上文中配置示例即为两个服务的日志配置。
Demo 中通过 filebeat 将日志传输到 logstash 中,经过过滤和解析再存储到 ES 中。最后,通过 kibana 可以看到及时日志数据。下面两图展示了添加图书链路(trace id: 29d7cc9f600542b1acc5fd7ed002085e.466.15998044380700001
)的集成效果。首先,在 skywalking 中搜索 trace id 可以看到从 web 请求到写 mysql 的完整调用链路;其次,在 kibana 中按 trace id 可以查询出整条链路上的所有日志。
整合 Skywalking 和 ELK 后,通过 trace id,在 skywaling 中快速看到链路中哪个环节出了问题,然后在 ELK 中按 trace id 搜索对应的系统日志,这样就可以很方便的定位出问题,为线上排障提供了方便。