手把手教你skywalking二开之扩展logback日志%tid

这里是weihubeats ,觉得文章不错可以关注公众号小奏技术,文章首发。拒绝营销号,拒绝标题党

skywalking 版本

  • 9.4.0

背景

目前系统服务全链路透传使用的是skywalking,大家都知道接入skywalking会再log里面添加一个tid的打印

比如这样。那么如果我们想新增一个我们自定义的标签怎么处理呢?比如我想新增一个uid 变成

java 复制代码
2023-12-19 22:07:01.361  INFO  10 [TID:8e3374d0c5394da58fa58b12f1a8c6ae.163.17029696213611565] [Uid:234]

tid的实现原理分析

apm-toolkit-logback-1.x 修改

这里我们以logback为例

一般我们在log.xml里面都会新增一个占位符,比如

xml 复制代码
    <property name="CONSOLE_LOG_PATTERN" value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(%X{tl:-}){yellow} %clr(${PID:- }){magenta} %clr([%tid]){faint}  %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>

    <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>${CONSOLE_LOG_PATTERN}</pattern>
            </layout>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
    </appender>

这里我们就加了tid。如果要实现我们自定义的uid的话,我们肯定也是要加一个占位符比如uid

我们首先看看skywalking是如何实现的

首先在LogbackPatternConverter类实现ClassicConverter给一个默认值

java 复制代码
public class LogbackPatternConverter extends ClassicConverter {
    /**
     * As default, return "TID: N/A" to the output message, if SkyWalking agent in active mode, return the real traceId
     * in the recent Context, if existed.
     *
     * @param iLoggingEvent the event
     * @return the traceId: N/A, empty String, or the real traceId.
     */
    @Override
    public String convert(ILoggingEvent iLoggingEvent) {
        return "TID: N/A";
    }
}

之后将LogbackPatternConverter添加到PatternLayoutdefaultConverterMap

java 复制代码
public class TraceIdPatternLogbackLayout extends PatternLayout {
    static {
        defaultConverterMap.put("tid", LogbackPatternConverter.class.getName());
    }
}

可以看到到此为止都只是给默认值。

这一快的代码都是在apm-toolkit-logback-1.x 这个sdk实现的。

增强定义(agent)

接下来真正的实现当然是放在agent里面去做的首先去继承ClassInstanceMethodsEnhancePluginDefine

java 复制代码
/**
 * Active the toolkit class "org.apache.skywalking.apm.toolkit.log.logback.v1.x.LogbackPatternConverter". Should not
 * dependency or import any class in "skywalking-toolkit-logback-1.x" module. Activation's classloader is diff from
 * "org.apache.skywalking.apm.toolkit.log.logback.v1.x.LogbackPatternConverter", using direct will trigger classloader
 * issue.
 * <p>
 */
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);
    }

    /**
     * @return null, no need to intercept constructor of enhance class.
     */
    @Override
    public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
        return null;
    }

    /**
     * @return the collection of {@link StaticMethodsInterceptPoint}, represent the intercepted methods and their
     * interceptors.
     */
    @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;
                    }

                    @Override
                    public boolean isOverrideArgs() {
                        return false;
                    }
                }
        };
    }
}

这里主要定义agent要增强哪个类、哪个方法。比如这里就通过ENHANCE_CLASS定义增强类,ENHANCE_METHOD定义增强的方法

之后再skywalking-plugin.def配置类中添加这个类

INTERCEPT_CLASS拦截class就是配置我们下面要写的也就是真正的实现类

拦截器(agent)

之后再写一个真正实现增强的拦截器

java 复制代码
public class PrintTraceIdInterceptor implements InstanceMethodsAroundInterceptor {

    @Override
    public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
                             MethodInterceptResult result) throws Throwable {

    }

    @Override
    public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
                              Object ret) throws Throwable {
        if (!ContextManager.isActive()) {
            if (allArguments[0] instanceof EnhancedInstance) {
                SkyWalkingContext skyWalkingContext = (SkyWalkingContext) ((EnhancedInstance) allArguments[0]).getSkyWalkingDynamicField();
                if (skyWalkingContext != null) {
                    return "TID:" + skyWalkingContext.getTraceId();
                }
            }
        }
        return "TID:" + ContextManager.getGlobalTraceId();
    }

    @Override
    public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
                                      Class<?>[] argumentsTypes, Throwable t) {

    }
}

可以看到这个类也是比较简单,实现InstanceMethodsAroundInterceptor即可。

然后有方法执行前,执行后,执行异常的各个增强点,和AOP优点类似。 看名字就知道这个方法是干嘛的,名字取得非常好

如何增加uid打印

通过上面的分析我们就知道如果我们要实现增加一个uid的打印我们需要如何开发

  1. apm-toolkit-logback-1.x中继承ClassicConverter添加默认值处理类比如LogbackUidPatternConverter
java 复制代码
public class LogbackUidPatternConverter extends ClassicConverter {
    /**
     * As default, return "TID: N/A" to the output message, if SkyWalking agent in active mode, return the real traceId
     * in the recent Context, if existed.
     *
     * @param iLoggingEvent the event
     * @return the traceId: N/A, empty String, or the real traceId.
     */
    @Override
    public String convert(ILoggingEvent iLoggingEvent) {
        return "Uid:null";
    }
}
  1. LogbackUidPatternConverter添加到TraceIdPatternLogbackLayout
java 复制代码
public class TraceIdPatternLogbackLayout extends PatternLayout {
    static {
        defaultConverterMap.put("tid", LogbackPatternConverter.class.getName());
        defaultConverterMap.put("uid", LogbackUidPatternConverter.class.getName());
    }
}
  1. apm-toolkit-logback-1.x默认sdk打包,其他项目升级到这个打包出来的新版本

  2. agent中apm-toolkit-logback-1.x-activation新增拦截器PrintUidInterceptor

java 复制代码
public class PrintUidInterceptor implements InstanceMethodsAroundInterceptor {

    @Override
    public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
                             MethodInterceptResult result) throws Throwable {

    }

    @Override
    public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
                              Object ret) throws Throwable {
        if (!ContextManager.isActive()) {
            if (allArguments[0] instanceof EnhancedInstance) {
                SkyWalkingContext skyWalkingContext = (SkyWalkingContext) ((EnhancedInstance) allArguments[0]).getSkyWalkingDynamicField();
                if (skyWalkingContext != null) {
                    return "Uid:null";
                }
            }
        }
        if (Objects.nonNull(ContextManager.getCorrelationContext())) {
            return "Uid:" + ContextManager.getCorrelationContext().get("x-xiazou-uid").orElse(null);
        }
        return "Uid:null";
    }

    @Override
    public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
                                      Class<?>[] argumentsTypes, Throwable t) {

    }
}
  1. 新增LogbackUidConverterActivation继承ClassInstanceMethodsEnhancePluginDefine定义增强点
java 复制代码
public class LogbackUidConverterActivation extends ClassInstanceMethodsEnhancePluginDefine {

    public static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.toolkit.activation.log.logback.v1.x.PrintUidInterceptor";
    public static final String ENHANCE_CLASS = "org.apache.skywalking.apm.toolkit.log.logback.v1.x.LogbackUidPatternConverter";
    public static final String ENHANCE_METHOD = "convert";

    /**
     * @return the target class, which needs active.
     */
    @Override
    protected ClassMatch enhanceClass() {
        return byName(ENHANCE_CLASS);
    }

    /**
     * @return null, no need to intercept constructor of enhance class.
     */
    @Override
    public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
        return null;
    }

    /**
     * @return the collection of {@link StaticMethodsInterceptPoint}, represent the intercepted methods and their
     * interceptors.
     */
    @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;
                    }

                    @Override
                    public boolean isOverrideArgs() {
                        return false;
                    }
                }
        };
    }


}
  1. LogbackUidConverterActivation添加到skywalking-plugin.def配置中

  2. 打包agent升级agent即可

总结

总的来说修改起来还是比较简单的,主要是skywalking这一套都高度封装了。我们只需要实现或者继承对应的接口(类)即可

相关推荐
计算机学姐2 小时前
基于python+django+vue的影视推荐系统
开发语言·vue.js·后端·python·mysql·django·intellij-idea
JustinNeil2 小时前
简化Java对象转换:高效实现大对象的Entity、VO、DTO互转与代码优化
后端
青灯文案12 小时前
SpringBoot 项目统一 API 响应结果封装示例
java·spring boot·后端
微尘83 小时前
C语言存储类型 auto,register,static,extern
服务器·c语言·开发语言·c++·后端
计算机学姐3 小时前
基于PHP的电脑线上销售系统
开发语言·vscode·后端·mysql·编辑器·php·phpstorm
码拉松4 小时前
千万不要错过,优惠券设计与思考初探
后端·面试·架构
白总Server5 小时前
MongoDB解说
开发语言·数据库·后端·mongodb·golang·rust·php
计算机学姐5 小时前
基于python+django+vue的家居全屋定制系统
开发语言·vue.js·后端·python·django·numpy·web3.py
程序员-珍6 小时前
SpringBoot v2.6.13 整合 swagger
java·spring boot·后端
海里真的有鱼6 小时前
好文推荐-架构
后端