一个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能够写入一条链路详情到调用链中。
附上插件类图: