美文网首页程序员
再探Pinpoint Agent (一)

再探Pinpoint Agent (一)

作者: 我是嘻哈大哥 | 来源:发表于2019-06-18 22:25 被阅读4次

1、Agent作为Pinpoint采集部分,作为数据的来源,在系统中发挥着重要的作用,Pinpoint Agent启动Agent时添加的参数有

-javaagent:$path\pinpoint-agent-1.7.4-SNAPSHOT\pinpoint-bootstrap-1.7.4-SNAPSHOT.jar -Dpinpoint.agentId=111 -Dpinpoint.applicationName=abc

当启动监控程序后,直接进入到PinpointBootStrap类下的premain函数:

    public static void premain(String agentArgs, Instrumentation instrumentation) {
        if (agentArgs == null) {
            agentArgs = "";
        }
        logger.info(ProductInfo.NAME + " agentArgs:" + agentArgs);

        final boolean success = STATE.start(); //检查pinpoint是否已经启动
        if (!success) {
            logger.warn("pinpoint-bootstrap already started. skipping agent loading.");
            return;
        }
        Map<String, String> agentArgsMap = argsToMap(agentArgs);//Args转Map

        final ClassPathResolver classPathResolver = new AgentDirBaseClassPathResolver();
        if (!classPathResolver.verify()) {
            logger.warn("Agent Directory Verify fail. skipping agent loading.");
            logPinpointAgentLoadFail();
            return;
        }

        BootstrapJarFile bootstrapJarFile = classPathResolver.getBootstrapJarFile();
        appendToBootstrapClassLoader(instrumentation, bootstrapJarFile);


        PinpointStarter bootStrap = new PinpointStarter(agentArgsMap, bootstrapJarFile, classPathResolver, instrumentation);
        if (!bootStrap.start()) {
            logPinpointAgentLoadFail();
        }

    }

下面主要介绍关键的代码:

final boolean success = STATE.start(); //检查pinpoint是否已经启动
    ->public boolean start() {
        return state.compareAndSet(STATE_NONE, STATE_STARTED);
    }

主要通过CAS判断是否已经启。

final ClassPathResolver classPathResolver = new AgentDirBaseClassPathResolver();
    public AgentDirBaseClassPathResolver(String classPath) {
        this.classPath = classPath;
        this.agentPattern = DEFAULT_AGENT_PATTERN;
        this.agentCommonsPattern = DEFAULT_AGENT_COMMONS_PATTERN;
        this.agentCorePattern = DEFAULT_AGENT_CORE_PATTERN;
        this.agentCoreOptionalPattern = DEFAULT_AGENT_CORE_OPTIONAL_PATTERN;
        this.annotationsPattern = DEFAULT_ANNOTATIONS;
        this.fileExtensionList = getDefaultFileExtensionList();
    }

主要是指定相关依赖jar的名称,采用正则表达式,方便版本扩展

lassPathResolver.verify()
   ->public boolean verify() {

        final BootstrapJarFile bootstrapJarFile = new BootstrapJarFile();

        // 1st find boot-strap.jar
        final boolean agentJarNotFound = this.findAgentJar();
        if (!agentJarNotFound) {
            logger.warn("pinpoint-bootstrap-x.x.x(-SNAPSHOT).jar not found.");
            return false;
        }

        // 2nd find pinpoint-commons.jar
        final String pinpointCommonsJar = getPinpointCommonsJar();
        if (pinpointCommonsJar == null) {
            logger.warn("pinpoint-commons-x.x.x(-SNAPSHOT).jar not found");
            return false;
        }
        final JarFile pinpointCommonsJarFile = getJarFile(pinpointCommonsJar);
        if (pinpointCommonsJarFile == null) {
            logger.warn("pinpoint-commons-x.x.x(-SNAPSHOT).jar not found");
            return false;
        }
        bootstrapJarFile.append(pinpointCommonsJarFile);

        // 3rd find bootstrap-core.jar
        final String bootStrapCoreJar = getBootStrapCoreJar();
        if (bootStrapCoreJar == null) {
            logger.warn("pinpoint-bootstrap-core-x.x.x(-SNAPSHOT).jar not found");
            return false;
        }
        JarFile bootStrapCoreJarFile = getJarFile(bootStrapCoreJar);
        if (bootStrapCoreJarFile == null) {
            logger.warn("pinpoint-bootstrap-core-x.x.x(-SNAPSHOT).jar not found");
            return false;
        }
        bootstrapJarFile.append(bootStrapCoreJarFile);

        // 4th find bootstrap-core-optional.jar
        final String bootStrapCoreOptionalJar = getBootStrapCoreOptionalJar();
        if (bootStrapCoreOptionalJar == null) {
            logger.info("pinpoint-bootstrap-core-optional-x.x.x(-SNAPSHOT).jar not found");
        } else {
            JarFile bootStrapCoreOptionalJarFile = getJarFile(bootStrapCoreOptionalJar);
            if (bootStrapCoreOptionalJarFile == null) {
                logger.info("pinpoint-bootstrap-core-optional-x.x.x(-SNAPSHOT).jar not found");
            } else {
                bootstrapJarFile.append(bootStrapCoreOptionalJarFile);
            }
        }

        // 5th find annotations.jar : optional dependency
        final String annotationsJar = getAnnotationsJar();
        if (annotationsJar == null) {
            logger.info("pinpoint-annotations-x.x.x(-SNAPSHOT).jar not found");
        } else {
            JarFile jarFile = getJarFile(annotationsJar);
            bootstrapJarFile.append(jarFile);
        }

        this.bootstrapJarFile = bootstrapJarFile;
        return true;
    }

由上面的程序可以看出,主要是将boot-strap.jar、pinpoint-commons.jar、bootstrap-core.jar、bootstrap-core-optional.jar、annotations.jar添加到bootstrapJarFile文件中,append方法就是将以上文件添加到一个list集合中

4.添加到BootstrapClassLoader查找的类中

  appendToBootstrapClassLoader(instrumentation, bootstrapJarFile);
    ->instrumentation.appendToBootstrapClassLoaderSearch(jarFile);

5.调用start方法

PinpointStarter bootStrap = new PinpointStarter(agentArgsMap, bootstrapJarFile, classPathResolver, instrumentation);
bootStrap.start()

start方法如下:

    boolean start() {
        final IdValidator idValidator = new IdValidator();
        final String agentId = idValidator.getAgentId();
        if (agentId == null) {
            return false;
        }
        final String applicationName = idValidator.getApplicationName();
        if (applicationName == null) {
            return false;
        }

        URL[] pluginJars = classPathResolver.resolvePlugins();  //获取插件url

        // TODO using PLogger instead of CommonLogger
        CommonLoggerFactory loggerFactory = StdoutCommonLoggerFactory.INSTANCE;
        TraceMetadataLoaderService typeLoaderService = new DefaultTraceMetadataLoaderService(pluginJars, loggerFactory);
        ServiceTypeRegistryService serviceTypeRegistryService = new DefaultServiceTypeRegistryService(typeLoaderService, loggerFactory);
        AnnotationKeyRegistryService annotationKeyRegistryService = new DefaultAnnotationKeyRegistryService(typeLoaderService, loggerFactory);

        String configPath = getConfigPath(classPathResolver);
        if (configPath == null) {
            return false;
        }

        // set the path of log file as a system property
        saveLogFilePath(classPathResolver);

        savePinpointVersion();

        try {
            // Is it right to load the configuration in the bootstrap?
            ProfilerConfig profilerConfig = DefaultProfilerConfig.load(configPath);

            // this is the library list that must be loaded
            List<URL> libUrlList = resolveLib(classPathResolver);
            AgentClassLoader agentClassLoader = new AgentClassLoader(libUrlList.toArray(new URL[libUrlList.size()]));
            final String bootClass = getBootClass();
            agentClassLoader.setBootClass(bootClass);
            logger.info("pinpoint agent [" + bootClass + "] starting...");


            AgentOption option = createAgentOption(agentId, applicationName, profilerConfig, instrumentation, pluginJars, bootstrapJarFile, serviceTypeRegistryService, annotationKeyRegistryService);
            Agent pinpointAgent = agentClassLoader.boot(option);
            pinpointAgent.start();
            registerShutdownHook(pinpointAgent);
            logger.info("pinpoint agent started normally.");
        } catch (Exception e) {
            // unexpected exception that did not be checked above
            logger.warn(ProductInfo.NAME + " start failed.", e);
            return false;
        }
        return true;
    }

介绍关键代码:
1.调用provider的setup方法,设置插件的ServiceType

TraceMetadataLoaderService typeLoaderService = new DefaultTraceMetadataLoaderService(pluginJars, loggerFactory);
   ->loader.load(jarLists);
      ->load(providers);
         ->provider.setup(context); //依次执行provider的setup方法

以tomcat插件为例,

    @Override
    public void setup(TraceMetadataSetupContext context) {
        context.addServiceType(TomcatConstants.TOMCAT);
        context.addServiceType(TomcatConstants.TOMCAT_METHOD);
    }

其中TomcatConstants类下定义的TOMCAT和TOMCAT_METHOD如下:

    public static final ServiceType TOMCAT = ServiceTypeFactory.of(1010, "TOMCAT", RECORD_STATISTICS);
    public static final ServiceType TOMCAT_METHOD = ServiceTypeFactory.of(1011, "TOMCAT_METHOD");//工厂构建

    -> return new DefaultServiceType(code, name, desc, properties); 

通过代码可以看出主要是构建ServiceType对象实例

2.主要是查找出刚才插件中创建的ServiceType以及默认ServiceType合并后的一些映射关系

 ServiceTypeRegistryService serviceTypeRegistryService = new DefaultServiceTypeRegistryService(typeLoaderService, loggerFactory);

3.主要是查找出刚才插件中创建的AnnotationKey以及默认AnnotationKey合并后的一些映射关系

 AnnotationKeyRegistryService annotationKeyRegistryService = new DefaultAnnotationKeyRegistryService(typeLoaderService, loggerFactory);

    ->this.registry = buildServiceTypeRegistry();
    

4.声明启动类

 AgentClassLoader agentClassLoader = new AgentClassLoader(libUrlList.toArray(new URL[libUrlList.size()]));
 final String bootClass = getBootClass();
 >BOOT_CLASS = "com.navercorp.pinpoint.profiler.DefaultAgent"   //声明启动类

5.创建AgentOption

AgentOption option = createAgentOption(agentId, applicationName, profilerConfig, instrumentation, pluginJars, bootstrapJarFile, serviceTypeRegistryService, annotationKeyRegistryService);

6、使用agentClassLoader启动,其实就是初始化DefaultAgent

Agent pinpointAgent = agentClassLoader.boot(option);

下面是DefaultAgent的初始化方法

    static {
        // Preload classes related to pinpoint-rpc module.
        ClassPreLoader.preload();
    }

    ->  preload(65535);
        ->serverAcceptor = new PinpointServerAcceptor();  //NIO
    public DefaultAgent(AgentOption agentOption, final InterceptorRegistryBinder interceptorRegistryBinder) {
        if (agentOption == null) {
            throw new NullPointerException("agentOption must not be null");
        }
        if (agentOption.getInstrumentation() == null) {
            throw new NullPointerException("instrumentation must not be null");
        }
        if (agentOption.getProfilerConfig() == null) {
            throw new NullPointerException("profilerConfig must not be null");
        }
        if (agentOption.getServiceTypeRegistryService() == null) {
            throw new NullPointerException("serviceTypeRegistryService must not be null");
        }

        if (interceptorRegistryBinder == null) {
            throw new NullPointerException("interceptorRegistryBinder must not be null");
        }
        logger.info("AgentOption:{}", agentOption);

        this.binder = new Slf4jLoggerBinder();
        bindPLoggerFactory(this.binder);

        this.interceptorRegistryBinder = interceptorRegistryBinder;
        interceptorRegistryBinder.bind();
        this.serviceTypeRegistryService = agentOption.getServiceTypeRegistryService();

        dumpSystemProperties();   //导出系统变量
        dumpConfig(agentOption.getProfilerConfig());  

        changeStatus(AgentStatus.INITIALIZING);  //修改Agent状态

        this.profilerConfig = agentOption.getProfilerConfig();

        this.applicationContext = newApplicationContext(agentOption, interceptorRegistryBinder);

        
        InterceptorInvokerHelper.setPropagateException(profilerConfig.isPropagateInterceptorException());
    }

这段代码中最关键的一句是

   this.applicationContext = newApplicationContext(agentOption, interceptorRegistryBinder);
      ->return new DefaultApplicationContext(agentOption, interceptorRegistryBinder, moduleFactoryProvider);

DefaultApplicationContext构造方法如下:

    public DefaultApplicationContext(AgentOption agentOption, final InterceptorRegistryBinder interceptorRegistryBinder, ModuleFactory moduleFactory) {
        Assert.requireNonNull(agentOption, "agentOption must not be null");
        this.profilerConfig = Assert.requireNonNull(agentOption.getProfilerConfig(), "profilerConfig must not be null");
        Assert.requireNonNull(moduleFactory, "moduleFactory must not be null");

        this.instrumentation = agentOption.getInstrumentation();
        this.serviceTypeRegistryService = agentOption.getServiceTypeRegistryService();

        if (logger.isInfoEnabled()) {
            logger.info("DefaultAgent classLoader:{}", this.getClass().getClassLoader());
        }

         //关键的下面两句
        final Module applicationContextModule = moduleFactory.newModule(agentOption, interceptorRegistryBinder);
        this.injector = Guice.createInjector(Stage.PRODUCTION, applicationContextModule);
        //使用injector 获取实例
        this.instrumentEngine = injector.getInstance(InstrumentEngine.class);

        this.classFileDispatcher = injector.getInstance(ClassFileTransformerDispatcher.class);
        this.dynamicTransformTrigger = injector.getInstance(DynamicTransformTrigger.class);
//        ClassFileTransformer classFileTransformer = injector.getInstance(ClassFileTransformer.class);
        ClassFileTransformer classFileTransformer = wrap(classFileDispatcher);
        instrumentation.addTransformer(classFileTransformer, true);

        this.spanStatClientFactory = injector.getInstance(Key.get(PinpointClientFactory.class, SpanStatClientFactory.class));
        logger.info("spanStatClientFactory:{}", spanStatClientFactory);

        this.spanDataSender = newUdpSpanDataSender();
        logger.info("spanDataSender:{}", spanDataSender);

        this.statDataSender = newUdpStatDataSender();
        logger.info("statDataSender:{}", statDataSender);

        this.clientFactory = injector.getInstance(Key.get(PinpointClientFactory.class, DefaultClientFactory.class));
        logger.info("clientFactory:{}", clientFactory);

        this.tcpDataSender = injector.getInstance(EnhancedDataSender.class);
        logger.info("tcpDataSender:{}", tcpDataSender);

        this.traceContext = injector.getInstance(TraceContext.class);

        this.agentInformation = injector.getInstance(AgentInformation.class);
        logger.info("agentInformation:{}", agentInformation);
        this.serverMetaDataRegistryService = injector.getInstance(ServerMetaDataRegistryService.class);

        this.deadlockMonitor = injector.getInstance(DeadlockMonitor.class);
        this.agentInfoSender = injector.getInstance(AgentInfoSender.class);
        this.agentStatMonitor = injector.getInstance(AgentStatMonitor.class);
    }

上面代码关键的两句:

 final Module applicationContextModule = moduleFactory.newModule(agentOption, interceptorRegistryBinder);
 this.injector = Guice.createInjector(Stage.PRODUCTION, applicationContextModule);

类似Spring依赖注入,使用轻量级谷歌的Guice进行依赖注入,关于Guice的使用可以参考以下文章
https://blog.csdn.net/cnhome/article/details/80627123

期间会调用插件的Plugin类下的setup方法,调用过程如下:

-->PluginContextLoadResult pluginContextLoadResult = this.pluginContextLoadResultProvider.get();//ApplicationServerTypeProvider类下的get方法
--> return new DefaultPluginContextLoadResult(profilerConfig, dynamicTransformTrigger, instrumentEngine, pluginJars); //PluginContextLoadResultProvider类
-->this.setupResultList = load(); //DefaultPluginContextLoadResult类
-->  List<SetupResult> load = loader.load(pluginJars);

   //ProfilerPluginLoader类
    public List<SetupResult> load(URL[] pluginJars) {

        List<SetupResult> pluginContexts = new ArrayList<SetupResult>(pluginJars.length);

        for (URL pluginJar : pluginJars) {

            final JarFile pluginJarFile = createJarFile(pluginJar);
            final List<String> pluginPackageList = getPluginPackage(pluginJarFile);

            final ClassNameFilter pluginFilterChain = createPluginFilterChain(pluginPackageList);

            final List<ProfilerPlugin> original = PluginLoader.load(ProfilerPlugin.class, new URL[] { pluginJar });

            List<ProfilerPlugin> plugins = filterDisablePlugin(original);

            for (ProfilerPlugin plugin : plugins) {
                 if (logger.isInfoEnabled()) {
                    logger.info("{} Plugin {}:{}", plugin.getClass(), PluginConfig.PINPOINT_PLUGIN_PACKAGE, pluginPackageList);
                }
                
                logger.info("Loading plugin:{} pluginPackage:{}", plugin.getClass().getName(), plugin);

                PluginConfig pluginConfig = new PluginConfig(pluginJar, pluginFilterChain);
                final ClassInjector classInjector = new JarProfilerPluginClassInjector(pluginConfig, instrumentEngine);
                final SetupResult result = pluginSetup.setupPlugin(plugin, classInjector);
                pluginContexts.add(result);
            }
        }
        

        return pluginContexts;
    }
->final SetupResult result = pluginSetup.setupPlugin(plugin, classInjector);
->profilerPlugin.setup(guardSetupContext);   //调用setup方法

如tomcat则调用:

   @Override
    public void setup(ProfilerPluginSetupContext context) {

        final TomcatConfig config = new TomcatConfig(context.getConfig());
        if (logger.isInfoEnabled()) {
            logger.info("TomcatPlugin config:{}", config);
        }
        if (!config.isTomcatEnable()) {
            logger.info("TomcatPlugin disabled");
            return;
        }

        TomcatDetector tomcatDetector = new TomcatDetector(config.getTomcatBootstrapMains());
        context.addApplicationTypeDetector(tomcatDetector);

        if (shouldAddTransformers(config)) {    //判断是否需要添加transformers
            logger.info("Adding Tomcat transformers");
            addTransformers(config);   //添加transformers

        } else {
            logger.info("Not adding Tomcat transfomers");
        }
    }

    private void addTransformers(TomcatConfig config) {
        if (config.isTomcatHidePinpointHeader()) {
            addRequestFacadeEditor();
        }

        addRequestEditor();
        addStandardHostValveEditor();
        addStandardServiceEditor();
        addTomcatConnectorEditor();
        addWebappLoaderEditor();

        addAsyncContextImpl();
    }

    private void addRequestEditor() {
        transformTemplate.transform("org.apache.catalina.connector.Request", 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);
                target.addField(TomcatConstants.TRACE_ACCESSOR);
                target.addField(TomcatConstants.ASYNC_ACCESSOR);

                // clear request.
                InstrumentMethod recycleMethodEditorBuilder = target.getDeclaredMethod("recycle");
                if (recycleMethodEditorBuilder != null) {
                    recycleMethodEditorBuilder.addInterceptor("com.navercorp.pinpoint.plugin.tomcat.interceptor.RequestRecycleInterceptor");  //添加拦截器
                }

                // trace asynchronous process.
                InstrumentMethod startAsyncMethodEditor = target.getDeclaredMethod("startAsync", "javax.servlet.ServletRequest", "javax.servlet.ServletResponse");
                if (startAsyncMethodEditor != null) {
                    startAsyncMethodEditor.addInterceptor("com.navercorp.pinpoint.plugin.tomcat.interceptor.RequestStartAsyncInterceptor");  //添加拦截器
                }

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

主要通过transform添加拦截器修改类的字节码,已达到监控的目的。

7.DefaultAgent的start函数(Running),主要是定时发送相关信息。

  pinpointAgent.start();
     --->this.applicationContext.start();
       -> this.deadlockMonitor.start();
           this.agentInfoSender.start();
           this.agentStatMonitor.start();

            ->scheduler.start();
            ->schedule(successListener, Integer.MAX_VALUE, IMMEDIATE, sendIntervalMs);
           ->AgentInfoSendTask task = new AgentInfoSendTask(successListener, retryCount);
               timer.scheduleAtFixedRate(task, delay, period);
           ->boolean isSuccessful = sendAgentInfo();
              ->dataSender.request(agentInfo, new AgentInfoSenderListener(future));  //定时发送agentInfo

今天就写这么多,下次再接着研究。

相关文章

网友评论

    本文标题:再探Pinpoint Agent (一)

    本文链接:https://www.haomeiwen.com/subject/sseqqctx.html