在实际项目中,为了方便线上排查问题,尤其是微服务之间调用链路比较复杂的系统中,通过可视化日志的手段仍然是最直接也很方便的排查定位问题的手段,比如大家熟悉的ELK就是一种比较成熟的可视化日志展现方式,在skywalking UI界面上,在服务菜单栏中有Log一项,该项就是用于服务中集成日志。 并提供相关搜索功能 ,根据TraceId快速定位某一次请求全链路日志信息。
skywalking支持的日志框架有:log4j、log4j2、logback等。
本文采用从skywalking agent收集的方式,日志框架使用springboot中使用默认的的logback。
1. 配置SpringBoot项目Skywalking agent
即在启动jvm参数增加
-javaagent后是skywalking-agent.jar的路径,在apache-skywalking-java-agent-9.0.0.tgz解压后的包中
-Dskywalking.agent.service_name是服务的名称,自定义,一般用spring.application.name
-Dskywalking.collector.backend_service是指skywalking oap服务器的ip和端口号
-javaagent:F:\project\git\agent\skywalking-agent\skywalking-agent.jar
-Dskywalking.agent.service_name=skywalking_demo_test
-Dskywalking.collector.backend_service=192.168.110.155:11800
详细步骤参考:SpringBoot集成Skywalking链路追踪-CSDN博客
2. 引入POM依赖
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-logback-1.x</artifactId>
<version>9.0.0</version>
</dependency>
3. 修改日志配置
有两种日志展示方式,一种是随机字符型,一种是展示链路上下文的,任选一种即可。注意项日志的路径和文件的名称修改为自己实际的。
3.1 方式一
skywalking使用traceId对调用链路进行标识,traceId的格式为随机字符,如果没有请求链路,则输出日志中的traceId为N/A。
logback.xml文件
<configuration debug="false" scan="false">
<springProperty scop="context" name="spring.application.name" source="spring.application.name" defaultValue=""/>
<property name="log.path" value="logs/ceshi"/>
<!-- 控制台输出 -->
<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.mdc.TraceIdMDCPatternLogbackLayout">
<pattern>%d{yyyy-MM-dd HH:mm:ss.sss} [%X{tid}] [%thread] %-5level %logger{36} -%msg%n</pattern>
</layout>
</encoder>
</appender>
<!--配置异步输出日志,提升性能-->
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<discardingThreshold>0</discardingThreshold>
<queueSize>1024</queueSize>
<neverBlock>true</neverBlock>
<appender-ref ref="console"/>
</appender>
<!--skywalking grpc 日志收集-->
<appender name="grpc" 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.mdc.TraceIdMDCPatternLogbackLayout">
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{tid}] [%thread] %-5level %logger{36} -%msg%n</Pattern>
</layout>
</encoder>
</appender>
<!--本地info日志保存 ,不需要可以删除-->
<appender name="info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/system-info.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${log.path}/%d{yyyy-MM}/info.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<maxFileSize>50MB</maxFileSize>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.sss} [%X{tid}] [%thread] %-5level %logger{36} -%msg%n</pattern>
</encoder>
</appender>
<!-- 本地error日志保存 ,不需要可以删除 -->
<appender name="error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/system-error.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${log.path}/%d{yyyy-MM}/error.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<maxFileSize>50MB</maxFileSize>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.sss} [%X{tid}] [%thread] %-5level %logger{36} -%msg%n</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
</appender>
<root level="info">
<appender-ref ref="console"/>
<appender-ref ref="info"/>
<appender-ref ref="error"/>
<appender-ref ref="grpc"/>
</root>
</configuration>
3.2 方式二
由于traceId仅表示为随机字符,可读性较差。幸运的是,skywalking也认识到这一点,于是又引入了一个新的概念:链路上下文SW_CTX,所谓链路上下文,其实与traceId的作用相同,但他的好处是可读性强,其格式为SW_CTX:[服务名, 实例名, traceId, traceSegmentId, spanId]。
<configuration debug="false" scan="false">
<springProperty scop="context" name="spring.application.name" source="spring.application.name" defaultValue=""/>
<property name="log.path" value="logs/ceshi"/>
<!-- 控制台输出 -->
<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.mdc.TraceIdMDCPatternLogbackLayout">
<pattern>%d{yyyy-MM-dd HH:mm:ss.sss} [%X{sw_ctx}] [%thread] %-5level %logger{36} -%msg%n</pattern>
</layout>
</encoder>
</appender>
<!--配置异步输出日志,提升性能-->
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<discardingThreshold>0</discardingThreshold>
<queueSize>1024</queueSize>
<neverBlock>true</neverBlock>
<appender-ref ref="console"/>
</appender>
<!--skywalking grpc 日志收集-->
<appender name="grpc" 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.mdc.TraceIdMDCPatternLogbackLayout">
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{sw_ctx}] [%thread] %-5level %logger{36} -%msg%n</Pattern>
</layout>
</encoder>
</appender>
<!--本地info日志保存 ,不需要可以删除-->
<appender name="info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/system-info.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${log.path}/%d{yyyy-MM}/info.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<maxFileSize>50MB</maxFileSize>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.sss} [%X{sw_ctx}] [%thread] %-5level %logger{36} -%msg%n</pattern>
</encoder>
</appender>
<!-- 本地error日志保存 ,不需要可以删除 -->
<appender name="error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/system-error.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${log.path}/%d{yyyy-MM}/error.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<maxFileSize>50MB</maxFileSize>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.sss} [%X{sw_ctx}] [%thread] %-5level %logger{36} -%msg%n</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
</appender>
<root level="info">
<appender-ref ref="console"/>
<appender-ref ref="info"/>
<appender-ref ref="error"/>
<appender-ref ref="grpc"/>
</root>
</configuration>
4. 启动SpringBoot项目
4.1. 启动springboot项目
没有请求链路的系统日志,比如项目启动时的
4.2. 发送一个http请求
4.3. 查看控制台或文件日志
按照3.1方式配置的日志
按照3.2方式配置的日志
从输出的日志可以看到,该请求的调用链上有了TraceId,可以根据这个TraceId在Skywalking日志里面搜索
5. 在Skywalking控制台查看链路日志
访问Skywalking控制台
点击Log选项卡
如下图所示,可以看到TraceId
查看某一个链路日志
复制TraceId,搜索即可以看到某次http请求的所有日志信息