java agent 监控_javaagent笔记及一个基于javassit的应用监控程序demo

APMAgentV1.java

package com.liq.app2;

import com.liq.javaagent.collector.*;

import javassist.ClassPool;

import javassist.CtClass;

import javassist.LoaderClassPath;

import java.lang.instrument.ClassFileTransformer;

import java.lang.instrument.IllegalClassFormatException;

import java.lang.instrument.Instrumentation;

import java.security.ProtectionDomain;

import java.util.Map;

import java.util.concurrent.ConcurrentHashMap;

public class APMAgentV1 implements ClassFileTransformer {

private static Collector[] collectors;

static {

collectors = new Collector[]{OtherCollector.INSTANCE};

}

private Map classPoolMap = new ConcurrentHashMap<>();

@Override

public byte[] transform(ClassLoader classLoader, String className, Class> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {

if ((className == null) || (classLoader == null) || (classLoader.getClass().getName().equals("sun.reflect.DelegatingClassLoader")) || (classLoader.getClass().getName().equals("org.apache.catalina.loader.StandardClassLoader")) || (classLoader.getClass().getName().equals("javax.management.remote.rmi.NoCallStackClassLoader")) || (classLoader.getClass().getName().equals("com.alibaba.fastjson.util.ASMClassLoader")) || (className.indexOf("$Proxy") != -1) || (className.startsWith("java"))) {

return null;

}

// 不同的ClassLoader使用不同的ClassPool

ClassPool localClassPool;

if (!this.classPoolMap.containsKey(classLoader)) {

localClassPool = new ClassPool();

localClassPool.insertClassPath(new LoaderClassPath(classLoader));

this.classPoolMap.put(classLoader, localClassPool);

} else {

localClassPool = this.classPoolMap.get(classLoader);

}

try {

className = className.replaceAll("/", ".");

CtClass localCtClass = localClassPool.get(className);

for (Collector collector : collectors) {

if (collector.isTarget(className, classLoader, localCtClass)) {

byte[] arrayOfByte = collector.transform(classLoader, className, classfileBuffer, localCtClass);

System.out.println(String.format("%s APM agent insert success", new Object[]{className}));

return arrayOfByte;

}

}

} catch (Throwable localThrowable) {

new Exception(String.format("%s APM agent insert fail", new Object[]{className}), localThrowable).printStackTrace();

}

return new byte[0];

}

public static void premain(String agentArgs, Instrumentation inst) {

System.out.println("Hello, world! JavaAgen");

System.out.println("agentArgs: " + agentArgs);

inst.addTransformer(new APMAgentV1());

}

}

ClassWrapper.java

用于向目标类插入一些监控代码

package com.liq.app2;

import javassist.CtMethod;

import javassist.NotFoundException;

public class ClassWrapper {

private String beginSrc;

private String endSrc;

private String errorSrc;

public ClassWrapper beginSrc(String paramString) {

this.beginSrc = paramString;

return this;

}

public ClassWrapper endSrc(String paramString) {

this.endSrc = paramString;

return this;

}

public ClassWrapper errorSrc(String paramString) {

this.errorSrc = paramString;

return this;

}

public String beginSrc(CtMethod ctMethod) {

try {

String template = ctMethod.getReturnType().getName().equals("void")

?

"{\n" +

" %s \n" +

" try {\n" +

" %s$agent($$);\n" +

" } catch (Throwable e) {\n" +

" %s\n" +

" throw e;\n" +

" }finally{\n" +

" %s\n" +

" }\n" +

"}"

:

"{\n" +

" %s \n" +

" Object result=null;\n" +

" try {\n" +

" result=($w)%s$agent($$);\n" +

" } catch (Throwable e) {\n" +

" %s \n" +

" throw e;\n" +

" }finally{\n" +

" %s \n" +

" }\n" +

" return ($r) result;\n" +

"}";

String insertBeginSrc = this.beginSrc == null ? "" : this.beginSrc;

String insertErrorSrc = this.errorSrc == null ? "" : this.errorSrc;

String insertEndSrc = this.endSrc == null ? "" : this.endSrc;

String result = String.format(template, new Object[]{insertBeginSrc, ctMethod.getName(), insertErrorSrc, insertEndSrc});

return result;

} catch (NotFoundException localNotFoundException) {

throw new RuntimeException(localNotFoundException);

}

}

}

ClassReplacer.java

用于使用包装过的类替换目标类

package com.liq.app2;

import javassist.CannotCompileException;

import javassist.CtClass;

import javassist.CtMethod;

import javassist.CtNewMethod;

import java.io.IOException;

public class ClassReplacer

{

private final String className;

private final ClassLoader classLoader;

private final CtClass ctClass;

public ClassReplacer(String className, ClassLoader classLoader, CtClass ctClass)

{

this.className = className;

this.classLoader = classLoader;

this.ctClass = ctClass;

}

public void replace(CtMethod ctMethod, ClassWrapper paramd) throws CannotCompileException {

String methodName = ctMethod.getName();

CtMethod localCtMethod2 = CtNewMethod.copy(ctMethod, methodName, this.ctClass, null);

localCtMethod2.setName(methodName + "$agent");

this.ctClass.addMethod(localCtMethod2);

ctMethod.setBody(paramd.beginSrc(ctMethod));

}

public byte[] replace() throws IOException, CannotCompileException {

return this.ctClass.toBytecode();

}

}

Collector.java

监控信息搜集器接口

package com.liq.app2.collector;

import javassist.CtClass;

public interface Collector {

boolean isTarget(String className, ClassLoader classLoader, CtClass ctClass);

byte[] transform(ClassLoader classLoader, String className, byte[] classfileBuffer, CtClass ctClass);

}

OtherCollector.java

监控信息搜集器实现,这里只是简单例子,所以写死了目标类名字“com.liq.service.UserService”

package com.liq.app2.collector;

import com.liq.app2.ClassReplacer;

import com.liq.app2.ClassWrapper;

import com.liq.app2.stat.Statistics;

import javassist.*;

public class OtherCollector implements Collector {

public static final OtherCollector INSTANCE = new OtherCollector();

private OtherCollector() {

}

private static final String beginSrc;

private static final String endSrc = "inst.end(statistic);";

private static final String errorSrc;

static {

StringBuilder stringBuilder = new StringBuilder();

stringBuilder.append("com.liq.app2.collector.OtherCollector inst=com.liq.app2.collector.OtherCollector.INSTANCE;");

stringBuilder.append("com.liq.app2.stat.Statistics statistic = inst.start(\"%s\");");

beginSrc = stringBuilder.toString();

errorSrc = "inst.error(statistic,e);";

}

@Override

public boolean isTarget(String className, ClassLoader classLoader, CtClass ctClass) {

return "com.liq.service.UserService".equals(className);

}

@Override

public byte[] transform(ClassLoader classLoader, String className, byte[] classfileBuffer, CtClass ctClass) {

try {

ClassReplacer replacer = new ClassReplacer(className, classLoader, ctClass);

for (CtMethod ctMethod : ctClass.getDeclaredMethods()) {

String str;

if ((Modifier.isPublic(ctMethod.getModifiers())) && (!Modifier.isStatic(ctMethod.getModifiers()) && (!Modifier.isNative(ctMethod.getModifiers())))) {

ClassWrapper classWrapper = new ClassWrapper();

classWrapper.beginSrc(String.format(beginSrc, ctMethod.getLongName()));

classWrapper.endSrc(endSrc);

classWrapper.errorSrc(errorSrc);

replacer.replace(ctMethod, classWrapper);

}

}

return replacer.replace();

} catch (Exception e) {

e.printStackTrace();

}

return new byte[0];

}

public Statistics start(String methodSign) {

return new Statistics(methodSign);

}

public void end(Statistics statistics) {

statistics.end();

}

public void error(Statistics statistics, Throwable e) {

statistics.error(e);

}

}

Statistics

package com.liq.app2.stat;

public class Statistics {

private String method;

private long startTime;

private long endTime;

private Throwable error;

public Statistics(String method) {

this.method = method;

this.startTime = System.currentTimeMillis();

}

public void end() {

endTime = System.currentTimeMillis();

System.out.println(this.toString());

}

public void error(Throwable e) {

error = e;

}

@Override

public String toString() {

final StringBuilder sb = new StringBuilder("Statistics{");

sb.append("method='").append(method).append('\'');

sb.append(", startTime=").append(startTime);

sb.append(", endTime=").append(endTime);

sb.append(", error=").append(error);

sb.append('}');

return sb.toString();

}

}

maven依赖

javassist

javassist

3.12.1.GA

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值