写在前面
打印方法执行耗时是监控,获取程序运行的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:
运行测试:
文章评论