pinpoint插件开发实践

plugin基本结构

一个plugin主要由三部分构成,插件类增强定义(ProfilerPlugin接口实现)、插件描述定义(TraceMetadataProvider接口实现)、增强类拦截器实现(AroundInterceptor接口实现)

举个栗子

1、插件定义

ProfilerPlugin 接口只有一个setup方法,插件加载时会调用setup方法,一般我们会在这个时候对指定的类进行增强。同时一般还会实现TransformTemplateAware接口,通过这个接口可以拿到TransformTemplate对象,对类进行增强主要是通过这个类。

public class OpenSearchPlugin implements ProfilerPlugin, TransformTemplateAware {

    private TransformTemplate transformTemplate;
    @Override
    public void setup(ProfilerPluginSetupContext context) {
        OpenSearchConfig config = new OpenSearchConfig(context.getConfig());
        if (!config.isEnable()) {
            return;
        }
        addTransformers();
    }
    private void addTransformers() {
        transformTemplate.transform("com.aliyun.opensearch.CloudsearchClient", new TransformCallback() {
            @Override
            public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException {
                InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer);
                InstrumentMethod method = target.getDeclaredMethod("call","java.lang.String","java.util.Map","java.lang.String","boolean","java.lang.StringBuffer");
                method.addInterceptor("com.navercorp.pinpoint.plugin.opensearch.interceptor.OpenSearchInterceptor");
                return target.toBytecode();
            }
        });
    }
    @Override
    public void setTransformTemplate(TransformTemplate transformTemplate) {
        this.transformTemplate = transformTemplate;
    }
}

  上面这个例子,我们对CloudsearchClient类进行了增强,具体增强的是call方法,最后指定了对应的拦截器OpenSearchInterceptor

通过ProfilerPluginSetupContext.getConfig()可以拿到我们在pinpoint.config中的配置。

2、插件描述定义

public class OpenSearchTypeProvider implements TraceMetadataProvider{
    @Override
    public void setup(TraceMetadataSetupContext context) {
        context.addServiceType(OpenSearchConstant.OPEN_SEARCH_SERVICE, AnnotationKeyMatchers.ARGS_MATCHER);
        context.addAnnotationKey(OpenSearchConstant.SEARCH_INDEX_NAME);
        context.addAnnotationKey(OpenSearchConstant.SEARCH_QUERY);
    }
}

这里指定了插件的服务名称为OPEN_SEARCH_SERVICE,增加了两个参数:SEARCH_INDEX_NAME和SEARCH_QUERY,这个主要是在链路详情中显示自定义的参数

这里如果不配置,在web页面上是没办法显示的。

3、拦截器实现

public class OpenSearchInterceptor implements AroundInterceptor {

    private static final String    OPEN_SEARCH = "openSearch";
    private final MethodDescriptor descriptor;
    private final TraceContext     traceContext;

    public OpenSearchInterceptor(TraceContext traceContext, MethodDescriptor descriptor){
        this.descriptor = descriptor;
        this.traceContext = traceContext;
    }

    private boolean getWwitch() {
        String applicationName = traceContext.getApplicationName();
        if (!traceContext.collectSwitch(applicationName, OPEN_SEARCH, null)) {
            return false;
        }
        return true;
    }

    @Override
    public void before(Object target, Object[] args) {
        if (!getWwitch()) {
            return;
        }

        Trace trace = traceContext.currentTraceObject();
        if (trace == null) return;
        SpanEventRecorder recorder = trace.traceBlockBegin();
        recorder.recordServiceType(OpenSearchConstant.OPEN_SEARCH_SERVICE);

    }

    @Override
    public void after(Object target, Object[] args, Object result, Throwable throwable) {
        if (!getWwitch()) {
            return;
        }
        Trace trace = traceContext.currentTraceObject();
        if (trace == null) return;
        try {
            // String path = (String) args[0];
            Map<String, String> param = (Map<String, String>) args[1];
            // String method= (String) args[2];
            // Boolean isPb= (Boolean) args[3];
            // StringBuffer sb= (StringBuffer) args[4];
            SpanEventRecorder recorder = trace.currentSpanEventRecorder();
            // String format=param.get("format");
            String indexName = param.get("index_name");
            String query = param.get("query");
            recorder.recordApi(descriptor, new Object[] { indexName });
            recorder.recordException(throwable);
            recorder.recordAttribute(OpenSearchConstant.SEARCH_INDEX_NAME, indexName);
            recorder.recordAttribute(OpenSearchConstant.SEARCH_QUERY, query);
            recorder.recordServiceType(OpenSearchConstant.OPEN_SEARCH_SERVICE);
            recorder.recordDestinationId(OpenSearchConstant.OPEN_SEARCH_DESTINATION);
            // recorder.recordAttribute(AnnotationKey.ARGS0,indexName);

            if (target instanceof BaseUriGetter) {
                String endPoint = ((BaseUriGetter) target)._$PINPOINT$_getBaseURI();
                recorder.recordEndPoint(endPoint);
            }
        } finally {
            trace.traceBlockEnd();
        }
    }
}

 拦截器的实现主要是一个before和after方法,对应我们的方法执行前和执行后。

通过SpanEventRecorder可以写入一条链路详情到调用链中。

附上插件类图:

原文地址:https://www.cnblogs.com/yissheng/p/9971924.html