skywalking番外01 - 如何扩展%tid的logback占位符

本文涉及的产品
应用实时监控服务-用户体验监控,每月100OCU免费额度
应用实时监控服务-应用监控,每月50GB免费额度
日志服务 SLS,月写入数据量 50GB 1个月
简介: skywalking番外01 - 如何扩展%tid的logback占位符

skywalking番外01 - 如何扩展%tid的logback占位符

配置

<appender name="FILE"  class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>./logs/ruoyi-vue-pro-%d{yyyy-MM-dd_HH}.log</FileNamePattern>
            <MaxHistory>3</MaxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
                <pattern>%d{ISO8601} | %tid | %thread | %-5level | %msg%n</pattern>
            </layout>
        </encoder>
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <MaxFileSize>10MB</MaxFileSize>
        </triggeringPolicy>
    </appender>

这是skywalking使用%tid做占位符来展示TraceId的方式.那么究竟怎么实现的呢?

Layout

观察配置很容易发现在/appender/encoder/layout中class属性指向的那个类是skywalking提供的工具包中的类.

package org.apache.skywalking.apm.toolkit.log.logback.v1.x;
import ch.qos.logback.classic.PatternLayout;
public class TraceIdPatternLogbackLayout extends PatternLayout {
    public TraceIdPatternLogbackLayout() {
    }
    static {
        defaultConverterMap.put("tid", LogbackPatternConverter.class.getName());
    }
}

这个类很简单,看似什么都没做,就是继承了Logback的PatternLayout类,并在该类的static 变量defaultConverterMap放入了一个key为tid,一个value为Sting类型的className.

Converter

package org.apache.skywalking.apm.toolkit.log.logback.v1.x;
import ch.qos.logback.classic.pattern.ClassicConverter;
import ch.qos.logback.classic.spi.ILoggingEvent;
public class LogbackPatternConverter extends ClassicConverter {
    public LogbackPatternConverter() {
    }
    public String convert(ILoggingEvent iLoggingEvent) {
        return "TID: N/A";
    }
}

看起来这个Converter也很简单,就是继承了logback的ClassicConverter,并实现了converter方法,返回一个固定值!根本就不是动态的啊!

所以,运行过工程,且没有打探针包的朋友们会发现就是输出了TID: N/A.而有探针的情况下,会输出动态的TraceId.那么问题肯定在探针中了.

探针增强

skywalking中探针在做增强的时候,在源码中会有被增强类的全类名来匹配,所以找到了这样的代码:

package org.apache.skywalking.apm.toolkit.activation.log.logback.v1.x;
public class LogbackPatternConverterActivation extends ClassInstanceMethodsEnhancePluginDefine {
    public static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.toolkit.activation.log.logback.v1.x.PrintTraceIdInterceptor";
    public static final String ENHANCE_CLASS = "org.apache.skywalking.apm.toolkit.log.logback.v1.x.LogbackPatternConverter";
    public static final String ENHANCE_METHOD = "convert";
    /**
     * @return the target class, which needs active.
     */
    @Override
    protected ClassMatch enhanceClass() {
        return byName(ENHANCE_CLASS);
    }
    @Override
    public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
        return new InstanceMethodsInterceptPoint[] {
            new InstanceMethodsInterceptPoint() {
                @Override
                public ElementMatcher<MethodDescription> getMethodsMatcher() {
                    return named(ENHANCE_METHOD).and(takesArgumentWithType(0, "ch.qos.logback.classic.spi.ILoggingEvent"));
                }
                @Override
                public String getMethodsInterceptor() {
                    return INTERCEPT_CLASS;
                }
            }
        };
    }
}

删除掉多余的代码,可以看到,通过匹配ENHANCE_CLASS,以及ENHANCE_METHOD,然后返回一个增强过的类INTERCEPT_CLASS,即org.apache.skywalking.apm.toolkit.activation.log.logback.v1.x.PrintTraceIdInterceptor

package org.apache.skywalking.apm.toolkit.activation.log.logback.v1.x;
public class PrintTraceIdInterceptor implements InstanceMethodsAroundInterceptor {
    @Override
    public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
        Object ret) throws Throwable {
        if (!ContextManager.isActive()) {
            if (allArguments[0] instanceof EnhancedInstance) {
                String tid = (String) ((EnhancedInstance) allArguments[0]).getSkyWalkingDynamicField();
                if (tid != null) {
                    return "TID:" + tid;
                }
            }
        }
        return "TID:" + ContextManager.getGlobalTraceId();
    }
}

就是这个类去上下文管理器中去取来了全局流水号.

学以致用

那么对于Logback可能陌生的同学,看完这篇应该就大致知道怎么扩展一个logback的占位符了吧.

  1. 继承ClassicConverter, 在convert方法中写入实际需要给占位符替换的内容.
  2. 继承PatternLayout,在static的map中放入(占位符,转换类类名)映射对.
  3. 配置文件中的layout指定class为该Layout的全类名.另外,Encoder节点的class也要使用ch.qos.logback.core.encoder.LayoutWrappingEncoder.

再说一种其他的方式, 如果用过spring cloud sleuth做全链路流水号的朋友会发现他们使用的占位符是这样的:%X{X-B3-TraceId:-},%X{X-B3-SpanId:-}.这是一种%X{key}的形式,使用了logback的MDC进行的扩展.可以参考这篇文章:<logback扩展字段>.

举例

那么究竟实际上有什么使用场景呢,举个例子: 我们不知道这个API是哪个用户登陆后进行的操作.

第一种解决方案: 拦截servlet的filter,从session中获取用户ID,打一条日志. 实际查询时根据全链路流水号来查询用户号.或者拦截spring mvc也是同理,不过是filter级别更高.

第二种解决方案:拦截servlet后,将其用户ID放入ThreadLocal中,利用本篇学到的扩展logback占位符的方式,输出到每一行日志中.

  • 两种方式都行,各取所需.

其他日志框架的扩展

日志框架有很多,需要去官方看文档学习. 而我发现skywalking中基本有了我们常用的日志框架的扩展占位符的方式,是一个很好的例子.

skywalking/apm-snifer/apm-tookit-activation包下涵盖了对log4j-1.x/ log4j-2.x/ logback-1.x/ logging-common的扩展.(github墙高筑,这里的链接改成gitee中的链接了).

相关实践学习
通过云拨测对指定服务器进行Ping/DNS监测
本实验将通过云拨测对指定服务器进行Ping/DNS监测,评估网站服务质量和用户体验。
目录
相关文章
|
8月前
|
XML Java 数据格式
【二十九】springboot整合logback实现日志管理
【二十九】springboot整合logback实现日志管理
252 1
|
监控 Java API
最简日志打印规范
个人认为,如果在公司的野蛮生长阶段,一些基础类库不做约束,很可能“埋坑”,形成技术债务,最终为此付出代价。本文讲解一个最简的日志打印规范。 事实上,日志打印规范互联网上已有很多,但大多比较冗长(记不住),也不太契合我们团队(关注点不契合)。
3981 0
|
5月前
|
Java 应用服务中间件 HSF
Java应用结构规范问题之配置Logback以在控制台输出日志的问题如何解决
Java应用结构规范问题之配置Logback以在控制台输出日志的问题如何解决
|
5月前
|
数据可视化 Java API
如何在项目中快速引入Logback日志并搭配ELK使用
如何在项目中快速引入Logback日志并搭配ELK使用
|
监控 Java API
通过编码方式构建SkyWalking 的Trace-中篇
通过编码方式构建SkyWalking 的Trace-中篇
518 0
|
8月前
|
SQL druid Java
三步实现maven工程集成logback日志框架(日志按天滚动生成文件)并附源码
三步实现maven工程集成logback日志框架(日志按天滚动生成文件)并附源码
294 0
|
人工智能 监控 Java
SpringBoot实战(十六):集成Skywalking调用链监控系统
SpringBoot实战(十六):集成Skywalking调用链监控系统
822 0
logging 学习最终版-配置的不同级别日志打印的颜色
logging 学习最终版-配置的不同级别日志打印的颜色
|
存储 Java 应用服务中间件
日志框架以及如何使用LogBack记录程序
日志框架以及如何使用LogBack记录程序
138 0
|
设计模式 缓存 Java
logback之 FileAppender 的原理及避坑建议
buffer 机制 通俗来说就是化零为整,把少量多次变成多量少次;具体来说就是进行流量整形,把突发的大数量较小规模的 I/O 整理成平稳的小数量较大规模的 I/O,以减少响应次数
849 0
logback之 FileAppender 的原理及避坑建议

热门文章

最新文章