Crash监控方案(一):Java层监控方案
在接触javassist与javaagent之前,有过几个方案,但发布了几版后发现实现方式太low、成本高、效率低等不足,其中包括:代码中嵌入日志、使用spring管理应用并使用aop、修改jar包源代码增加日志。
二、字节码插桩技术实现更高效的应用性能监控,什么是字节码插桩技术: javaagent 是java1.5之后引⼊的特性,其主要作⽤是在class 被加载之前对其拦截,插⼊字节码。
javassist:编辑和创建字节码的类库,其主要的优点,在于简单,⽽且快速。直接使⽤java编码的形式。
基于javaagent和javassist实现字节码插桩技术。
三、demo实现方法执行耗时监控
public class TimeAgent {
public static void premain(String args, Instrumentation instrumentation) {
System.out.println("传入参数:"+args);
instrumentation.addTransformer(new ClassFileTransformer() {
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer)
throws IllegalClassFormatException {
if (!"com/apm/agent/TimeServiceImpl".equals(className)) {
return null;
}
try {
//javassist 编辑改造字节码
ClassPool classPool = new ClassPool();
classPool.insertClassPath(new LoaderClassPath(loader));
CtClass ctClass = classPool.get("com.apm.agent.TimeServiceImpl");
CtMethod method = ctClass.getDeclaredMethod("hello");
method.addLocalVariable("beginTime",CtClass.longType);
method.addLocalVariable("endTime", CtClass.longType);
method.insertBefore("System.out.println(System.currentTimeMillis());");
method.insertBefore("long beginTime = System.currentTimeMillis();");
method.insertAfter("long endTime = System.currentTimeMillis();
"+
" System.out.println(endTime-beginTime);");
return ctClass.toBytecode();
} catch (NotFoundException e) {
e.printStackTrace();
} catch (CannotCompileException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
});
}
}
public class TimeServiceImpl {
public TimeServiceImpl() {
}
//有一次必须向上一层抛出,如果用try{}catch(){}捕获异常,则会抛出异常
// java.lang.VerifyError: (class: com/apm/agent/TimeServiceImpl, method: hello signature:
// (Ljava/lang/String;)V) Register pair 3/4 contains wrong type
public void hello(String hello) throws InterruptedException {
{
// 开始时间
Thread.sleep(3000);
// 结束时间
}
}
}
public class TimeAgentTest {
public static void main(String[] args) throws InterruptedException {
System.out.println("执行main方法");
TimeServiceImpl timeService = new TimeServiceImpl();
timeService.hello("");
}
}
编辑MANIFEST.MF文件
设置JVM启动参数
执行TimeAgentTest.main()方法,输出结果: 传入参数:helloworld 执行main方法 1554281967837 3001
上一篇:
JS实现多线程数据分片下载
下一篇:
hadoop、hive常见问题及解决方式
