logback和log4j日志框架堆栈信息添加TraceId方式
作者:lllllLiangjia
背景
TraceId是我在项目上自定义的,作为链路追踪来使用。至于为什么没有用市面上skywalking此类现成的链路追踪,是因为目前这个项目是boot单体,也不是分布式,不想引入过多比较复杂的依赖项,造成不必要的维护麻烦。
使用traceId只是来准确定位某个请求的日志信息,自己实现的话比较轻量化,也能够满足项目的开发和维护需求。
当请求访问时,被过滤器拦截到,生成一个唯一的traceId存放在MDC中(分布式项目可以通过请求头获取上游服务传过来的traceId),MDC是ThreadLocal类型线程安全的。
日志xml配置写上traceId会自动读取MDC。
logback日志框架
由于之前项目是使用的logback日志框架,如果只在xml日志文件中配置traceId的话,当报错时候输出的堆栈信息内不会保存traceId。
到时候线上排查问题,无法通过grep命令筛选出来报错的堆栈信息,也就不能快速定位代码中的报错位置。
堆栈信息不携带traceId
xml配置文件中的配置
堆栈信息携带traceId
logback想要在堆栈信息中添加traceId需要继承ThrowableProxyConverter,重写里面的方法。
import ch.qos.logback.classic.pattern.ThrowableProxyConverter; import ch.qos.logback.classic.spi.IThrowableProxy; import org.apache.commons.lang3.StringUtils; import org.slf4j.MDC; public class CompressedStackTraceConverter extends ThrowableProxyConverter { public CompressedStackTraceConverter() { } @Override protected String throwableProxyToString(IThrowableProxy tp) { String original = super.throwableProxyToString(tp); String traceId = MDC.get("traceId"); if (StringUtils.isBlank(traceId)) { traceId = ""; } traceId = "\t[ably-stack]\t[" + traceId + "]"; return original.replaceAll("\n", traceId + "\n"); } }
此时的xml配置
<?xml version="1.0" encoding="UTF-8"?> <configuration> <conversionRule conversionWord="ex" converterClass="com.example.springbootdemo.configuration.httpglobal.CompressedStackTraceConverter"/> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <pattern xml:space="preserve"> %d{yyyy-MM-dd HH:mm:ss.SSS}|-|%lsn|-|%thread|-|%X{traceType}|-|%X{traceId}|-|%logger{80}:%L|-|%msg|-|%ex|-|%n </pattern> </encoder> </appender> <root level="info"> <appender-ref ref="STDOUT"/> </root> </configuration>
这样logback框架就可以打印堆栈信息的时候携带traceId了
log4j日志框架
目前这个新项目使用的log4j这个框架,这里的traceId也是放在MDC中。
堆栈信息不携带traceId
堆栈信息携带traceId
当我配置好traceId后,开始配置堆栈信息中的traceId,发现ThrowableProxyConverter是logback包下面的,无法使用它来添加。
于是我在网上找是否log4j有对应的像logback这种接口可以操作堆栈信息的。无果!(也有可能我没找到)。
后来偶然查到%throwable可以支持更改单个堆栈跟踪元素,我就想可不可以使用它来添加traceId。
通过了解%throwable的常用方法,看到了配合{suffix(pattern)}使用,可以在每个堆栈帧的末尾添加模式输出。
于是抱着试一试的态度就打印traceId,结果是可以的。
对应的traceId在堆栈信息以及主日志中都打印了出来
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。