一個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能夠寫入一條鏈路詳情到調用鏈中。
附上插件類圖: