pinpoint插件開發實踐

plugin基本結構

一個plugin主要由三部分構成,插件類加強定義(ProfilerPlugin接口實現)、插件描述定義(TraceMetadataProvider接口實現)、加強類攔截器實現(AroundInterceptor接口實現)java

舉個栗子

一、插件定義web

ProfilerPlugin 接口只有一個setup方法,插件加載時會調用setup方法,通常咱們會在這個時候對指定的類進行加強。同時通常還會實現TransformTemplateAware接口,經過這個接口能夠拿到TransformTemplate對象,對類進行加強主要是經過這個類。app

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方法,最後指定了對應的攔截器OpenSearchInterceptoride

經過ProfilerPluginSetupContext.getConfig()能夠拿到咱們在pinpoint.config中的配置。this

二、插件描述定義spa

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頁面上是沒辦法顯示的。code

三、攔截器實現orm

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能夠寫入一條鏈路詳情到調用鏈中。

 

附上插件類圖:

相關文章
相關標籤/搜索