写在前面

打印方法执行耗时是监控,获取程序运行的JVM信息是监控,链路追踪也是监控。

本文看下如何实现一个通用的监控解决方案。

1:程序

定义premain:

package com.dahuyou.multi.monitor;

import com.dahuyou.multi.monitor.factory.PluginFactory;
import com.dahuyou.multi.monitor.linktrace.LinkTraceAdvice;
import com.dahuyou.multi.monitor.plugin.IPlugin;
import com.dahuyou.multi.monitor.plugin.InterceptPoint;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.matcher.ElementMatchers;
import net.bytebuddy.utility.JavaModule;

import java.lang.instrument.Instrumentation;
import java.util.List;

public class MyPreMain {

    public static void premain(String agentArgs, Instrumentation inst) {
        System.out.println("Java agent配置参数:" + agentArgs);
        System.out.println("============================");
        System.out.println("大忽悠🐂B监控系统开始工作了!");
        System.out.println("============================");

        AgentBuilder agentBuilder = new AgentBuilder.Default();
        // 获取所有可用的监控插件(jvm,链路追踪,执行耗时等)
        List<IPlugin> pluginGroup = PluginFactory.pluginGroup;

        for (IPlugin plugin : pluginGroup) {
            InterceptPoint[] interceptPoints = plugin.buildInterceptPoint();
            for (InterceptPoint point : interceptPoints) {
                AgentBuilder.Transformer transformer
                        = (builder, typeDescription, classLoader, javaModule) -> {
                    builder = builder.visit(Advice.to(plugin.adviceClass()).on(point.buildMethodsMatcher()));
                    return builder;
                };
                agentBuilder = agentBuilder.type(point.buildTypesMatcher()).transform(transformer).asDecorator();
            }
        }

        // 将bytebuddy的插桩逻辑安装到instrument
        agentBuilder.with(new AgentBuilder.Listener() {
            @Override
            public void onDiscovery(String s, ClassLoader classLoader, JavaModule javaModule, boolean b) {

            }

            @Override
            public void onTransformation(TypeDescription typeDescription, ClassLoader classLoader, JavaModule javaModule, boolean b, DynamicType dynamicType) {
//                System.out.println("onTransformation:" + typeDescription);
            }

            @Override
            public void onIgnored(TypeDescription typeDescription, ClassLoader classLoader, JavaModule javaModule, boolean b) {

            }

            @Override
            public void onError(String s, ClassLoader classLoader, JavaModule javaModule, boolean b, Throwable throwable) {

            }

            @Override
            public void onComplete(String s, ClassLoader classLoader, JavaModule javaModule, boolean b) {

            }
        }).installOn(inst);
    }
}

这里将不同的监控类型抽象为插件,定义了监控插件接口类:

package com.dahuyou.multi.monitor.plugin;

/**
 * 监控插件接口
 */
public interface IPlugin {
    /*
    插件名称
     */
    String pluginName();

    /*
    插件的监控点(即监控哪些类的哪些方法)
     */
    InterceptPoint[] buildInterceptPoint();

    /*
    执行具体监控的切面类
     */
    Class adviceClass();

}

本文实现,打印JVM,和链路追踪两种监控方式,实现类如下:

package com.dahuyou.multi.monitor.plugin.concrete;

import com.dahuyou.multi.monitor.jvmusage.JVMUsageAdvice;
import com.dahuyou.multi.monitor.plugin.IPlugin;
import com.dahuyou.multi.monitor.plugin.InterceptPoint;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import net.bytebuddy.matcher.ElementMatchers;

/**
 * jvm使用情况插件
 */
public class JvmPlugin implements IPlugin {

    @Override
    public String pluginName() {
        return "jvmusage";
    }

    @Override
    public InterceptPoint[] buildInterceptPoint() {
        return new InterceptPoint[]{
                new InterceptPoint() {
                    @Override
                    public ElementMatcher<TypeDescription> buildTypesMatcher() {
                        return ElementMatchers.nameStartsWith("com.dahuyou.multi.monitor");
                    }

                    @Override
                    public ElementMatcher<MethodDescription> buildMethodsMatcher() {
                        return ElementMatchers.named("method1")
                                .or(ElementMatchers.named("method2"))
                                .or(ElementMatchers.named("method3"));
                    }
                }
        };
    }

    @Override
    public Class adviceClass() {
        return JVMUsageAdvice.class;
    }

}
package com.dahuyou.multi.monitor.plugin.concrete;

import com.dahuyou.multi.monitor.jvmusage.JVMUsageAdvice;
import com.dahuyou.multi.monitor.linktrace.LinkTraceAdvice;
import com.dahuyou.multi.monitor.plugin.IPlugin;
import com.dahuyou.multi.monitor.plugin.InterceptPoint;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import net.bytebuddy.matcher.ElementMatchers;

/**
 * 链路追踪插件
 */
public class LinkTracePlugin implements IPlugin {

    @Override
    public String pluginName() {
        return "linktrace";
    }

    @Override
    public InterceptPoint[] buildInterceptPoint() {
        return new InterceptPoint[]{
                new InterceptPoint() {
                    @Override
                    public ElementMatcher<TypeDescription> buildTypesMatcher() {
                        return ElementMatchers.nameStartsWith("com.dahuyou.multi.monitor");
                    }

                    @Override
                    public ElementMatcher<MethodDescription> buildMethodsMatcher() {
                        return ElementMatchers.named("method1")
                                .or(ElementMatchers.named("method2"))
                                .or(ElementMatchers.named("method3"));
                    }
                }
        };
    }

    @Override
    public Class adviceClass() {
        return LinkTraceAdvice.class;
    }

}

通过插件工厂PluginFactory来维护所有可用的监控插件:

package com.dahuyou.multi.monitor.factory;

import com.dahuyou.multi.monitor.plugin.IPlugin;
import com.dahuyou.multi.monitor.plugin.concrete.JvmPlugin;
import com.dahuyou.multi.monitor.plugin.concrete.LinkTracePlugin;
import java.util.ArrayList;
import java.util.List;

/**
 * 可用监控插件工厂类
 */
public class PluginFactory {

    public static List<IPlugin> pluginGroup = new ArrayList<>();

    static {
        //链路追踪监控
        pluginGroup.add(new LinkTracePlugin());
        //Jvm监控插件
        pluginGroup.add(new JvmPlugin());
    }

}

接口InterceptPoint,用来抽象监控点,接口定义如下:

package com.dahuyou.multi.monitor.plugin;

import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;

/**
 * 插件监控点接口,设置插件要监控的类和要监控的方法
 */
public interface InterceptPoint {

    /*
    设置插件要监控的类
     */
    ElementMatcher<TypeDescription> buildTypesMatcher();

    /*
    设置插件要监控的方法
     */
    ElementMatcher<MethodDescription> buildMethodsMatcher();

}

核心逻辑就是这些了,详细的大家感兴趣的话还是看源码。

接着来打包:
在这里插入图片描述
测试类:

package com.dahuyou.multi.monitor.test;

public class ApiTest {

    public static void main(String[] args) {

        //线程一
        new Thread(() -> new ApiTest().method1(), "线程思密达").start();
//        new Thread(() -> new ApiTest().method1(), "线程萨瓦迪卡").start();

//        new ApiTest().method1();
    }


    public void method1() {
        System.out.println("测试结果:hi1");
        method2();
    }

    public void method2() {
        System.out.println("测试结果:hi2");
        method3();
    }

    public void method3() {
        System.out.println("测试结果:hi3");
    }


}

配置javaagent:
在这里插入图片描述
运行测试:
在这里插入图片描述

写在后面

参考文章列表

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐