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常见问题及解决方式