pinpoint下载

git clone https://github.com/naver/pinpoint.git

设置环境变量

export JAVA_6_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home
export JAVA_7_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home
export JAVA_8_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home
export JAVA_9_HOME=/Library/Java/JavaVirtualMachines/jdk-9.0.1.jdk/Contents/Home

注意:pinpoint项目要成功跑起来,需要按官方要求配置“JAVA_6_HOME、JAVA_7_HOME、JAVA_8_HOME、JAVA_9_HOME”等环境变量,故提前安装好需要的jdk

编译

mvn install -Dmaven.test.skip=true -e
Could not resolve dependencies for project com.navercorp.pinpoint:pinpoint-web:war:1.8.2: Could not transfer artifact com.navercorp.pinpoint:pinpoint-rpc:jar:tests:1.8.2 from/to bintray (http://jcenter.bintray.com): Access denied to: http://jcenter.bintray.com/com/navercorp/pinpoint/pinpoint-rpc/1.8.2/pinpoint-rpc-1.8.2-tests.jar , ReasonPhrase:Forbidden. -> [Help 1]

如果报上述错误拉不到jar包,修改pom 中的maven库连接为https://jcenter.bintray.com

新建plugin模块

WX20200826-170825

修改pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <properties>
    <pinpoint.version>1.8.2</pinpoint.version>
  </properties>

  <groupId>com.never.plugins</groupId>
  <artifactId>demo</artifactId>
  <packaging>jar</packaging>
  <version>1.8.2</version>

  <parent>
    <groupId>com.navercorp.pinpoint</groupId>
    <artifactId>pinpoint</artifactId>
    <relativePath>../..</relativePath>
    <version>1.8.2</version>
  </parent>

  <dependencies>
    <dependency>
      <groupId>com.navercorp.pinpoint</groupId>
      <artifactId>pinpoint-bootstrap-core</artifactId>
      <scope>provided</scope>
      <version>1.8.2</version>
    </dependency>
  </dependencies>
</project>

新增配置文件

WX20200923-102143@2x

  • com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin
    文件内容:com.navercorp.pinpoint.plugin.demo.DemoPlugin
    文件功能:指定插件功能类

  • com.navercorp.pinpoint.common.trace.TraceMetadataProvider
    文件内容:com.navercorp.pinpoint.plugin.bizlog.BizlogMetadataProvider
    文件功能:指定元数据类

开发插件功能类

public class DemoPlugin implements ProfilerPlugin, TransformTemplateAware {

    //BIZLOG_SERVICE_TYPE是bizlog插件的身份定义,用了1998这个id
    public static final ServiceType DEMO_SERVICE_TYPE = ServiceTypeFactory.of(1998, "DEMO");

    //BIZLOG_ANNOTATION_KEY_INFO是打算在pinpoint追踪信息中显示的属性的定义,用了9998这个id
    public static final AnnotationKey DEMO_ANNOTATION_KEY_INFO = AnnotationKeyFactory
            .of(9998, "demo.info", AnnotationKeyProperty.VIEW_IN_RECORD_SET);

    private TransformTemplate transformTemplate;

    private static final String DEMO_SCOPE = "DEMO_SCOPE";


    @Override
    public void setTransformTemplate(TransformTemplate transformTemplate) {
        this.transformTemplate = transformTemplate;
    }

    @Override
    public void setup(ProfilerPluginSetupContext context) {
        System.out.println(">>>>>>>>>>>>>>DemoPlugin.setup>>>>>>>>>>>>>>>>>>>>>>");
        //Logger类被加载的时候,会注入这里new的TransformCallback,对这个类的实例在线程中的行为进行拦截
        transformTemplate.transform("com.taoche.search.service.impl.AServiceImpl", new TransformCallback() {

            @Override
            public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className,
                                        Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
                                        byte[] classfileBuffer) throws
                                                                InstrumentException {
                InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer);

                //找到所有名为info的方法
                for (InstrumentMethod m : target.getDeclaredMethods(MethodFilters.name("buildCustomize"))) {
                    //注入Interceptor,在Logger类的实例执行info方法的时候会执行这个interceptor
                    m.addScopedInterceptor("com.navercorp.pinpoint.plugin.demo.DemoInterceptor",
                                           DEMO_SCOPE);
                }

                return target.toBytecode();
            }
        });
    }
}

以上方法对com.taoche.search.service.impl.AServiceImpl类进行了注入,在AServiceImpl类的实例的buildCustomize方法被调用时注入的Interceptorcom.navercorp.pinpoint.plugin.demo.DemoInterceptor就会被执行;

开发元信息类

public class DemoMetadataProvider implements TraceMetadataProvider {
    @Override
    public void setup(TraceMetadataSetupContext context) {
        System.out.println(">>>>>>>>>>>>>>DemoMetadataProvider.setup>>>>>>>>>>>>>>>>>>>>>>");
        context.addServiceType(DemoPlugin.DEMO_SERVICE_TYPE);
        context.addAnnotationKey(DemoPlugin.DEMO_ANNOTATION_KEY_INFO);
    }
}

以上方法会被pinpoint调用,这样pinpoint就知道了我们这次新增的这个插件了,以及我们要在pinpoint中显示的参数;

拦截器DemoInterceptor

拦截器是AServiceImpl类被加载的时候被pinpoint注入的,被拦截的方法在执行前后所做的事情都在拦截器中定义,以下就是DemoInterceptor:

public class DemoInterceptor implements AroundInterceptor {

    private final TraceContext traceContext;
    private final MethodDescriptor descriptor;
    private final PLogger logger = PLoggerFactory.getLogger(getClass());

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


    @Override
    public void before(Object target, Object[] args) {

        System.out.println(">>>>>>>>pinpoint before");
        if (logger.isDebugEnabled()) {
            logger.beforeInterceptor(target, args);
        }
        final Trace trace = traceContext.currentTraceObject();
        if (trace == null) {
            return;
        }

        /*if(!shouldTrace(args)){
            return;
        }*/

        trace.traceBlockBegin();
    }

    @Override
    public void after(Object target, Object[] args, Object result, Throwable throwable) {
        System.out.println(">>>>>>>>pinpoint after");

        if (logger.isDebugEnabled()) {
            logger.afterInterceptor(target, args);
        }

        Trace trace = traceContext.currentTraceObject();
        if (trace == null) {
            return;
        }

        /*if(!shouldTrace(args)){
            return;
        }*/

        try {
            SpanEventRecorder recorder = trace.currentSpanEventRecorder();
            recorder.recordServiceType(DemoPlugin.DEMO_SERVICE_TYPE);
            recorder.recordApi(descriptor);
            recorder.recordException(throwable);
            recorder.recordAttribute(DemoPlugin.DEMO_ANNOTATION_KEY_INFO, args[0]);
        } finally {
            trace.traceBlockEnd();
        }

    }

    private static boolean shouldTrace(Object[] args){
        System.out.println(">>>>>>>>>>>>>>DemoInterceptor.shouldTrace>>>>>>>>>>>>>>>>>>>>>>");

        return null!=args
               && args.length>0
               && (args[0] instanceof String)
               && ((String)args[0]).indexOf("pinpoint_bizlog_name")>-1;
    }
}

上述的代码中,before和after方法分别代表AServiceImpl.buildCustomize方法执行前和执行后拦截器所做的事情,shouldTrace方法检查入参中是否有"pinpoint_xxx_name"前缀,如果没有就不执行拦截操作了(上述代码中注释掉了shouldTrace方法的判断),如果有,就执行trace操作,recorder.recordAttribute会将入参记录并在pinpoint追踪信息中展示出来;

plugins工程的配置

modeles

由于我们新建的demo工程和其他插件工程一样是plugins的子工程,为了能构建和打包,要在plugins工程中配置,打开plugins文件夹下的pom.xml文件:
首先,在modeles节点中增加以下内容:

<module>demo</module>

dependencies

然后,在dependencies节点增加以下内容:

<dependency>
	<groupId>com.navercorp.pinpoint</groupId>
	<artifactId>demo</artifactId>
	<version>${project.version}</version>
</dependency>

构建

在demo项目下执行package命令

mvn install -Dmaven.test.skip=true

修改项目dockerfile,将demo对应的jar包添加到image中

FROM harbor.xxxx.com/taoche/library/java/jdk8:apm-1.7

ENV PROJECT_DIR=/opt/pinpoint-agent
WORKDIR $PROJECT_DIR

COPY docker/demo-1.8.2.jar $PROJECT_DIR/plugin/demo-1.7.3.jar
.......

演示

controller

 @GetMapping
public String apm(@RequestParam(value = "type", defaultValue = "0") int type) {

    IMGroup group = new IMGroup();
    if (type == 0) {
        new AServiceImpl().buildCustomize(group);
    } else {
        new BServiceImpl().buildCustomize(group);
    }
    return "SUCCESS";
}

在type为0时执行AServiceImpl,否则执行BServiceImpl

请求接口

分别添加type=1及type=0请求上述接口

apm日志

WX20200923-105453@2x

WX20200923-105505@2x

发现请求AServiceImpl时,记录了apm日志,原因是我们开发的插件对该类进行了拦截