一、介绍
在上一篇文章skywalking全链路追踪中我们介绍了在微服务项目中使用skywalking进行服务调用链路的追踪。
本文在全链路追踪的基础上,我们介绍如何使用skywalking对一次调用链路上进行日志收集。
skywalking日志收集方式有两种:
从日志文件中收集
在微服务项目中,每一个微服务所产生的日志均会保存到本地日志文件或远程文件服务器中,skywalking提供Filebeat、Fluentd、Fluent-bit三种方式通过kafka或http读取日志文件并将其按照调用链路进行收集。
Filebeat
此方式应用于本地日志文件场景。由使用kafka进行日志收集,需要在skywalking客户端的配置文件
agent.conf
和服务端的配置文件application.yml
中对kafka-fetcher
进行配置,并在skywalking客户端添加配置文件filebeat.yml
。Fluentd
此方式应用于本地日志文件场景。使用kafka进行日志收集,需要在skywalking客户端的配置文件
agent.conf
和服务端的配置文件application.yml
中对kafka-fetcher
进行配置,并在skywalking客户端添加配置文件fluentd.conf
。Fluent-bit
此方式应用于远程文件服务器场景。使用http进行日志收集,需要在skywalking服务端的配置文件
application.yml
中对core
或receiver-sharing-server
的restHost:restPort
项进行配置。并添加配置文件fluent-bit.conf
。
从skywalking客户端收集
在微服务项目中,每一个微服务都会有一个日志配置文件用于规范日志的输出格式。skywalking客户端提供了工具将输出的日志通过消息队列(如kafka)或http发送到skywalking服务端。此方式只需要对日志配置文件进行修改。
skywalking支持的日志框架有:log4j、log4j2、logback。
我们本次的日志收集演示采用从skywalking客户端收集的方式,并使用springboot推荐的日志框架logback。
二、添加依赖
在各个微服务的pom.xml
中添加以下依赖
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-logback-1.x</artifactId>
<version>8.9.0</version>
</dependency>
三、修改日志配置
在我们添加的依赖apm-toolkit-logback-1.x
中,包含了大量适配于logback与skywalking的Appender
、Encoder
以及Layout
实现类。下面我们需要对日志配置文件进行修改。
在微服务系统的一次请求调用链中,可能出现多个服务之间相互调用的场景(如商品服务调用订单服务,订单服务调用支付服务)。而这些服务显然处于不同的进程甚至不同的服务器,如何确定一个请求的调用链路中调用了哪些服务呢?
1. 添加链路表示traceId
skywalking使用traceId
对调用链路进行标识,traceId
的格式为随机字符,如果没有请求链路,则输出日志中的traceId
为N/A
。如果以羊肉串类比,多个羊肉被同一个棍子串起来,羊肉就类比为链路上的多个服务,棍子就类比为traceId
。
修改logback.xml
日志配置文件
在日志的输出格式定义中添加
%tid
,并修改对应的Layout
实现类为TraceIdPatternLogbackLayout
。<?xml version="1.0" encoding="UTF-8"?> <configuration> <!-- 日志输出格式 --> <property name="log.pattern" value="%black(%contextName-) %red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %boldMagenta([%tid]) %highlight(%-5level) %boldMagenta(%logger{36}) - %gray(%msg%n)"/> <!-- 控制台输出 --> <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"> <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout"> <Pattern>${log.pattern}</Pattern> </layout> </encoder> </appender> <root level="info"> <appender-ref ref="console"/> </root> </configuration>
没有请求链路的系统日志
当我们向接口发送请求时
请求如下:
日志如下,从输出的日志可以看到,该请求的调用链为8012端口的商品服务调用8021端口的订单服务,8021端口的订单服务调用8032端口的支付服务,在该调用链上各个服务的traceId
相同。
进入skywalking服务端的页面,我们查看该调用链路,该链路的traceId
与日志中打印的traceId
一致。
2. 添加链路上下文
由于traceId
仅表示为随机字符,可读性较差。幸运的是,skywalking也认识到这一点,于是又引入了一个新的概念:链路上下文SW_CTX,所谓链路上下文,其实与traceId
的作用相同,但他的好处是可读性强,其格式为SW_CTX:[服务名, 实例名, traceId, traceSegmentId, spanId]
。
同样的,如果没有请求链路,则输出日志中的链路上下文为SW_CTX:[服务名, 实例名, N/A, N/A, -1]
。
修改logback.xml
日志配置文件
将日志的输出格式定义中表示
traceId
的%tid
修改为%sw_ctx
即可<?xml version="1.0" encoding="UTF-8"?> <configuration> <!-- 日志输出格式 --> <property name="log.pattern" value="%black(%contextName-) %red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %boldMagenta([%sw_ctx]) %highlight(%-5level) %boldMagenta(%logger{36}) - %gray(%msg%n)"/> <!-- 控制台输出 --> <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"> <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout"> <Pattern>${log.pattern}</Pattern> </layout> </encoder> </appender> <root level="info"> <appender-ref ref="console"/> </root> </configuration>
重启项目,查看没有请求链路的系统日志
当我们向接口发送请求时
请求如下
日志如下,由于打印出的上下文日志包含信息量过长,只截取其部分日志。
进入skywalking服务端的页面,我们查看该调用链路,该调用链路同样是商品服务的8011端口服务调用订单服务的8022端口服务,且该调用链的traceId
与日志中打印的traceId
一致。
3. 异步日志
skywalking客户端还支持日志的异步打印,就是说业务代码与日志打印采用不同的线程执行,提高接口响应速度。
修改logback.xml
日志配置文件
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 日志输出格式 -->
<property name="log.pattern"
value="%black(%contextName-) %red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %boldMagenta([%tid]) %highlight(%-5level) %boldMagenta(%logger{36}) - %gray(%msg%n)"/>
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
<Pattern>${log.pattern}</Pattern>
</layout>
</encoder>
</appender>
<!-- 异步输出 -->
<appender name="console-async" class="ch.qos.logback.classic.AsyncAppender">
<discardingThreshold>0</discardingThreshold>
<queueSize>1024</queueSize>
<neverBlock>true</neverBlock>
<appender-ref ref="console"/>
</appender>
<root level="info">
<appender-ref ref="console-async"/>
</root>
</configuration>
四、收集链路日志
skywalking客户端通过gRpc
将输出的日志发送给skywalking服务端,skywalking服务端根据traceId
去分析日志,然后通过skywalking服务端页面可以查看指定调用链路中所有服务所输出的日志。
修改
logback.xml
日志配置文件,只需要添加GRPCLogClientAppender
即可<?xml version="1.0" encoding="UTF-8"?> <configuration> <!-- 日志输出格式 --> <property name="log.pattern" value="%black(%contextName-) %red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %boldMagenta([%tid]) %highlight(%-5level) %boldMagenta(%logger{36}) - %gray(%msg%n)"/> <!-- 控制台输出 --> <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"> <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout"> <Pattern>${log.pattern}</Pattern> </layout> </encoder> </appender> <!-- 异步输出 --> <appender name="console-async" class="ch.qos.logback.classic.AsyncAppender"> <discardingThreshold>0</discardingThreshold> <queueSize>1024</queueSize> <neverBlock>true</neverBlock> <appender-ref ref="console"/> </appender> <!-- 使用gRpc将日志发送到skywalking服务端 --> <appender name="grpc-log" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender"> <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"> <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout"> <Pattern>${log.pattern}</Pattern> </layout> </encoder> </appender> <root level="info"> <appender-ref ref="console-async"/> <appender-ref ref="grpc-log"/> </root> </configuration>
重启项目,并向接口发送请求
查看输出的日志
进入skywalking页面查看
查看该调用链路上各服务的日志,我们以商品服务的日志为例,在调用链路中电击商品服务,可查看对应的实例详情,再点击相关的日志,即可查看商品服务该实例所产生的日志列表,该列表中每一行即为代码中打印的一行日志,点击可查看该行完整的日志信息。
到这里,skywalking的日志收集我们就介绍完了。
纸上得来终觉浅,绝知此事要躬行。
————————我是万万岁,我们下期再见————————