├── .gitignore ├── README.md ├── java-tracer.jar ├── pom.xml ├── tracer-agent ├── pom.xml └── src │ ├── META-INF │ └── MANIFEST.MF │ ├── main │ └── java │ │ └── com │ │ └── ali │ │ └── trace │ │ └── agent │ │ ├── inject │ │ ├── TraceEnhance.java │ │ └── TraceTransformer.java │ │ ├── loader │ │ └── SpyClassLoader.java │ │ └── main │ │ ├── AttackEngine.java │ │ ├── CoreEngine.java │ │ └── Premain.java │ └── test │ └── java │ └── com │ └── ali │ └── dbtech │ └── test │ ├── AsmTest.java │ ├── AsmVisitTrace.java │ ├── DynamicCode.java │ ├── MainProcess.java │ ├── TransferTest.java │ └── error │ └── Test.java └── tracer-spy ├── pom.xml └── src ├── META-INF └── MANIFEST.MF ├── main ├── java │ └── com │ │ └── ali │ │ └── trace │ │ └── spy │ │ ├── core │ │ ├── ConfigPool.java │ │ └── NodePool.java │ │ ├── helper │ │ ├── IFileNameGenerator.java │ │ ├── InputStreamClassLoader.java │ │ └── ThreadFileNameGenerator.java │ │ ├── inject │ │ └── TraceInjecter.java │ │ ├── intercepter │ │ ├── BaseIntercepter.java │ │ ├── CommonIntercepter.java │ │ ├── CommonThreadntercepter.java │ │ ├── CommonTreeIntercepter.java │ │ ├── CompressIntercepter.java │ │ ├── CompressThreadIntercepter.java │ │ ├── CompressTreeIntercepter.java │ │ ├── IIntercepter.java │ │ ├── MethodTreeIntercepter.java │ │ └── ThreadTreeIntercepter.java │ │ ├── jetty │ │ ├── JettyServer.java │ │ ├── ModuleHttpServlet.java │ │ ├── handler │ │ │ ├── ClassHandler.java │ │ │ ├── ITraceHttpHandler.java │ │ │ ├── IndexHandler.java │ │ │ ├── StaticHandler.java │ │ │ ├── ThreadHandler.java │ │ │ └── TraceHandler.java │ │ ├── io │ │ │ ├── AgentResVmLoader.java │ │ │ ├── StaticResResolver.java │ │ │ └── VmViewResolver.java │ │ ├── support │ │ │ ├── HandlerConfig.java │ │ │ └── Module.java │ │ └── vo │ │ │ ├── DataRet.java │ │ │ ├── MetaVO.java │ │ │ ├── RecordVO.java │ │ │ ├── SetVO.java │ │ │ └── TraceVO.java │ │ ├── util │ │ ├── BaseNode.java │ │ ├── ClassDigest.java │ │ ├── ClassUtils.java │ │ ├── CommonNode.java │ │ ├── CompressNode.java │ │ ├── CrunchifyReverseLineReader.java │ │ ├── NameUtils.java │ │ ├── RootNode.java │ │ ├── SelectiveFilter.java │ │ ├── TestAsmImport.java │ │ └── XmlUtils.java │ │ └── xml │ │ └── XmlNode.java └── resources │ └── static │ ├── css │ └── home.css │ ├── js │ ├── home.js │ ├── lodash.min.js │ ├── raphael-min.js │ ├── sequence-diagram-min.js │ └── sequence.js │ └── vm │ ├── index.vm │ └── trace.vm └── test └── java ├── com └── ali │ └── dbtech │ └── test │ ├── log │ └── LogClient.java │ └── netty │ ├── NettyServer.java │ ├── NettyServerFilter.java │ └── NettyServerHandler.java └── io └── netty ├── channel └── nio │ └── NioEventLoop.java └── util └── concurrent └── SingleThreadEventExecutor.java /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | 12 | ### IntelliJ IDEA ### 13 | .idea 14 | *.iws 15 | *.iml 16 | *.ipr 17 | 18 | ### NetBeans ### 19 | nbproject/private/ 20 | build/ 21 | nbbuild/ 22 | dist/ 23 | nbdist/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # java-tracer : 方法调用跟踪记录工具 2 | 3 | ## agent 工具 可以用来记录方法调用 4 | ### 步骤 1 下载agent包 5 | 直接从 https://github.com/fengzhongke/java-tracer/blob/master/java-tracer.jar 下载到本地 6 | 或者下载源码包 mvn clean package 打包,在项目根目录下面就有一个java-tracer.jar 7 | 8 | ### 步骤 2 运行进程 9 | 运行进程如下 10 | 1. 如果使用命令行启动java进程 11 | java -javaagent:xxx/tracer-agent/target/java-tracer.jar xxx 12 | 2. 使用IDE启动进程 13 | 增加-javaagent:xxx/tracer-agent/target/java-tracer.jar 到VM启动参数 14 | 15 | ### 步骤 3 访问链接 16 | 游览器访问 http://127.0.0.1:18902 17 | 页面功能包括 18 | 1. 系统信息,包括 a.classLoader&class信息,b.thread信息 19 | 2. 设置需要跟踪的类(cname)、方法(mname)、保存链路跟踪个数(size) 20 | 3. 查看链路 21 | 22 | ## agent tool used for trace method invoke 23 | ### STEP 1 download agent jar 24 | you can download from https://github.com/fengzhongke/java-tracer/blob/master/java-tracer.jar to local storage 25 | or download source and use maven to package and then in the root directory you can find java-tracer.jar 26 | 27 | ### STEP 2 start process 28 | running java process as follow 29 | 1. with commond: 30 | java -javaagent:xxx/tracer-agent/target/java-tracer.jar xxx 31 | 2. with IDE 32 | add -javaagent:xxx/tracer-agent/target/java-tracer.jar to VM arguments 33 | 34 | ### STEP 3 visit links 35 | visit http://127.0.0.1:18902/tracer/info see results as follow 36 | use browser to visit http://127.0.0.1:18902 37 | actions include 38 | 1. system infomation include a.classLoader&class detail,b.intime thread detail 39 | 2. to set class(cname) and method(mname) to trace and numbers of trace result to retain 40 | 3. view the trance 41 | 42 | END 43 | 44 | ## DEMO: 45 | 1. Mybatis :https://fengzhongke.github.io/pages/chart.html?page=mybatis 46 | 2. Spring :https://fengzhongke.github.io/pages/chart.html?page=spring 47 | 3. Netty1 :https://fengzhongke.github.io/pages/chart.html?page=NettyServer 48 | 4. Netty2 :https://fengzhongke.github.io/pages/chart.html?page=NioEventLoop 49 | 50 | -------------------------------------------------------------------------------- /java-tracer.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fengzhongke/java-tracer/ff30c6c78a4b9b5f71b7da68be24c54bea22a264/java-tracer.jar -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | java-tracer 5 | tracer 6 | pom 7 | 0.0.1-SNAPSHOT 8 | tracer 9 | http://maven.apache.org 10 | 11 | 12 | tracer-agent 13 | tracer-spy 14 | 15 | 16 | 17 | 18 | 19 | 20 | java-tracer 21 | tracer-spy 22 | 0.0.1-SNAPSHOT 23 | 24 | 25 | java-tracer 26 | tracer-agent 27 | 0.0.1-SNAPSHOT 28 | 29 | 30 | 31 | 32 | org.ow2.asm 33 | asm 34 | 7.0 35 | 36 | 37 | org.ow2.asm 38 | asm-commons 39 | 7.0 40 | 41 | 42 | org.ow2.asm 43 | asm-util 44 | 7.0 45 | 46 | 47 | 48 | 49 | org.eclipse.jetty 50 | jetty-server 51 | 8.1.2.v20120308 52 | 53 | 54 | org.eclipse.jetty 55 | jetty-servlet 56 | 8.1.2.v20120308 57 | 58 | 59 | javax.servlet 60 | javax.servlet-api 61 | 3.1.0 62 | 63 | 64 | 65 | 66 | velocity 67 | velocity 68 | 1.5 69 | 70 | 71 | com.google.code.gson 72 | gson 73 | 2.8.5 74 | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /tracer-agent/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | java-tracer 5 | tracer 6 | 0.0.1-SNAPSHOT 7 | ../pom.xml 8 | 9 | 10 | 4.0.0 11 | tracer-agent 12 | jar 13 | 14 | 15 | 16 | 17 | java-tracer 18 | tracer-spy 19 | 20 | 21 | 22 | 23 | java-tracer 24 | 25 | 26 | org.apache.maven.plugins 27 | maven-dependency-plugin 28 | 3.1.1 29 | 30 | 31 | copy-dependencies 32 | prepare-package 33 | 34 | copy-dependencies 35 | 36 | 37 | 38 | ${project.build.directory}/classes/META-INF/lib 39 | 40 | 41 | 42 | 43 | 44 | 45 | org.apache.maven.plugins 46 | maven-jar-plugin 47 | 2.4 48 | 49 | 50 | false 51 | 52 | 53 | lib/ 54 | 55 | 56 | 57 | com.ali.trace.agent.main.Premain 58 | com.ali.trace.agent.main.Premain 59 | com.ali.trace.spy.util.XmlUtils 60 | true 61 | true 62 | java-tracer.jar 63 | 64 | 65 | 66 | 67 | 68 | maven-antrun-plugin 69 | 70 | 71 | copy 72 | package 73 | 74 | 75 | 78 | 79 | 80 | 81 | run 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /tracer-agent/src/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Created-By: Apache Maven 3 | -------------------------------------------------------------------------------- /tracer-agent/src/main/java/com/ali/trace/agent/inject/TraceEnhance.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.agent.inject; 2 | 3 | import java.lang.reflect.Method; 4 | 5 | /** 6 | * @author nkhanlang@163.com 7 | */ 8 | public class TraceEnhance { 9 | 10 | /** 11 | * inner intercepter 12 | */ 13 | private static volatile Intercepter intercepter; 14 | 15 | /** 16 | * to avoid 17 | */ 18 | private static final ThreadLocal IN = new ThreadLocal(); 19 | 20 | /** 21 | * set intercepter 22 | */ 23 | public static boolean setIntecepter(Object instance) { 24 | boolean set = false; 25 | if (instance != null) { 26 | try { 27 | TraceEnhance.intercepter = new Intercepter(instance); 28 | set = true; 29 | } catch (Throwable e) { 30 | e.printStackTrace(); 31 | } 32 | } 33 | return set; 34 | } 35 | 36 | public static void delIntercepter() { 37 | intercepter = null; 38 | } 39 | 40 | /** 41 | * inject point before execute method body 42 | */ 43 | public static final void s(String c, String m) { 44 | try { 45 | if (intercepter != null && IN.get() == null) { 46 | IN.set(true); 47 | intercepter.START.invoke(intercepter.INSTANCE, c, m); 48 | IN.set(null); 49 | } 50 | } catch (Throwable t) { 51 | t.printStackTrace(); 52 | } 53 | } 54 | 55 | /** 56 | * inject point after execute method body 57 | */ 58 | public static final void e(String c, String m) { 59 | try { 60 | if (intercepter != null && IN.get() == null) { 61 | IN.set(true); 62 | intercepter.END.invoke(intercepter.INSTANCE, c, m); 63 | IN.set(null); 64 | } 65 | } catch (Throwable t) { 66 | t.printStackTrace(); 67 | } 68 | } 69 | 70 | private static class Intercepter { 71 | final Object INSTANCE; 72 | final Method START; 73 | final Method END; 74 | 75 | Intercepter(Object instance) throws Exception { 76 | INSTANCE = instance; 77 | Class> clazz = instance.getClass(); 78 | START = clazz.getMethod("start", String.class, String.class); 79 | END = clazz.getMethod("end", String.class, String.class); 80 | } 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /tracer-agent/src/main/java/com/ali/trace/agent/inject/TraceTransformer.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.agent.inject; 2 | 3 | import java.lang.instrument.ClassFileTransformer; 4 | import java.lang.instrument.IllegalClassFormatException; 5 | import java.lang.reflect.Method; 6 | import java.security.ProtectionDomain; 7 | 8 | /** 9 | * @author nkhanlang@163.com 10 | */ 11 | public class TraceTransformer implements ClassFileTransformer { 12 | final Object INJECTER; 13 | final Method GET_BYTES; 14 | 15 | public TraceTransformer(Object injecter) throws SecurityException, NoSuchMethodException { 16 | INJECTER = injecter; 17 | GET_BYTES = injecter.getClass().getMethod("getBytes", ClassLoader.class, String.class, byte[].class); 18 | } 19 | 20 | public byte[] transform(ClassLoader loader, String className, Class> classBeingRedefined, 21 | ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { 22 | try { 23 | classfileBuffer = (byte[])GET_BYTES.invoke(INJECTER, loader, className, classfileBuffer); 24 | } catch (Throwable e) { 25 | //e.printStackTrace(); 26 | } 27 | return classfileBuffer; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tracer-agent/src/main/java/com/ali/trace/agent/loader/SpyClassLoader.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.agent.loader; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.ByteArrayOutputStream; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.net.MalformedURLException; 8 | import java.net.URL; 9 | import java.net.URLConnection; 10 | import java.net.URLStreamHandler; 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | import java.util.jar.JarEntry; 14 | import java.util.jar.JarInputStream; 15 | 16 | /** 17 | * self define classLoader to load jar bytes resources 18 | * 19 | * @author nkhanlang@163.com 20 | * 21 | */ 22 | public class SpyClassLoader extends ClassLoader { 23 | 24 | private Map bytesMap = new HashMap(); 25 | 26 | /** 27 | * with parent 28 | */ 29 | public SpyClassLoader(ClassLoader parent) { 30 | super(parent); 31 | } 32 | 33 | /** 34 | * load input stream 35 | */ 36 | public void load(InputStream in) { 37 | JarInputStream jarInput = null; 38 | try { 39 | jarInput = new JarInputStream(in); 40 | JarEntry entry = null; 41 | while ((entry = jarInput.getNextJarEntry()) != null) { 42 | ByteArrayOutputStream bytes = new ByteArrayOutputStream(); 43 | int len = 0; 44 | byte[] data = new byte[256]; 45 | while ((len = jarInput.read(data)) != -1) { 46 | bytes.write(data, 0, len); 47 | } 48 | //System.out.println("file : " + entry.getName()); 49 | bytesMap.put(entry.getName(), bytes.toByteArray()); 50 | } 51 | } catch (Throwable e) { 52 | e.printStackTrace(); 53 | } finally { 54 | if (jarInput != null) { 55 | try { 56 | jarInput.close(); 57 | } catch (IOException e1) { 58 | e1.printStackTrace(); 59 | } 60 | } 61 | } 62 | } 63 | 64 | /** 65 | * load by self first 66 | */ 67 | protected Class> loadClass(String name, boolean resolve) throws ClassNotFoundException { 68 | Class> clazz = null; 69 | try { 70 | clazz = findClass(name); 71 | } catch (ClassNotFoundException e) { 72 | } 73 | if (clazz == null) { 74 | clazz = super.loadClass(name, resolve); 75 | } 76 | return clazz; 77 | } 78 | 79 | /** 80 | * define from bytes loaded 81 | */ 82 | protected Class> findClass(String name) throws ClassNotFoundException { 83 | Class> clazz = this.findLoadedClass(name); 84 | if (clazz == null && name != null) { 85 | String fileName = name.replace(".", "/") + ".class"; 86 | byte[] bytes = bytesMap.get(fileName); 87 | if (bytes == null) { 88 | throw new ClassNotFoundException("class not found : " + name); 89 | } 90 | clazz = this.defineClass(name, bytes, 0, bytes.length); 91 | } 92 | return clazz; 93 | } 94 | 95 | @Override 96 | protected URL findResource(String paramString) { 97 | byte[] extractedBytes = bytesMap.get(paramString); 98 | if (extractedBytes != null) { 99 | try { 100 | return new URL(null, "bytes:///" + paramString, new Handler(extractedBytes)); 101 | } catch (MalformedURLException e) { 102 | } 103 | } 104 | return null; 105 | } 106 | 107 | public URL getResource(String name) { 108 | URL url = findResource(name); 109 | if (url == null) { 110 | url = super.getResource(name); 111 | } 112 | return url; 113 | } 114 | 115 | /** 116 | * self define handler to make byte array into URL 117 | */ 118 | class Handler extends URLStreamHandler { 119 | private final byte[] bytes; 120 | 121 | public Handler(byte[] bytes) { 122 | this.bytes = bytes; 123 | } 124 | 125 | @Override 126 | protected URLConnection openConnection(URL paramURL) throws IOException { 127 | return new ByteURLConnection(paramURL); 128 | } 129 | 130 | /** 131 | * self defined URL connection 132 | */ 133 | class ByteURLConnection extends URLConnection { 134 | public ByteURLConnection(URL paramURL) { 135 | super(paramURL); 136 | } 137 | 138 | @Override 139 | public InputStream getInputStream() throws IOException { 140 | return new ByteArrayInputStream(bytes); 141 | } 142 | 143 | @Override 144 | public void connect() throws IOException {} 145 | } 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /tracer-agent/src/main/java/com/ali/trace/agent/main/AttackEngine.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.agent.main; 2 | 3 | import java.lang.reflect.Method; 4 | import java.net.URL; 5 | import java.net.URLClassLoader; 6 | 7 | // import ; 8 | 9 | /** 10 | * @author nkhanlang@163.com 11 | */ 12 | public class AttackEngine { 13 | 14 | public static void main(String[] args) throws Exception { 15 | String pid = null; 16 | String tool = null; 17 | String agent = null; 18 | String params = null; 19 | if(args.length > 0){ 20 | pid = args[0]; 21 | } 22 | if(args.length > 1){ 23 | agent = args[1]; 24 | } 25 | if(args.length > 2){ 26 | tool = args[2]; 27 | } 28 | if(args.length > 3){ 29 | params = args[3]; 30 | } 31 | if(pid == null){ 32 | System.err.println("please input pid agent tool params"); 33 | System.exit(0); 34 | } 35 | if(agent == null){ 36 | agent = "/u01/project/java-tracer/target/java-tracer.jar"; 37 | } 38 | if(tool == null){ 39 | tool = "/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Classes/classes.jar"; 40 | } 41 | tool = "file:" + tool; 42 | if(params == null){ 43 | params = "intercepter:thread#class:com.hema.sre.pool.service.SqlService#method:exec#online:true"; 44 | } 45 | 46 | Class> clasz = null; 47 | Method detach = null; 48 | Object vm = null; 49 | try { 50 | Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); 51 | method.setAccessible(true); 52 | method.invoke(AttackEngine.class.getClassLoader(), new URL(tool)); 53 | ClassLoader loader = AttackEngine.class.getClassLoader(); 54 | clasz = loader.loadClass("com.sun.tools.attach.VirtualMachine"); 55 | Method attach = clasz.getMethod("attach", String.class); 56 | Method loadAgent = clasz.getMethod("loadAgent", String.class, String.class); 57 | detach = clasz.getMethod("detach"); 58 | 59 | vm = attach.invoke(null, pid); 60 | loadAgent.invoke(vm, agent, 61 | params); 62 | } finally { 63 | if (vm != null && detach != null) { 64 | detach.invoke(vm); 65 | } 66 | } 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /tracer-agent/src/main/java/com/ali/trace/agent/main/CoreEngine.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.agent.main; 2 | 3 | import com.ali.trace.agent.inject.TraceEnhance; 4 | import com.ali.trace.spy.intercepter.CommonIntercepter; 5 | import com.ali.trace.spy.intercepter.CompressIntercepter; 6 | import com.ali.trace.spy.intercepter.CompressTreeIntercepter; 7 | 8 | import java.lang.instrument.Instrumentation; 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | /** 12 | * @author nkhanlang@163.com 13 | */ 14 | public class CoreEngine { 15 | 16 | private static String INTERCEPTER = "intercepter"; 17 | private static String CLASS = "class"; 18 | private static String METHOD = "method"; 19 | private static String PATH = "path"; 20 | private static String ONLINE = "online"; 21 | 22 | //private static TraceTransformer transformer = new TraceTransformer(); 23 | 24 | public static void process(String args, Instrumentation inst) { 25 | String path = null; 26 | String intercepter = null; 27 | Map map = new HashMap(); 28 | if (args != null) { 29 | String[] items = args.split("#"); 30 | for (String item : items) { 31 | String[] keyVal = item.split(":"); 32 | if (keyVal.length == 2) { 33 | map.put(keyVal[0], keyVal[1]); 34 | } 35 | } 36 | } 37 | intercepter = map.get(INTERCEPTER); 38 | path = map.get(PATH); 39 | if ("compress".equalsIgnoreCase(intercepter)) { 40 | TraceEnhance.setIntecepter(new CompressIntercepter(path)); 41 | } else if ("stastic".equals(intercepter)) { 42 | String clasz = map.get(CLASS); 43 | String method = map.get(METHOD); 44 | System.out.println("class:[" + clasz + "]method:[" + method + "]"); 45 | TraceEnhance.setIntecepter(new CompressTreeIntercepter(clasz, method)); 46 | } else if ("thread".equals(intercepter)) { 47 | String clasz = map.get(CLASS); 48 | String method = map.get(METHOD); 49 | System.out.println("class:[" + clasz + "]method:[" + method + "]"); 50 | TraceEnhance.setIntecepter(new CompressTreeIntercepter(clasz, method)); 51 | } else { 52 | boolean printTime = Boolean.valueOf(args); 53 | TraceEnhance.setIntecepter(new CommonIntercepter(path, printTime)); 54 | } 55 | String online = map.get(ONLINE); 56 | System.out.println("map:" + map); 57 | if (Boolean.valueOf(online)) { 58 | System.out.println("online transformer"); 59 | //inst.addTransformer(transformer, true); 60 | } else { 61 | System.out.println("offline transformer"); 62 | //inst.removeTransformer(transformer); 63 | } 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /tracer-agent/src/main/java/com/ali/trace/agent/main/Premain.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.agent.main; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.ByteArrayOutputStream; 5 | import java.io.IOException; 6 | import java.lang.instrument.Instrumentation; 7 | import java.net.URL; 8 | import java.util.HashMap; 9 | import java.util.HashSet; 10 | import java.util.Map; 11 | import java.util.Set; 12 | import java.util.concurrent.atomic.AtomicReference; 13 | import java.util.jar.JarEntry; 14 | import java.util.jar.JarInputStream; 15 | 16 | import com.ali.trace.agent.inject.TraceEnhance; 17 | import com.ali.trace.agent.inject.TraceTransformer; 18 | import com.ali.trace.agent.loader.SpyClassLoader; 19 | 20 | /** 21 | * @author nkhanlang@163.com 22 | */ 23 | public class Premain { 24 | 25 | private static final String PATH = "/META-INF/lib"; 26 | private static final String SPY_CLASS = "com.ali.trace.spy.inject.TraceInjecter"; 27 | // default port opened by JETTY 28 | private static final int DEFAULT_PORT = 18902; 29 | private static final String DEFAULT_CONFIG = ""; 30 | 31 | private static final String CONFIG_PORT="port"; 32 | private static final String CONFIG_SLEEP="sleep"; 33 | private static final String CONFIG_MODE="mode"; 34 | 35 | 36 | private static final SpyClassLoader LOADER = new SpyClassLoader(null); 37 | private static final AtomicReference INJECT = new AtomicReference(); 38 | 39 | public static void premain(String args, Instrumentation inst) { 40 | Map configs = new HashMap(); 41 | int port = DEFAULT_PORT; 42 | long sleep = 1L; 43 | int mode = 0; 44 | if (args != null) { 45 | String[] pairs = args.split(":"); 46 | if(pairs != null){ 47 | for(String pair : pairs){ 48 | int idx = pair.indexOf("="); 49 | if(idx > 0){ 50 | configs.put(pair.substring(0, idx), pair.substring(idx+1)); 51 | }else{ 52 | configs.put(pair, DEFAULT_CONFIG); 53 | } 54 | } 55 | } 56 | String portStr = configs.get(CONFIG_PORT); 57 | if(portStr != null && portStr != DEFAULT_CONFIG){ 58 | port = Integer.valueOf(args); 59 | } 60 | String sleepStr = configs.get(CONFIG_SLEEP); 61 | if(sleepStr != null){ 62 | sleep = Long.parseLong(sleepStr); 63 | } 64 | String modeStr = configs.get(CONFIG_MODE); 65 | if(modeStr != null){ 66 | mode = Integer.valueOf(modeStr); 67 | } 68 | } 69 | System.out.println("init trace agent with port [" + port + "] and sleep [" + sleep + "]"); 70 | System.out.println("pages can be found in http://127.0.0.1:" + port); 71 | Object inject = loadSpyJar(inst, port, mode); 72 | try { 73 | if (inject == null) { 74 | throw new Exception("inject is null"); 75 | } 76 | Thread.sleep(sleep); 77 | inst.addTransformer(new TraceTransformer(inject), true); 78 | } catch (Throwable t) { 79 | t.printStackTrace(); 80 | } 81 | } 82 | 83 | /** 84 | * agent loaded by bootstrap loader, spy and all dependent jars loaded by spy loader 85 | */ 86 | private static Object loadSpyJar(Instrumentation inst, int port, int mode) { 87 | Object inject = null; 88 | if ((inject = INJECT.get()) == null) { 89 | synchronized (Premain.class) { 90 | if ((inject = INJECT.get()) == null) { 91 | String path = Premain.class.getResource(PATH).getPath(); 92 | if (path.endsWith(PATH)) { 93 | path = path.substring(0, path.length() - PATH.length() - 1); 94 | } 95 | try { 96 | JarInputStream jarInput = null; 97 | try { 98 | jarInput = new JarInputStream(new URL(path).openStream()); 99 | JarEntry entry = null; 100 | while ((entry = jarInput.getNextJarEntry()) != null) { 101 | String entryName = "/" + entry.getName(); 102 | if (entryName.startsWith(PATH) && entryName.endsWith(".jar")) { 103 | ByteArrayOutputStream bytes = new ByteArrayOutputStream(); 104 | int chunk = 0; 105 | byte[] data = new byte[256]; 106 | while (-1 != (chunk = jarInput.read(data))) { 107 | bytes.write(data, 0, chunk); 108 | } 109 | data = bytes.toByteArray(); 110 | LOADER.load(new ByteArrayInputStream(data, 0, data.length)); 111 | } 112 | } 113 | } catch (Exception e) { 114 | e.printStackTrace(); 115 | } finally { 116 | if (jarInput != null) { 117 | try { 118 | jarInput.close(); 119 | } catch (IOException e1) { 120 | e1.printStackTrace(); 121 | } 122 | } 123 | } 124 | Class> injectClass = LOADER.loadClass(SPY_CLASS); 125 | INJECT.set(inject = 126 | injectClass.getConstructor(Instrumentation.class, Class.class, int.class, int.class).newInstance(inst, TraceEnhance.class, port, mode)); 127 | } catch (Throwable t) { 128 | t.printStackTrace(); 129 | } 130 | } 131 | } 132 | } 133 | return inject; 134 | } 135 | 136 | private static Set CANT_TRANSFORM = new HashSet(); 137 | 138 | public static void agentmain(String args, Instrumentation inst) { 139 | CoreEngine.process(args, inst); 140 | Class>[] classes = inst.getAllLoadedClasses(); 141 | for (Class> clasz : classes) { 142 | String name = clasz.getName(); 143 | try { 144 | if (clasz.getClassLoader() != null && clasz.getClassLoader().getParent() != null 145 | && !CANT_TRANSFORM.contains(name)) { 146 | // inst.retransformClasses(new Class>[] {clasz}); 147 | } 148 | } catch (Throwable t) { 149 | CANT_TRANSFORM.add(name); 150 | // t.printStackTrace(); 151 | } 152 | } 153 | } 154 | 155 | } 156 | -------------------------------------------------------------------------------- /tracer-agent/src/test/java/com/ali/dbtech/test/AsmTest.java: -------------------------------------------------------------------------------- 1 | package com.ali.dbtech.test; 2 | 3 | import java.io.FileNotFoundException; 4 | import java.io.IOException; 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | import org.objectweb.asm.ClassReader; 9 | import org.objectweb.asm.ClassVisitor; 10 | import org.objectweb.asm.ClassWriter; 11 | import org.objectweb.asm.MethodVisitor; 12 | import org.objectweb.asm.Opcodes; 13 | import org.objectweb.asm.Type; 14 | 15 | import com.ali.dbtech.test.AsmTest.MyClassVisitor.MethodInfo; 16 | 17 | public class AsmTest { 18 | 19 | public static void main(String[] args) throws FileNotFoundException, IOException { 20 | MyClassVisitor visitor = new MyClassVisitor(AsmTest.class.getName()); 21 | for (MethodInfo method : visitor.getMethods()) { 22 | System.out.println("Title: invokes of " + method.getClasz() + ":" + method.getMethod()); 23 | for (MethodInfo invoke : method.getInvoke()) { 24 | if (!invoke.getClasz().startsWith("java.")) { 25 | System.out.println(method.getClasz() + "->" + invoke.getClasz() + ":" + invoke.getMethod()); 26 | } 27 | } 28 | System.out.println(); 29 | } 30 | 31 | } 32 | 33 | /** 34 | * 类的所有方法存在methods里面 35 | */ 36 | public static class MyClassVisitor extends ClassVisitor { 37 | private List methods = new ArrayList(); 38 | private String cname; 39 | 40 | public MyClassVisitor(String className) throws IOException { 41 | super(Opcodes.ASM7, new ClassWriter(ClassReader.SKIP_DEBUG)); 42 | ClassReader cr = new ClassReader(className); 43 | cr.accept(this, ClassReader.SKIP_DEBUG); 44 | } 45 | 46 | public List getMethods() { 47 | return methods; 48 | } 49 | 50 | public void visit(final int version, final int access, final String cname, final String signature, 51 | final String superName, final String[] interfaces) { 52 | this.cname = cname; 53 | super.visit(version, access, cname, signature, superName, interfaces); 54 | } 55 | 56 | public MethodVisitor visitMethod(final int access, final String mname, final String descriptor, 57 | final String signature, final String[] exceptions) { 58 | return new MyMethodVisitor(mname, descriptor, 59 | cv.visitMethod(access, mname, descriptor, signature, exceptions)); 60 | } 61 | 62 | private class MyMethodVisitor extends MethodVisitor { 63 | private MethodInfo method; 64 | 65 | public MyMethodVisitor(String mname, String descriptor, MethodVisitor mv) { 66 | super(Opcodes.ASM7, mv); 67 | method = new MethodInfo(cname, mname, descriptor); 68 | methods.add(method); 69 | } 70 | 71 | public void visitMethodInsn(final int opcode, final String invokeCname, final String invokeMname, 72 | final String InvokeDescriptor, final boolean isInterface) { 73 | method.addInvoke(new MethodInfo(invokeCname, invokeMname, InvokeDescriptor)); 74 | super.visitMethodInsn(opcode, invokeCname, invokeMname, InvokeDescriptor, isInterface); 75 | } 76 | } 77 | 78 | /** 79 | * 存储类名,方法名,方法描述,及方法内部调用过的方法 80 | */ 81 | public class MethodInfo { 82 | String cname; 83 | String mname; 84 | String descripter; 85 | List invokeInfo = new ArrayList(); 86 | 87 | public MethodInfo(String cname, String mname, String descripter) { 88 | this.cname = cname; 89 | this.mname = mname; 90 | this.descripter = descripter; 91 | } 92 | 93 | public void addInvoke(MethodInfo invoke) { 94 | invokeInfo.add(invoke); 95 | } 96 | 97 | public List getInvoke() { 98 | return invokeInfo; 99 | } 100 | 101 | public String getClasz() { 102 | return Type.getType("L" + cname + ";").getClassName(); 103 | } 104 | 105 | public String getMethod() { 106 | Type retType = Type.getReturnType(descripter); 107 | Type[] argTypes = Type.getArgumentTypes(descripter); 108 | StringBuilder sb = new StringBuilder(); 109 | String split = ""; 110 | for (Type argType : argTypes) { 111 | sb.append(split).append(argType.getClassName()); 112 | split = ","; 113 | } 114 | return mname + "#(" + sb + ")" + retType.getClassName(); 115 | } 116 | } 117 | 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /tracer-agent/src/test/java/com/ali/dbtech/test/AsmVisitTrace.java: -------------------------------------------------------------------------------- 1 | package com.ali.dbtech.test; 2 | 3 | import java.io.FileNotFoundException; 4 | import java.io.IOException; 5 | import java.util.Scanner; 6 | 7 | import org.objectweb.asm.ClassReader; 8 | import org.objectweb.asm.ClassVisitor; 9 | import org.objectweb.asm.ClassWriter; 10 | import org.objectweb.asm.Opcodes; 11 | 12 | 13 | public class AsmVisitTrace { 14 | 15 | public static void main(String[] args) throws FileNotFoundException, IOException { 16 | // 17 | // String name = Test.class.getName(); 18 | // new Test(); 19 | Scanner scanner = new Scanner(System.in); 20 | String line = null; 21 | //test(name); 22 | while((line = scanner.nextLine()) != null && !"q".equalsIgnoreCase(line)){ 23 | System.out.println("print line : " + line); 24 | test(line); 25 | } 26 | } 27 | 28 | public static void test(String name) throws IOException{ 29 | new ClassReader(name).accept( 30 | new ClassVisitor(Opcodes.ASM7, new ClassWriter( ClassWriter.COMPUTE_MAXS) { 31 | public String getCommonSuperClass(String type1, String type2) { 32 | System.out.println("names : " + type1 + "," + type2); 33 | return super.getCommonSuperClass(type1, type2); 34 | } 35 | }) {}, ClassReader.EXPAND_FRAMES); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /tracer-agent/src/test/java/com/ali/dbtech/test/DynamicCode.java: -------------------------------------------------------------------------------- 1 | package com.ali.dbtech.test; 2 | 3 | public class DynamicCode implements Runnable { 4 | 5 | public void run() { 6 | 7 | MainProcess.print(); 8 | } 9 | 10 | public static void main(String[] args){ 11 | new DynamicCode().run(); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /tracer-agent/src/test/java/com/ali/dbtech/test/MainProcess.java: -------------------------------------------------------------------------------- 1 | package com.ali.dbtech.test; 2 | 3 | import java.text.SimpleDateFormat; 4 | import java.util.Date; 5 | 6 | public class MainProcess { 7 | 8 | private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; 9 | 10 | public static void main(String[] args) throws InterruptedException { 11 | Object t = new Object(); 12 | System.out.println(t instanceof Object); 13 | 14 | System.out.println("hello world"); 15 | while (true) { 16 | Thread.sleep(2 * 1000); 17 | System.out.println("sleep over now time is " + new SimpleDateFormat(DATE_FORMAT).format(new Date())); 18 | } 19 | } 20 | 21 | public static void print(){ 22 | System.out.println("externer call time is " + new SimpleDateFormat(DATE_FORMAT).format(new Date())); 23 | throw new RuntimeException("s"); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tracer-agent/src/test/java/com/ali/dbtech/test/TransferTest.java: -------------------------------------------------------------------------------- 1 | package com.ali.dbtech.test; 2 | 3 | import java.io.FileOutputStream; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.io.OutputStream; 7 | 8 | import org.objectweb.asm.ClassReader; 9 | import org.objectweb.asm.ClassVisitor; 10 | import org.objectweb.asm.ClassWriter; 11 | import org.objectweb.asm.Label; 12 | import org.objectweb.asm.MethodVisitor; 13 | import org.objectweb.asm.Opcodes; 14 | import org.objectweb.asm.Type; 15 | import org.objectweb.asm.commons.AdviceAdapter; 16 | import org.objectweb.asm.commons.Method; 17 | 18 | import com.ali.trace.spy.util.NameUtils; 19 | 20 | public class TransferTest { 21 | 22 | public static void main(String[] args) throws IOException { 23 | InputStream in = null; 24 | OutputStream out = null; 25 | try { 26 | in = DynamicCode.class.getResourceAsStream("DynamicCode.class"); 27 | out = new FileOutputStream("/tmp/com/ali/dbtech/test/DynamicCode.class"); 28 | 29 | byte[] bytes = new byte[in.available()]; 30 | in.read(bytes); 31 | bytes = new TraceInjecter(bytes).getBytes(); 32 | out.write(bytes); 33 | } finally { 34 | if (in != null) { 35 | in.close(); 36 | } 37 | if (out != null) { 38 | out.close(); 39 | } 40 | } 41 | 42 | } 43 | 44 | public static void s(String c, String m) { 45 | System.out.println("start [" + c + "." + m + "]"); 46 | } 47 | 48 | public static void e(String c, String m) { 49 | System.out.println("end [" + c + "." + m + "]"); 50 | } 51 | 52 | static class TraceInjecter extends ClassReader { 53 | 54 | private ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); 55 | private Class> clasz = TransferTest.class; 56 | private Type type; 57 | private Method start; 58 | private Method end; 59 | { 60 | { 61 | type = Type.getType(clasz); 62 | try { 63 | start = Method.getMethod(clasz.getMethod("s", new Class>[] {String.class, String.class})); 64 | end = Method.getMethod(clasz.getMethod("e", new Class>[] {String.class, String.class})); 65 | } catch (Throwable e) { 66 | e.printStackTrace(); 67 | } 68 | } 69 | } 70 | 71 | public TraceInjecter(byte[] classfileBuffer) { 72 | super(classfileBuffer); 73 | accept(new CodeVisitor(classWriter), EXPAND_FRAMES); 74 | } 75 | 76 | public byte[] getBytes() { 77 | return classWriter.toByteArray(); 78 | } 79 | 80 | class CodeVisitor extends ClassVisitor { 81 | private String cName; 82 | 83 | public CodeVisitor(ClassVisitor cv) { 84 | super(Opcodes.ASM5, cv); 85 | } 86 | 87 | @Override 88 | public void visit(int paramInt1, int paramInt2, String paramString1, String paramString2, 89 | String paramString3, String[] paramArrayOfString) { 90 | cName = NameUtils.getClassName(paramString1); 91 | super.visit(paramInt1, paramInt2, paramString1, paramString2, paramString3, paramArrayOfString); 92 | } 93 | 94 | @Override 95 | public MethodVisitor visitMethod(int access, String name, String desc, String signature, 96 | String[] exceptions) { 97 | if ((access & 256) != 0) { 98 | return super.visitMethod(access, name, desc, signature, exceptions); 99 | } 100 | return new FinallyAdapter(super.visitMethod(access, name, desc, signature, exceptions), 101 | 102 | access, name, desc); 103 | } 104 | 105 | class FinallyAdapter extends AdviceAdapter { 106 | private String name; 107 | private Label startFinally = new Label(); 108 | private Label endFinally = new Label(); 109 | 110 | public FinallyAdapter(MethodVisitor mv, int acc, String name, String desc) { 111 | super(Opcodes.ASM5, mv, acc, name, desc); 112 | this.name = NameUtils.getMethodName(name); 113 | } 114 | 115 | @Override 116 | protected void onMethodEnter() { 117 | push(cName); 118 | push(name); 119 | invokeStatic(type, start); 120 | mark(startFinally); 121 | } 122 | 123 | public void visitMaxs(int maxStack, int maxLocals) { 124 | mark(endFinally); 125 | visitTryCatchBlock(startFinally, endFinally, mark(), null); 126 | onFinally(ATHROW); 127 | dup(); 128 | throwException(); 129 | // maxLocals = maxLocals > 2 ? maxLocals : 2; 130 | super.visitMaxs(maxStack, maxLocals); 131 | } 132 | 133 | protected void onMethodExit(int opcode) { 134 | if (opcode != ATHROW) { 135 | onFinally(opcode); 136 | } 137 | } 138 | 139 | private void onFinally(int opcode) { 140 | push(cName); 141 | push(name); 142 | invokeStatic(type, end); 143 | } 144 | } 145 | } 146 | } 147 | 148 | } 149 | -------------------------------------------------------------------------------- /tracer-agent/src/test/java/com/ali/dbtech/test/error/Test.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | 14 | package com.ali.dbtech.test.error; 15 | 16 | public class Test { 17 | public Test() { 18 | System.out.println(this != null ? this : new Object()); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tracer-spy/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | java-tracer 5 | tracer 6 | 0.0.1-SNAPSHOT 7 | ../pom.xml 8 | 9 | 10 | 4.0.0 11 | tracer-spy 12 | jar 13 | 14 | 15 | 16 | 17 | 18 | 19 | org.ow2.asm 20 | asm 21 | 22 | 23 | org.ow2.asm 24 | asm-commons 25 | 26 | 27 | org.ow2.asm 28 | asm-util 29 | 30 | 31 | 32 | 33 | org.eclipse.jetty 34 | jetty-server 35 | 36 | 37 | org.eclipse.jetty 38 | jetty-servlet 39 | 40 | 41 | javax.servlet 42 | javax.servlet-api 43 | 44 | 45 | 46 | 47 | velocity 48 | velocity 49 | 50 | 51 | com.google.code.gson 52 | gson 53 | 54 | 55 | 57 | 58 | io.netty 59 | netty-all 60 | 4.0.42.Final 61 | test 62 | 63 | 64 | 65 | org.apache.logging.log4j 66 | log4j-slf4j-impl 67 | 2.11.2 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /tracer-spy/src/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Created-By: Apache Maven 3 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/core/ConfigPool.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.core; 2 | 3 | import com.ali.trace.spy.intercepter.IIntercepter; 4 | 5 | import java.lang.instrument.ClassFileTransformer; 6 | import java.lang.instrument.IllegalClassFormatException; 7 | import java.lang.instrument.Instrumentation; 8 | import java.lang.reflect.Method; 9 | import java.security.ProtectionDomain; 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | import java.util.Map; 13 | import java.util.concurrent.ConcurrentHashMap; 14 | import java.util.concurrent.CopyOnWriteArrayList; 15 | import java.util.concurrent.atomic.AtomicInteger; 16 | /** 17 | * @author nkhanlang@163.com 18 | */ 19 | public class ConfigPool { 20 | 21 | private static final ConfigPool INSTANCE = new ConfigPool(); 22 | private final AtomicInteger SEQ_SEED = new AtomicInteger(0); 23 | 24 | private CopyOnWriteArrayList loaderSets = new CopyOnWriteArrayList(); 25 | private Class> weaveClass; 26 | private Instrumentation inst; 27 | private volatile ClassLoader redefineLoader; 28 | private volatile String redefineName; 29 | private EmptyTransformer emptyTransformer = new EmptyTransformer(); 30 | 31 | public static ConfigPool getPool() { 32 | return INSTANCE; 33 | } 34 | 35 | public void setInst(Instrumentation inst) { 36 | this.inst = inst; 37 | } 38 | 39 | public boolean isRedefine(ClassLoader loader, String name){ 40 | return loader == redefineLoader && name.equalsIgnoreCase(redefineName); 41 | } 42 | 43 | public void redefine(int type){ 44 | for(LoaderSet loaderSet : loaderSets){ 45 | ClassLoader loader = loaderSet.getLoader(); 46 | for(String name : loaderSet.classNames.keySet()){ 47 | if(type == loaderSet.classNames.get(name)){ 48 | redefine(loader, name); 49 | } 50 | } 51 | } 52 | } 53 | 54 | private synchronized void redefine(ClassLoader loader, String name){ 55 | this.redefineLoader = loader; 56 | this.redefineName = name; 57 | try { 58 | inst.retransformClasses(loader.loadClass(name.replace("/", "."))); 59 | } catch (Exception e) { 60 | e.printStackTrace(); 61 | } 62 | this.redefineLoader = null; 63 | this.redefineName = null; 64 | } 65 | 66 | public ClassLoader redefine(int loaderId, String redefineName){ 67 | LoaderSet loaderSet = getLoderSet(Integer.valueOf(loaderId)); 68 | ClassLoader loader =null; 69 | if(loaderSet != null) { 70 | loader = loaderSet.getLoader(); 71 | for (String name : loaderSet.classNames.keySet()) { 72 | if(name.equalsIgnoreCase(redefineName)){ 73 | redefine(loader, name); 74 | break; 75 | } 76 | } 77 | } 78 | return loader; 79 | } 80 | 81 | private LoaderSet getLoaderSet(ClassLoader loader){ 82 | LoaderSet loaderSet = null;; 83 | for (LoaderSet set : loaderSets) { 84 | if (set.loader == loader) { 85 | loaderSet = set; 86 | } 87 | } 88 | return loaderSet; 89 | } 90 | 91 | public void addClass(ClassLoader loader, String className, Integer type) { 92 | LoaderSet loaderSet = null; 93 | if ((loaderSet = getLoaderSet(loader)) == null) { 94 | synchronized (loaderSets){ 95 | if ((loaderSet = getLoaderSet(loader)) == null) { 96 | loaderSets.add(loaderSet = new LoaderSet(SEQ_SEED.incrementAndGet(), loader)); 97 | } 98 | } 99 | } 100 | loaderSet.classNames.put(className, type); 101 | } 102 | 103 | public List getLoaderSets(){ 104 | return new ArrayList(loaderSets); 105 | } 106 | 107 | private LoaderSet getLoderSet(int id){ 108 | LoaderSet loaderSet = null;; 109 | for (LoaderSet set : loaderSets) { 110 | if (set.id == id) { 111 | loaderSet = set; 112 | } 113 | } 114 | return loaderSet; 115 | } 116 | 117 | public void setWeaveClass(Class> weaveClass) { 118 | if (weaveClass != null) { 119 | this.weaveClass = weaveClass; 120 | } 121 | } 122 | 123 | public boolean setIntercepter(IIntercepter intercepter) { 124 | boolean set = false; 125 | if (weaveClass != null) { 126 | try { 127 | Method method = weaveClass.getDeclaredMethod("setIntecepter", Object.class); 128 | Object setObj = method.invoke(null, intercepter); 129 | if (setObj != null && Boolean.TRUE.equals(setObj)) { 130 | set = true; 131 | } 132 | } catch (Throwable e) { 133 | e.printStackTrace(); 134 | } 135 | } 136 | return set; 137 | } 138 | 139 | public boolean delIntercepter() { 140 | boolean del = false; 141 | if (weaveClass != null) { 142 | try { 143 | Method method = weaveClass.getDeclaredMethod("delIntercepter"); 144 | method.invoke(null); 145 | del = true; 146 | } catch (Throwable e) { 147 | e.printStackTrace(); 148 | } 149 | } 150 | return del; 151 | } 152 | 153 | public class LoaderSet { 154 | final int id; 155 | final ClassLoader loader; 156 | Map classNames = new ConcurrentHashMap(); 157 | private LoaderSet(int id, ClassLoader loader) { 158 | this.id=id; 159 | this.loader = loader; 160 | } 161 | public int getId() { 162 | return id; 163 | } 164 | public ClassLoader getLoader() { 165 | return loader; 166 | } 167 | public Map getClassNames() { 168 | return classNames; 169 | } 170 | } 171 | 172 | public static class EmptyTransformer implements ClassFileTransformer{ 173 | 174 | public byte[] transform(ClassLoader loader, String className, Class> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { 175 | System.out.println("empty:" + className); 176 | return classfileBuffer; 177 | } 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/core/NodePool.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.core; 2 | 3 | import com.ali.trace.spy.util.BaseNode; 4 | import com.ali.trace.spy.util.RootNode; 5 | 6 | import java.util.HashMap; 7 | import java.util.Iterator; 8 | import java.util.Map; 9 | import java.util.concurrent.ConcurrentHashMap; 10 | import java.util.concurrent.LinkedBlockingQueue; 11 | import java.util.concurrent.atomic.AtomicLong; 12 | 13 | /** 14 | * @author nkhanlang@163.com 15 | */ 16 | public class NodePool { 17 | 18 | private static final AtomicLong MAX = new AtomicLong(0L); 19 | private static final AtomicLong MIN = new AtomicLong(0L); 20 | private static final NodePool INSTANCE = new NodePool(); 21 | 22 | private final Map POOL = new ConcurrentHashMap(); 23 | private final LinkedBlockingQueue QUEUE = new LinkedBlockingQueue< RootNode>(); 24 | 25 | 26 | private int mode; 27 | private volatile long size = 5; 28 | public static NodePool getPool() { 29 | return INSTANCE; 30 | } 31 | 32 | public RootNode getNode(Long seed){ 33 | return POOL.get(seed); 34 | } 35 | 36 | 37 | public void setMode(int mode){ 38 | this.mode = mode; 39 | if(mode > 0){ 40 | setSize(1024L); 41 | } 42 | } 43 | public int getMode(){ 44 | return mode; 45 | } 46 | 47 | public void setSize(long size){ 48 | this.size = size; 49 | while(MAX.get() - MIN.get() > size) { 50 | RootNode root = QUEUE.poll(); 51 | if( root != null){ 52 | POOL.remove(root.getId()); 53 | MIN.incrementAndGet(); 54 | }else{ 55 | break; 56 | } 57 | } 58 | } 59 | public long getSize(){return size;} 60 | 61 | public Map getNodes(){ 62 | Map map = new HashMap(); 63 | Iterator itr = QUEUE.iterator(); 64 | while(itr.hasNext()){ 65 | RootNode root = itr.next(); 66 | map.put(root.getId(), root); 67 | } 68 | return map; 69 | } 70 | 71 | public void addNode(BaseNode node, String type){ 72 | long seed = MAX.incrementAndGet(); 73 | while(seed - MIN.get() > size) { 74 | RootNode root = QUEUE.poll(); 75 | if( root != null){ 76 | POOL.remove(root.getId()); 77 | MIN.incrementAndGet(); 78 | }else{ 79 | break; 80 | } 81 | } 82 | RootNode root = new RootNode(seed, node, type); 83 | POOL.put(seed, root); 84 | QUEUE.offer(root); 85 | } 86 | 87 | 88 | 89 | } 90 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/helper/IFileNameGenerator.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.helper; 2 | 3 | /** 4 | * @author nkhanlang@163.com 5 | */ 6 | public interface IFileNameGenerator { 7 | 8 | /** 9 | * generate file name 10 | * 11 | * @return 12 | */ 13 | String getName(); 14 | } 15 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/helper/InputStreamClassLoader.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.helper; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | import java.util.jar.JarEntry; 9 | import java.util.jar.JarInputStream; 10 | 11 | /** 12 | * @author nkhanlang@163.com 13 | */ 14 | public class InputStreamClassLoader extends ClassLoader { 15 | private Map classBytes = new HashMap(); 16 | 17 | public InputStreamClassLoader(InputStream in) { 18 | super(InputStreamClassLoader.class.getClassLoader().getParent()); 19 | 20 | Map newClasses = new HashMap(); 21 | JarInputStream jarInput = null; 22 | try { 23 | jarInput = new JarInputStream(in); 24 | JarEntry entry = jarInput.getNextJarEntry(); 25 | while (entry != null) { 26 | String entryName = entry.getName(); 27 | if (entryName.endsWith(".class")) { 28 | String className = entryName.replace(".class", "").replace("/", "."); 29 | if (!classBytes.containsKey(className)) { 30 | ByteArrayOutputStream bytes = new ByteArrayOutputStream(); 31 | int chunk = 0; 32 | byte[] data = new byte[256]; 33 | while (-1 != (chunk = jarInput.read(data))) { 34 | bytes.write(data, 0, chunk); 35 | } 36 | classBytes.put(className, bytes.toByteArray()); 37 | newClasses.put(className, true); 38 | } else { 39 | newClasses.put(className, false); 40 | } 41 | } 42 | entry = jarInput.getNextJarEntry(); 43 | } 44 | } catch (Exception e) { 45 | e.printStackTrace(); 46 | } finally { 47 | if (jarInput != null) { 48 | try { 49 | jarInput.close(); 50 | } catch (IOException e1) { 51 | e1.printStackTrace(); 52 | } 53 | } 54 | } 55 | } 56 | 57 | @Override 58 | protected Class> findClass(String name) throws ClassNotFoundException { 59 | Class> clazz = this.findLoadedClass(name); 60 | if (clazz == null) { 61 | byte[] bytes = classBytes.get(name); 62 | if (bytes == null) { 63 | throw new ClassNotFoundException("class not found : " + name); 64 | } 65 | clazz = this.defineClass(name, bytes, 0, bytes.length); 66 | } 67 | return clazz; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/helper/ThreadFileNameGenerator.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.helper; 2 | 3 | /** 4 | * @author nkhanlang@163.com 5 | */ 6 | public class ThreadFileNameGenerator implements IFileNameGenerator { 7 | 8 | private String path; 9 | 10 | public ThreadFileNameGenerator(String path) { 11 | this.path = path; 12 | } 13 | 14 | @Override 15 | public String getName() { 16 | Thread thread = Thread.currentThread(); 17 | StackTraceElement[] traces = thread.getStackTrace(); 18 | StackTraceElement trace = traces[traces.length - 1]; 19 | String fName = new StringBuilder(path).append("/").append(trace.getClassName()).append("-") 20 | .append(thread.getId()).append(".xml").toString(); 21 | return fName; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/inject/TraceInjecter.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.inject; 2 | 3 | import com.ali.trace.spy.core.NodePool; 4 | import com.ali.trace.spy.intercepter.CommonThreadntercepter; 5 | import com.ali.trace.spy.intercepter.CompressThreadIntercepter; 6 | import org.objectweb.asm.ClassReader; 7 | import org.objectweb.asm.ClassVisitor; 8 | import org.objectweb.asm.ClassWriter; 9 | import org.objectweb.asm.Label; 10 | import org.objectweb.asm.MethodVisitor; 11 | import org.objectweb.asm.Opcodes; 12 | import org.objectweb.asm.Type; 13 | import org.objectweb.asm.commons.AdviceAdapter; 14 | import org.objectweb.asm.commons.Method; 15 | 16 | import com.ali.trace.spy.core.ConfigPool; 17 | import com.ali.trace.spy.jetty.JettyServer; 18 | 19 | import java.lang.instrument.Instrumentation; 20 | 21 | /** 22 | * trace code inject 23 | * 24 | * @author nkhanlang@163.com 25 | * 26 | */ 27 | public class TraceInjecter { 28 | private final ClassLoader LOADER; 29 | private final Type TYPE; 30 | private final Method START; 31 | private final Method END; 32 | private final ConfigPool POOL = ConfigPool.getPool(); 33 | 34 | public TraceInjecter(Instrumentation inst, Class> clasz, int port, int mode) throws NoSuchMethodException, SecurityException { 35 | LOADER = getClass().getClassLoader(); 36 | TYPE = Type.getType(clasz); 37 | START = Method.getMethod(clasz.getMethod("s", new Class>[] {String.class, String.class})); 38 | END = Method.getMethod(clasz.getMethod("e", new Class>[] {String.class, String.class})); 39 | POOL.setInst(inst); 40 | POOL.setWeaveClass(clasz); 41 | NodePool.getPool().setMode(mode); 42 | if(mode == 1){ 43 | POOL.setIntercepter(new CommonThreadntercepter()); 44 | }else if(mode == 2){ 45 | POOL.setIntercepter(new CompressThreadIntercepter()); 46 | } 47 | new JettyServer(port); 48 | } 49 | 50 | public byte[] getBytes(final ClassLoader loader, final String name, byte[] bytes) throws Throwable { 51 | Integer type = 0; 52 | try { 53 | if (name != null) { 54 | if ((loader != null && loader != LOADER 55 | && !name.startsWith("com/alibaba/jvm/sandbox/core/manager/impl/SandboxClassFileTransformer") 56 | && !name.startsWith("com/google/gson/internal/reflect/ReflectionAccessor")) 57 | || (loader == null && name.startsWith("java/com/alibaba/jvm/sandbox/spy"))) { 58 | bytes = new CodeReader(loader, name, bytes, POOL.isRedefine(loader, name), false).getBytes(); 59 | type = 1; 60 | } 61 | } 62 | return bytes; 63 | } catch (TypeNotPresentException e) { 64 | type = 3; 65 | throw e; 66 | } catch (Throwable t) { 67 | try{ 68 | bytes = new CodeReader(loader, name, bytes, POOL.isRedefine(loader, name), true).getBytes(); 69 | type = 1; 70 | return bytes; 71 | }catch (Throwable t1){ 72 | type = 2; 73 | System.err.println("class : " + name); 74 | //t1.printStackTrace(); 75 | throw t1; 76 | } 77 | } finally { 78 | if (name != null) { 79 | POOL.addClass(loader, name, type); 80 | } 81 | } 82 | } 83 | 84 | class CodeReader extends ClassReader { 85 | private final ClassWriter classWriter; 86 | 87 | public CodeReader(final ClassLoader loader, final String name, byte[] bytes, final boolean redefine, boolean common) { 88 | super(bytes); 89 | int flag = ClassWriter.COMPUTE_MAXS; 90 | if(!common){ 91 | flag = flag | ClassWriter.COMPUTE_FRAMES; 92 | } 93 | classWriter = new ClassWriter(flag) { 94 | @Override 95 | public ClassLoader getClassLoader() { 96 | return loader; 97 | } 98 | 99 | @Override 100 | protected String getCommonSuperClass(final String type1, final String type2) { 101 | if(!redefine) { 102 | if (name.equals(type1)) { 103 | throw new TypeNotPresentException(type1, 104 | new Exception("circular define 1:[" + type1 + "," + type2 + "]")); 105 | } 106 | if (name.equals(type2)) { 107 | throw new TypeNotPresentException(type2, 108 | new Exception("circular define 2:[" + type1 + "," + type2 + "]")); 109 | } 110 | } 111 | return super.getCommonSuperClass(type1, type2); 112 | } 113 | }; 114 | accept(new CodeVisitor(classWriter, common), EXPAND_FRAMES); 115 | } 116 | /** 117 | * return modified bytes 118 | */ 119 | public byte[] getBytes() { 120 | return classWriter.toByteArray(); 121 | } 122 | } 123 | 124 | /** 125 | * weave code before and after each method 126 | * 127 | * @author hanlang.hl 128 | * 129 | */ 130 | class CodeVisitor extends ClassVisitor { 131 | private String cName; 132 | private boolean common; 133 | 134 | public CodeVisitor(ClassVisitor cv, boolean common) { 135 | super(Opcodes.ASM7, cv); 136 | this.common = common; 137 | } 138 | 139 | @Override 140 | public void visit(int paramInt1, int paramInt2, String paramString1, String paramString2, String paramString3, 141 | String[] paramArrayOfString) { 142 | cName = paramString1.replace('/', '.').replaceAll("\\$", "."); 143 | super.visit(paramInt1, paramInt2, paramString1, paramString2, paramString3, paramArrayOfString); 144 | } 145 | 146 | @Override 147 | public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { 148 | if ((access & 256) != 0) { 149 | return super.visitMethod(access, name, desc, signature, exceptions); 150 | } 151 | if(common){ 152 | return new CommonAdapter(super.visitMethod(access, name, desc, signature, exceptions), access, name, desc); 153 | }else { 154 | return new FinallyAdapter(super.visitMethod(access, name, desc, signature, exceptions), access, name, desc); 155 | } 156 | } 157 | 158 | class FinallyAdapter extends AdviceAdapter { 159 | private String mName; 160 | private Label startFinally = new Label(); 161 | private Label endFinally = new Label(); 162 | 163 | public FinallyAdapter(MethodVisitor methodVisitor, int acc, String name, String desc) { 164 | super(Opcodes.ASM7, methodVisitor, acc, name, desc); 165 | this.mName = name.replaceAll("<", "_").replaceAll("\\$|>", ""); 166 | } 167 | 168 | @Override 169 | protected void onMethodEnter() { 170 | push(cName); 171 | push(mName); 172 | invokeStatic(TYPE, START); 173 | mark(startFinally); 174 | } 175 | 176 | @Override 177 | public void visitMaxs(int maxStack, int maxLocals) { 178 | mark(endFinally); 179 | visitTryCatchBlock(startFinally, endFinally, mark(), null); 180 | onFinally(); 181 | dup(); 182 | throwException(); 183 | super.visitMaxs(maxStack, maxLocals); 184 | } 185 | 186 | @Override 187 | protected void onMethodExit(int opcode) { 188 | if (opcode != ATHROW) { 189 | onFinally(); 190 | } 191 | } 192 | 193 | private void onFinally() { 194 | push(cName); 195 | push(mName); 196 | invokeStatic(TYPE, END); 197 | } 198 | } 199 | 200 | class CommonAdapter extends AdviceAdapter { 201 | private String mName; 202 | private Label startFinally = new Label(); 203 | private Label endFinally = new Label(); 204 | 205 | public CommonAdapter(MethodVisitor methodVisitor, int acc, String name, String desc) { 206 | super(Opcodes.ASM7, methodVisitor, acc, name, desc); 207 | this.mName = name.replaceAll("<", "_").replaceAll("\\$|>", ""); 208 | } 209 | 210 | @Override 211 | protected void onMethodEnter() { 212 | push(cName); 213 | push(mName); 214 | invokeStatic(TYPE, START); 215 | } 216 | 217 | @Override 218 | protected void onMethodExit(int opcode) { 219 | push(cName); 220 | push(mName); 221 | invokeStatic(TYPE, END); 222 | } 223 | } 224 | } 225 | } 226 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/intercepter/BaseIntercepter.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.intercepter; 2 | 3 | import java.io.BufferedWriter; 4 | import java.io.FileWriter; 5 | import java.io.IOException; 6 | import java.io.Writer; 7 | 8 | import com.ali.trace.spy.helper.IFileNameGenerator; 9 | import com.ali.trace.spy.helper.ThreadFileNameGenerator; 10 | 11 | /** 12 | * print XML format stacks 13 | * 14 | * @author nkhanlang@163.com 15 | * 16 | */ 17 | public abstract class BaseIntercepter implements IIntercepter { 18 | private final String path; 19 | private final ThreadLocal t_outs = new ThreadLocal(); 20 | private IFileNameGenerator nameGenerator; 21 | 22 | public BaseIntercepter(String path) { 23 | if (path != null) { 24 | this.path = path; 25 | } else { 26 | this.path = "/tmp/"; 27 | } 28 | } 29 | 30 | public void setNameGenerator(IFileNameGenerator nameGenerator) { 31 | this.nameGenerator = nameGenerator; 32 | } 33 | 34 | protected void write(String line) throws Exception { 35 | if (line != null) { 36 | Writer out = getWriter(); 37 | out.write(line); 38 | out.flush(); 39 | } 40 | } 41 | 42 | protected Writer getWriter() throws IOException { 43 | Writer out = t_outs.get(); 44 | if (out == null) { 45 | if (nameGenerator == null) { 46 | synchronized (this) { 47 | if (nameGenerator == null) { 48 | nameGenerator = new ThreadFileNameGenerator(path); 49 | } 50 | } 51 | } 52 | String fName = nameGenerator.getName(); 53 | t_outs.set(out = new BufferedWriter(new FileWriter(fName))); 54 | } 55 | return out; 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/intercepter/CommonIntercepter.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.intercepter; 2 | 3 | import java.io.IOException; 4 | import java.lang.reflect.Field; 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | import java.util.Map.Entry; 8 | import java.util.Stack; 9 | 10 | /** 11 | * @author nkhanlang@163.com 12 | */ 13 | public class CommonIntercepter extends BaseIntercepter { 14 | 15 | private final long start = System.currentTimeMillis(); 16 | private final ThreadLocal prePiece = new ThreadLocal(); 17 | private final ThreadLocal lineNumber = new ThreadLocal(); 18 | private final ThreadLocal preTime = new ThreadLocal(); 19 | private final ThreadLocal stack = new ThreadLocal(); 20 | private final ThreadLocal> pieceStacks = new ThreadLocal>(); 21 | 22 | private static final char TIME_OFF_START = 'o'; 23 | private static final char THREAD_LINE = 'l'; 24 | private static final char THREAD_DEPTH = 'd'; 25 | private static final char CLASS_NAME = 'c'; 26 | private static final char STEP_COST = 't'; 27 | private static final char SON_COUNT = 's'; 28 | private static Map INFO_MAP = new HashMap(); 29 | static { 30 | Field[] fields = CommonIntercepter.class.getDeclaredFields(); 31 | for (Field field : fields) { 32 | if (field.getType() == char.class) { 33 | try { 34 | INFO_MAP.put((Character) field.get(null), field.getName()); 35 | } catch (Exception e) { 36 | //e.printStackTrace(); 37 | } 38 | } 39 | } 40 | } 41 | 42 | private final boolean printTime; 43 | public CommonIntercepter(String path, boolean printTime) { 44 | super(path); 45 | this.printTime = printTime; 46 | } 47 | 48 | public void start(String c, String m) { 49 | try { 50 | Integer s = stack.get(); 51 | StringBuilder sb = null; 52 | if (s == null) { 53 | sb = getBuilder(m); 54 | stack.set(1); 55 | } else { 56 | sb = new StringBuilder(64).append('<').append(m); 57 | stack.set(s + 1); 58 | } 59 | 60 | printDepth(printLine(sb)); 61 | 62 | long t = System.currentTimeMillis() - start; 63 | if(printTime){ 64 | printTime(sb, t); 65 | } 66 | sb.append(" ").append(CLASS_NAME).append("='").append(c).append('\'').append(">\r\n"); 67 | 68 | write(sb.toString()); 69 | Piece piece = new Piece(c, m, t); 70 | prePiece.set(piece); 71 | if (!pieceStacks.get().isEmpty()) { 72 | Piece superPiece = pieceStacks.get().peek(); 73 | superPiece.sons = superPiece.sons + 1; 74 | } 75 | pieceStacks.get().push(piece); 76 | } catch (Throwable t) { 77 | //t.printStackTrace(); 78 | } 79 | } 80 | 81 | public void end(String c, String m) { 82 | try { 83 | stack.set(stack.get() - 1); 84 | Stack pieceStack = pieceStacks.get(); 85 | Piece piece = null; 86 | if (pieceStack == null || pieceStack.isEmpty() || (piece = pieceStack.pop()) == null || !c.equals(piece.c) 87 | || !m.equals(piece.m)) { 88 | return; 89 | } 90 | 91 | StringBuilder sb = new StringBuilder("").append(m); 92 | printCost(sb, piece); 93 | if(printTime){ 94 | printSons(sb, piece); 95 | } 96 | sb.append(">\r\n"); 97 | write(sb.toString()); 98 | } catch (Throwable t) { 99 | t.printStackTrace(); 100 | } 101 | } 102 | 103 | StringBuilder getBuilder(String m) throws IOException { 104 | lineNumber.set(0L); 105 | Stack pieceStack = pieceStacks.get(); 106 | if (pieceStack == null) { 107 | pieceStacks.set(new Stack()); 108 | } 109 | StringBuilder sb = new StringBuilder(96).append('<').append(m); 110 | for (Entry entry : INFO_MAP.entrySet()) { 111 | sb.append(" ").append(entry.getKey()).append("_").append("='").append(entry.getValue()).append('\''); 112 | } 113 | return sb; 114 | } 115 | 116 | long printTime(StringBuilder sb, long t) { 117 | preTime.set(t); 118 | sb.append(" ").append(TIME_OFF_START).append("='").append(t).append('\''); 119 | return t; 120 | } 121 | 122 | StringBuilder printLine(StringBuilder sb) { 123 | long l = lineNumber.get() + 1; 124 | lineNumber.set(l); 125 | return sb.append(" ").append(THREAD_LINE).append("='").append(l).append('\''); 126 | } 127 | 128 | StringBuilder printDepth(StringBuilder sb) { 129 | return sb.append(" ").append(THREAD_DEPTH).append("='").append(stack.get()).append('\''); 130 | } 131 | 132 | StringBuilder printCost(StringBuilder sb, Piece piece) { 133 | long p = System.currentTimeMillis() - start - piece.time; 134 | return sb.append(" ").append(STEP_COST).append("='").append(p).append('\''); 135 | } 136 | 137 | StringBuilder printSons(StringBuilder sb, Piece piece) { 138 | return sb.append(" ").append(SON_COUNT).append("='").append(piece.sons).append('\''); 139 | } 140 | 141 | /** 142 | * record method stack . 143 | */ 144 | static final class Piece { 145 | String c; 146 | String m; 147 | long time; 148 | int sons; 149 | 150 | Piece(String c, String m, long time) { 151 | this.c = c; 152 | this.m = m; 153 | this.time = time; 154 | this.sons = 0; 155 | } 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/intercepter/CommonThreadntercepter.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.intercepter; 2 | 3 | import com.ali.trace.spy.util.CommonNode; 4 | 5 | /** 6 | * @author nkhanlang@163.com 7 | */ 8 | public class CommonThreadntercepter extends ThreadTreeIntercepter { 9 | 10 | protected CommonNode getNode(long metaId) { 11 | return new CommonNode(metaId); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/intercepter/CommonTreeIntercepter.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.intercepter; 2 | 3 | import com.ali.trace.spy.util.CommonNode; 4 | 5 | /** 6 | * @author nkhanlang@163.com 7 | */ 8 | public class CommonTreeIntercepter extends MethodTreeIntercepter { 9 | 10 | public CommonTreeIntercepter(String c, String m) { 11 | super(c, m); 12 | } 13 | 14 | protected CommonNode getNode(long metaId) { 15 | return new CommonNode(metaId); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/intercepter/CompressIntercepter.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.intercepter; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.HashSet; 6 | import java.util.Iterator; 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.Set; 10 | import java.util.Stack; 11 | 12 | import com.ali.trace.spy.util.NameUtils; 13 | 14 | /** 15 | * delete duplication stacks 16 | * 17 | * @author nkhanlang@163.com 18 | * 19 | */ 20 | public class CompressIntercepter extends BaseIntercepter { 21 | private final ThreadLocal t_depth = new ThreadLocal(); 22 | private final ThreadLocal t_seq = new ThreadLocal(); 23 | private final ThreadLocal> t_map = new ThreadLocal>(); 24 | private final ThreadLocal t_root = new ThreadLocal(); 25 | private final ThreadLocal> t_stack = new ThreadLocal>(); 26 | 27 | public CompressIntercepter(String path) { 28 | super(path); 29 | } 30 | 31 | public final void start(String c, String m) throws Exception { 32 | if (t_seq.get() == null) { 33 | t_seq.set(0); 34 | t_map.set(new HashMap()); 35 | t_stack.set(new Stack()); 36 | } 37 | 38 | Integer depth = t_depth.get(); 39 | t_depth.set(depth = (depth == null) ? 1 : depth + 1); 40 | Node node = new Node(m, c).buildDepth(depth); 41 | if (t_stack.get().isEmpty()) { 42 | t_stack.get().push(node); 43 | t_root.set(node); 44 | } else { 45 | Node preNode = t_stack.get().peek(); 46 | if (preNode.depth == depth - 1) { 47 | preNode.sons.add(node); 48 | node.parent = preNode; 49 | t_stack.get().push(node); 50 | } else if (preNode.depth > depth - 1) { 51 | do { 52 | preNode = t_stack.get().pop(); 53 | preNode.format(); 54 | if (preNode.parent != null && preNode.parent.isRef == 1) { 55 | write(t_root.get().printPre().append(preNode.printSur()).toString()); 56 | preNode.sons.clear(); 57 | } 58 | } while (preNode.depth > depth); 59 | Node parent = t_stack.get().peek(); 60 | parent.sons.add(node); 61 | node.parent = parent; 62 | t_stack.get().push(node); 63 | } else { 64 | throw new RuntimeException("depth error"); 65 | } 66 | } 67 | } 68 | 69 | public final void end(String c, String m) throws Exception { 70 | t_depth.set(t_depth.get() - 1); 71 | if (t_depth.get() == 0) { 72 | while (!t_stack.get().isEmpty()) { 73 | Node preNode = t_stack.get().pop(); 74 | preNode.format(); 75 | if (preNode.parent != null && preNode.parent.isRef == 1) { 76 | write(t_root.get().printPre().append(preNode.printSur()).toString()); 77 | preNode.sons.clear(); 78 | } 79 | } 80 | write(t_root.get().printSur().toString()); 81 | } 82 | } 83 | 84 | class Node { 85 | String method; 86 | String clasz; 87 | Node parent; 88 | int depth; 89 | 90 | String content; 91 | int ref = 0; 92 | int isRef = 0; 93 | int print = 0; 94 | List sons = new ArrayList(); 95 | 96 | public Node(String method, String clasz) { 97 | this.method = method; 98 | this.clasz = clasz; 99 | } 100 | 101 | public Node buildDepth(int depth) { 102 | this.depth = depth; 103 | return this; 104 | } 105 | 106 | public void format() { 107 | if (content == null) { 108 | StringBuilder sb = new StringBuilder(clasz).append(".").append(method).append("["); 109 | Set set = new HashSet(); 110 | Iterator itr = sons.iterator(); 111 | while (itr.hasNext()) { 112 | Node node = itr.next(); 113 | node.format(); 114 | if (set.add(node.content)) { 115 | sb.append(node.content).append(","); 116 | } else { 117 | itr.remove(); 118 | } 119 | } 120 | sb.append("]"); 121 | content = NameUtils.getHexMd5(sb.toString()); 122 | Node refNode = t_map.get().get(content); 123 | if (refNode == null) { 124 | t_map.get().put(content, this); 125 | t_seq.set(t_seq.get() + 1); 126 | this.ref = t_seq.get(); 127 | setRef(1); 128 | } else { 129 | this.ref = refNode.ref; 130 | setRef(2); 131 | } 132 | } 133 | } 134 | 135 | public void setRef(int isRef) { 136 | if (this.isRef == 0) { 137 | this.isRef = isRef; 138 | if (isRef == 1 && parent != null) { 139 | parent.setRef(isRef); 140 | } 141 | } 142 | } 143 | 144 | public StringBuilder printPre() { 145 | StringBuilder sb = new StringBuilder(); 146 | if (print == 0) { 147 | sb.append("<").append(method).append(" c='").append(clasz) 148 | .append("'>\r\n").toString(); 149 | print = 1; 150 | if (isRef == 2) { 151 | sb.append(printSur()); 152 | } 153 | } 154 | if (isRef == 1) { 155 | Set preSons = new HashSet(); 156 | for (Node son : sons) { 157 | if (!preSons.contains(son.content)) { 158 | preSons.add(son.content); 159 | sb.append(son.printPre()); 160 | } 161 | } 162 | } 163 | return sb; 164 | } 165 | 166 | public StringBuilder printSur() { 167 | if (print == 1) { 168 | print = 2; 169 | return new StringBuilder("").append(method).append(" r='").append(ref).append("' i='").append(isRef) 170 | .append("'").append(">\r\n"); 171 | } 172 | return new StringBuilder(); 173 | } 174 | } 175 | 176 | } 177 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/intercepter/CompressThreadIntercepter.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.intercepter; 2 | 3 | import com.ali.trace.spy.util.CompressNode; 4 | 5 | /** 6 | * @author nkhanlang@163.com 7 | */ 8 | public class CompressThreadIntercepter extends ThreadTreeIntercepter { 9 | 10 | protected CompressNode getNode(long metaId) { 11 | return new CompressNode(metaId); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/intercepter/CompressTreeIntercepter.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.intercepter; 2 | 3 | import com.ali.trace.spy.util.CompressNode; 4 | 5 | /** 6 | * @author nkhanlang@163.com 7 | */ 8 | public class CompressTreeIntercepter extends MethodTreeIntercepter { 9 | 10 | public CompressTreeIntercepter(String c, String m) { 11 | super(c, m); 12 | } 13 | 14 | protected CompressNode getNode(long metaId) { 15 | return new CompressNode(metaId); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/intercepter/IIntercepter.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.intercepter; 2 | 3 | /** 4 | * do around method except exception 5 | * 6 | * @author nkhanlang@163.com 7 | * 8 | */ 9 | public interface IIntercepter { 10 | 11 | /** 12 | * do before with class and method name 13 | */ 14 | void start(String c, String m) throws Exception; 15 | 16 | /** 17 | * do after with class and method name 18 | */ 19 | void end(String c, String m) throws Exception; 20 | } 21 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/intercepter/MethodTreeIntercepter.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.intercepter; 2 | 3 | import com.ali.trace.spy.core.NodePool; 4 | import com.ali.trace.spy.util.BaseNode; 5 | 6 | import java.util.Stack; 7 | 8 | /** 9 | * @author nkhanlang@163.com 10 | */ 11 | public abstract class MethodTreeIntercepter extends BaseIntercepter { 12 | 13 | protected final String c; 14 | protected final String m; 15 | protected final ThreadLocal> t_stack = new ThreadLocal>(); 16 | protected final ThreadLocal> t_time = new ThreadLocal>(); 17 | protected final NodePool nodePool; 18 | 19 | public MethodTreeIntercepter(String c, String m) { 20 | super(null); 21 | this.c = c; 22 | this.m = m; 23 | nodePool = NodePool.getPool(); 24 | } 25 | 26 | public String getC(){ 27 | return c; 28 | } 29 | public String getM(){ 30 | return m; 31 | } 32 | 33 | public void start(String c, String m) { 34 | Stack stack = t_stack.get(); 35 | Stack time = t_time.get(); 36 | if (c.equalsIgnoreCase(this.c) && m.equalsIgnoreCase(this.m)) { 37 | if (stack == null) { 38 | t_stack.set(stack = new Stack()); 39 | T node = getNode(BaseNode.getId(c, m)); 40 | nodePool.addNode(node, getClass().getSimpleName()); 41 | stack.add(node); 42 | t_time.set(time = new Stack()); 43 | } 44 | } 45 | if (stack != null && !stack.isEmpty()) { 46 | if (!time.isEmpty()) { 47 | stack.push((T)stack.peek().addSon(BaseNode.getId(c, m))); 48 | } 49 | time.add(System.currentTimeMillis()); 50 | } 51 | } 52 | 53 | protected abstract T getNode(long metaId); 54 | 55 | public void end(String c, String m) { 56 | Stack stack = t_stack.get(); 57 | Stack time = t_time.get(); 58 | T node = null; 59 | if (stack != null && !stack.isEmpty()) { 60 | node = stack.pop(); 61 | node.addRt(System.currentTimeMillis() - time.pop()); 62 | } 63 | if (stack != null && stack.isEmpty()) { 64 | t_stack.set(null); 65 | t_time.set(null); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/intercepter/ThreadTreeIntercepter.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.intercepter; 2 | 3 | import com.ali.trace.spy.core.NodePool; 4 | import com.ali.trace.spy.util.BaseNode; 5 | 6 | import java.util.Stack; 7 | 8 | /** 9 | * @author nkhanlang@163.com 10 | */ 11 | public abstract class ThreadTreeIntercepter extends BaseIntercepter { 12 | 13 | protected final ThreadLocal> t_stack = new ThreadLocal>(); 14 | protected final ThreadLocal> t_time = new ThreadLocal>(); 15 | protected final NodePool nodePool; 16 | 17 | public ThreadTreeIntercepter() { 18 | super(null); 19 | nodePool = NodePool.getPool(); 20 | } 21 | 22 | public void start(String c, String m) { 23 | Stack stack = t_stack.get(); 24 | Stack time = t_time.get(); 25 | if (stack == null) { 26 | t_stack.set(stack = new Stack()); 27 | T node = getNode(BaseNode.getId(c, m)); 28 | Thread t = Thread.currentThread(); 29 | nodePool.addNode(node, t.getName() + "[" + t.getId() + "]"); 30 | stack.add(node); 31 | t_time.set(time = new Stack()); 32 | time.add(System.currentTimeMillis()); 33 | } 34 | if (stack != null && !stack.isEmpty()) { 35 | if (!time.isEmpty()) { 36 | stack.push((T)stack.peek().addSon(BaseNode.getId(c, m))); 37 | } 38 | time.add(System.currentTimeMillis()); 39 | } 40 | } 41 | 42 | protected abstract T getNode(long metaId); 43 | 44 | public void end(String c, String m) { 45 | Stack stack = t_stack.get(); 46 | Stack time = t_time.get(); 47 | T node = null; 48 | if (stack != null && !stack.isEmpty()) { 49 | node = stack.pop(); 50 | node.addRt(System.currentTimeMillis() - time.pop()); 51 | } 52 | if (stack != null && stack.isEmpty()) { 53 | t_stack.set(null); 54 | t_time.set(null); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/jetty/JettyServer.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.jetty; 2 | 3 | import com.ali.trace.spy.jetty.support.HandlerConfig; 4 | import org.eclipse.jetty.server.Server; 5 | import org.eclipse.jetty.servlet.ServletContextHandler; 6 | import org.eclipse.jetty.servlet.ServletHolder; 7 | import org.eclipse.jetty.util.thread.QueuedThreadPool; 8 | 9 | import java.net.InetSocketAddress; 10 | 11 | /** 12 | * @author nkhanlang@163.com 13 | */ 14 | public class JettyServer { 15 | 16 | public JettyServer(int port) { 17 | 18 | final ServletContextHandler context = new ServletContextHandler(null, ModuleHttpServlet.ROOT, ServletContextHandler.NO_SESSIONS); 19 | 20 | context.setClassLoader(JettyServer.class.getClassLoader()); 21 | final String pathSpec = "/*"; 22 | context.addServlet(new ServletHolder(new ModuleHttpServlet(HandlerConfig.getInstance())), pathSpec); 23 | 24 | Server httpServer = new Server(new InetSocketAddress(port)); 25 | if (httpServer.getThreadPool() instanceof QueuedThreadPool) { 26 | final QueuedThreadPool qtp = (QueuedThreadPool)httpServer.getThreadPool(); 27 | qtp.setName("tracer-jetty-qtp" + qtp.hashCode()); 28 | } 29 | httpServer.setHandler(context); 30 | try { 31 | httpServer.start(); 32 | } catch (Exception e) { 33 | e.printStackTrace(); 34 | } finally { 35 | } 36 | } 37 | 38 | public static void main(String[] args) { 39 | { 40 | int port = 8080; 41 | new JettyServer(port); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/jetty/ModuleHttpServlet.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.jetty; 2 | 3 | import com.ali.trace.spy.jetty.handler.ITraceHttpHandler.ModelMap; 4 | import com.ali.trace.spy.jetty.handler.ITraceHttpHandler.TraceParam; 5 | import com.ali.trace.spy.jetty.handler.ITraceHttpHandler.TraceView; 6 | import com.ali.trace.spy.jetty.io.VmViewResolver; 7 | import com.ali.trace.spy.jetty.support.HandlerConfig; 8 | import com.ali.trace.spy.jetty.support.Module; 9 | 10 | import javax.servlet.ServletException; 11 | import javax.servlet.http.HttpServlet; 12 | import javax.servlet.http.HttpServletRequest; 13 | import javax.servlet.http.HttpServletResponse; 14 | import java.io.IOException; 15 | import java.io.PrintWriter; 16 | import java.lang.annotation.Annotation; 17 | import java.lang.reflect.Method; 18 | import java.util.HashMap; 19 | import java.util.Map; 20 | 21 | /** 22 | * @author nkhanlang@163.com 23 | */ 24 | public class ModuleHttpServlet extends HttpServlet { 25 | 26 | /** 27 | * 28 | */ 29 | private static final long serialVersionUID = 1L; 30 | 31 | public static final String ROOT = ""; 32 | private HandlerConfig config; 33 | public ModuleHttpServlet(HandlerConfig config){ 34 | this.config = config; 35 | } 36 | 37 | @Override 38 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 39 | doMethod(req, resp, "get"); 40 | } 41 | 42 | @Override 43 | protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 44 | doMethod(req, resp, "post"); 45 | } 46 | 47 | private void doMethod(final HttpServletRequest req, final HttpServletResponse resp, final String requestMethod) 48 | throws ServletException, IOException { 49 | final String path = req.getPathInfo(); 50 | Module module = null; 51 | for(Module m : config.getModules()){ 52 | if(m.match(path)){ 53 | module = m; 54 | break; 55 | } 56 | } 57 | 58 | if (module == null) { 59 | module = config.getDefaultModule(); 60 | } 61 | 62 | final PrintWriter writer = resp.getWriter(); 63 | if (module != null) { 64 | Method method = module.getMethod(); 65 | try { 66 | Object[] params = generateParams(method, req, resp); 67 | Object ret = method.invoke(module.getHttpHandler(), params); 68 | if (ret != null) { 69 | TraceView view = method.getAnnotation(TraceView.class); 70 | if(ret instanceof String && view != null){ 71 | String viewPath = "static/vm/" + ret + ".vm"; 72 | Map model = new HashMap(); 73 | for(Object param : params){ 74 | if(param instanceof ModelMap){ 75 | model.putAll((ModelMap)param); 76 | } 77 | } 78 | VmViewResolver.resolve(viewPath, model, writer); 79 | }else{ 80 | writer.write(ret.toString()); 81 | } 82 | } 83 | } catch (Throwable e) { 84 | e.printStackTrace(writer); 85 | } 86 | } else { 87 | writer.write("path with[" + path + "]has no handler"); 88 | } 89 | } 90 | 91 | private Object[] generateParams(final Method method, final HttpServletRequest req, 92 | final HttpServletResponse resp) { 93 | final Class>[] paramTypes = method.getParameterTypes(); 94 | if (paramTypes != null && paramTypes.length > 0) { 95 | final Object[] params = new Object[paramTypes.length]; 96 | final Annotation[][] annos = method.getParameterAnnotations(); 97 | for (int index = 0; index < params.length; index++) { 98 | final Class> paramType = paramTypes[index]; 99 | if (HttpServletRequest.class.isAssignableFrom(paramType)) { 100 | params[index] = req; 101 | }else if (HttpServletResponse.class.isAssignableFrom(paramType)) { 102 | params[index] = resp; 103 | }else if(PrintWriter.class.isAssignableFrom(paramType)) { 104 | try { 105 | params[index] = resp.getWriter(); 106 | } catch (IOException e) { 107 | e.printStackTrace(); 108 | } 109 | }else if(String.class.isAssignableFrom(paramType) && annos[index] != null && annos[index].length > 0){ 110 | for(Annotation anno : annos[index]){ 111 | if(anno.annotationType() == TraceParam.class){ 112 | String name = ((TraceParam)anno).value(); 113 | if(name != null){ 114 | String value = req.getParameter(name); 115 | if(value != null){ 116 | params[index] = value.trim(); 117 | } 118 | } 119 | } 120 | } 121 | }else if(ModelMap.class.isAssignableFrom(paramType)){ 122 | params[index] = new ModelMap(); 123 | } 124 | } 125 | return params; 126 | } 127 | return null; 128 | } 129 | 130 | } 131 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/jetty/handler/ClassHandler.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.jetty.handler; 2 | 3 | import com.ali.trace.spy.core.ConfigPool; 4 | import com.ali.trace.spy.core.ConfigPool.LoaderSet; 5 | import com.ali.trace.spy.jetty.vo.DataRet; 6 | import com.ali.trace.spy.xml.XmlNode; 7 | 8 | import java.io.IOException; 9 | import java.io.PrintWriter; 10 | import java.util.ArrayList; 11 | import java.util.Collection; 12 | import java.util.Collections; 13 | import java.util.Comparator; 14 | import java.util.List; 15 | import java.util.Map; 16 | import java.util.Map.Entry; 17 | import java.util.Set; 18 | import java.util.TreeSet; 19 | 20 | /** 21 | * @author nkhanlang@163.com 22 | */ 23 | public class ClassHandler implements ITraceHttpHandler { 24 | 25 | @TracerPath(value = "/class", order = 10) 26 | public void thread(PrintWriter writer) throws IOException { 27 | writer.write(""); 28 | ConfigPool pool = ConfigPool.getPool(); 29 | RootNode root = new RootNode(); 30 | for (LoaderSet loader : pool.getLoaderSets()) { 31 | String name = ""; 32 | if (loader != null) { 33 | name = loader.toString().replaceAll("'|<|>|\\$", "_"); 34 | } 35 | LoaderNode node = root.addLoader(name); 36 | Map classNames = loader.getClassNames(); 37 | for (Entry entry : classNames.entrySet()) { 38 | String cname = entry.getKey(); 39 | cname = cname.replaceAll("'|<|>|\\$", "_"); 40 | node.addClass(cname, entry.getValue(), loader.getId()); 41 | } 42 | } 43 | root.write(writer); 44 | } 45 | 46 | @TracerPath(value = "/class/redefine", order = 10) 47 | public DataRet redefine(@TraceParam("lid")String loaderId, @TraceParam("cname")String cname) throws IOException { 48 | DataRet ret = null; 49 | try { 50 | ClassLoader loader = ConfigPool.getPool().redefine(Integer.valueOf(loaderId), cname); 51 | ret = new DataRet(true, 0, "redefine class[" + cname + "]lid[" + loaderId + "]loader[" + loader + "]"); 52 | } catch (Exception e) { 53 | ret = new DataRet(false, -1, "redefine class[" + cname + "]lid[" + loaderId + "]failed" + e.getMessage()); 54 | } 55 | return ret; 56 | } 57 | 58 | @TracerPath(value = "/class/redefineType", order = 10) 59 | public DataRet redefineType(@TraceParam("type")String type) throws IOException { 60 | DataRet ret = null; 61 | try { 62 | ConfigPool.getPool().redefine(Integer.valueOf(type)); 63 | ret = new DataRet(true, 0, "redefine type failed"); 64 | } catch (Exception e) { 65 | ret = new DataRet(false, -1, "redefine type failed" + e.getMessage()); 66 | } 67 | return ret; 68 | } 69 | 70 | class RootNode extends LoaderNode { 71 | List children = new ArrayList(); 72 | 73 | RootNode() { 74 | super("boot"); 75 | } 76 | 77 | int cnt; 78 | 79 | LoaderNode addLoader(String name) { 80 | LoaderNode node = new LoaderNode(name); 81 | children.add(node); 82 | cnt++; 83 | return node; 84 | } 85 | 86 | @Override 87 | protected String getStart() { 88 | StringBuilder sb = new StringBuilder("\r\n").toString(); 91 | } 92 | 93 | @Override 94 | protected String getEnd() { 95 | return "\r\n"; 96 | } 97 | 98 | @Override 99 | protected Collection getChildren() { 100 | Collections.sort(children, new Comparator() { 101 | public int compare(LoaderNode o1, LoaderNode o2) { 102 | return o2.cnt - o1.cnt; 103 | } 104 | }); 105 | return children; 106 | } 107 | } 108 | 109 | class ClassNode extends LoaderNode { 110 | int type; 111 | int loaderId; 112 | 113 | ClassNode(String name, int type, int loaderId) { 114 | super(name); 115 | this.type = type; 116 | this.loaderId = loaderId; 117 | } 118 | 119 | @Override 120 | protected String getStart() { 121 | StringBuilder sb = new StringBuilder("\r\n").toString(); 126 | } 127 | 128 | @Override 129 | protected String getEnd() { 130 | return "\r\n"; 131 | } 132 | } 133 | 134 | class LoaderNode extends XmlNode { 135 | int cnt; 136 | String name; 137 | Set children = new TreeSet(new Comparator() { 138 | public int compare(LoaderNode o1, LoaderNode o2) { 139 | return o1.name.compareTo(o2.name); 140 | } 141 | 142 | }); 143 | 144 | LoaderNode(String name) { 145 | this.name = name; 146 | } 147 | 148 | void addClass(String className, int type, int loaderId) { 149 | cnt++; 150 | children.add(new ClassNode(className, type, loaderId)); 151 | } 152 | 153 | @Override 154 | protected String getStart() { 155 | StringBuilder sb = new StringBuilder("\r\n").toString(); 159 | } 160 | 161 | @Override 162 | protected String getEnd() { 163 | return "\r\n"; 164 | } 165 | 166 | @Override 167 | protected Collection getChildren() { 168 | return children; 169 | } 170 | 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/jetty/handler/ITraceHttpHandler.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.jetty.handler; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | import java.util.HashMap; 9 | 10 | 11 | /** 12 | * @author nkhanlang@163.com 13 | * @date 2019-08-21 23:32 14 | */ 15 | public interface ITraceHttpHandler { 16 | 17 | @Target({ElementType.METHOD}) 18 | @Retention(RetentionPolicy.RUNTIME) 19 | @Documented 20 | public @interface TracerPath { 21 | String value() default ""; 22 | int order() default 0; 23 | } 24 | 25 | @Target({ElementType.PARAMETER}) 26 | @Retention(RetentionPolicy.RUNTIME) 27 | @Documented 28 | public @interface TraceParam { 29 | String value() default ""; 30 | } 31 | 32 | @Target({ElementType.METHOD}) 33 | @Retention(RetentionPolicy.RUNTIME) 34 | @Documented 35 | public @interface TraceView { 36 | } 37 | 38 | public class ModelMap extends HashMap{ 39 | 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/jetty/handler/IndexHandler.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.jetty.handler; 2 | 3 | import java.io.IOException; 4 | import java.io.PrintWriter; 5 | 6 | /** 7 | * @author nkhanlang@163.com 8 | */ 9 | public class IndexHandler implements ITraceHttpHandler { 10 | 11 | @TracerPath(value = "/index", order = 1) 12 | @TraceView 13 | public String getInfo(PrintWriter writer) throws IOException { 14 | return "index"; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/jetty/handler/StaticHandler.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.jetty.handler; 2 | 3 | import com.ali.trace.spy.jetty.io.StaticResResolver; 4 | 5 | import javax.servlet.http.HttpServletRequest; 6 | import java.io.IOException; 7 | import java.io.PrintWriter; 8 | import java.util.regex.Pattern; 9 | 10 | /** 11 | * @author nkhanlang@163.com 12 | */ 13 | public class StaticHandler implements ITraceHttpHandler { 14 | 15 | @TracerPath(value="/static/((js)|(css))/.*", order=100) 16 | public void set(HttpServletRequest req, PrintWriter writer) throws IOException { 17 | String path = req.getPathInfo(); 18 | if(path.charAt(0) == '/'){ 19 | path = path.substring(1); 20 | } 21 | StaticResResolver.resolve(path, writer); 22 | } 23 | 24 | public static void main(String[] args){ 25 | System.out.println(Pattern.compile("^/static/js/.*$").matcher("/static/js/home.js").find()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/jetty/handler/ThreadHandler.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.jetty.handler; 2 | 3 | import com.ali.trace.spy.xml.XmlNode; 4 | 5 | import java.io.IOException; 6 | import java.io.PrintWriter; 7 | import java.util.ArrayList; 8 | import java.util.Collection; 9 | import java.util.Collections; 10 | import java.util.Comparator; 11 | import java.util.LinkedHashMap; 12 | import java.util.List; 13 | import java.util.Map; 14 | import java.util.Map.Entry; 15 | 16 | /** 17 | * @author nkhanlang@163.com 18 | */ 19 | public class ThreadHandler implements ITraceHttpHandler { 20 | 21 | @TracerPath(value = "/thread", order = 10) 22 | public void thread(PrintWriter writer) throws IOException { 23 | Map stackTraces = Thread.getAllStackTraces(); 24 | writer.write(""); 25 | Node root = new RootNode(stackTraces.size()); 26 | for (Entry entry : stackTraces.entrySet()) { 27 | Thread thread = entry.getKey(); 28 | StackTraceElement[] stacks = entry.getValue(); 29 | int size = stacks.length; 30 | Node node = root; 31 | for (size = stacks.length - 1; size >= 0; size--) { 32 | StackTraceElement stackTrace = stacks[size]; 33 | String mname = stackTrace.getMethodName().replaceAll("'|<|>|\\$", "_"); 34 | String cname = stackTrace.getClassName().replaceAll("'|<|>|\\$", "_"); 35 | int line = stackTrace.getLineNumber(); 36 | node = node.addSon(cname, mname, line); 37 | } 38 | long id = thread.getId(); 39 | String name = thread.getName(); 40 | if (name != null) { 41 | name = name.replaceAll("'|<|>|\\$", "_"); 42 | } 43 | node.addSon(String.valueOf(id), new NameNode(name, id)); 44 | } 45 | root.write(writer); 46 | } 47 | 48 | class RootNode extends Node { 49 | RootNode(int cnt) { 50 | this.cnt = cnt; 51 | } 52 | 53 | protected String getStart() { 54 | StringBuilder sb = new StringBuilder("").toString(); 56 | } 57 | 58 | protected String getEnd() { 59 | return ""; 60 | } 61 | } 62 | 63 | class NameNode extends Node { 64 | String name; 65 | long id; 66 | 67 | NameNode(String name, long id) { 68 | this.name = name; 69 | this.id = id; 70 | } 71 | 72 | protected String getStart() { 73 | StringBuilder sb = new StringBuilder("").toString(); 76 | } 77 | 78 | protected String getEnd() { 79 | return ""; 80 | } 81 | } 82 | 83 | class Node extends XmlNode { 84 | String cname; 85 | String mname; 86 | int line; 87 | int cnt; 88 | Map children = new LinkedHashMap(); 89 | 90 | private Node() { 91 | } 92 | 93 | private Node(String cname, String mname, int line) { 94 | this.cname = cname; 95 | this.mname = mname; 96 | this.line = line; 97 | } 98 | 99 | Node addSon(String cname, String mname, int line) { 100 | String key = cname + "#" + mname + "#" + line; 101 | Node son = children.get(key); 102 | if (son == null) { 103 | children.put(key, son = new Node(cname, mname, line)); 104 | } 105 | son.cnt++; 106 | return son; 107 | } 108 | 109 | Node addSon(String key, Node son) { 110 | children.put(key, son); 111 | return son; 112 | } 113 | 114 | protected String getStart() { 115 | StringBuilder sb = new StringBuilder("<").append(mname); 116 | sb.append(" class='").append(cname); 117 | sb.append("' line='").append(line); 118 | sb.append("' cnt='").append(cnt); 119 | return sb.append("'>").toString(); 120 | } 121 | 122 | protected String getEnd() { 123 | StringBuilder sb = new StringBuilder("").append(mname); 124 | return sb.append(">").toString(); 125 | } 126 | 127 | protected Collection getChildren() { 128 | List sons = new ArrayList(children.values()); 129 | Collections.sort(sons, new Comparator() { 130 | public int compare(Node o1, Node o2) { 131 | return o2.cnt - o1.cnt; 132 | } 133 | }); 134 | return sons; 135 | } 136 | 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/jetty/handler/TraceHandler.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.jetty.handler; 2 | 3 | import com.ali.trace.spy.core.ConfigPool; 4 | import com.ali.trace.spy.core.NodePool; 5 | import com.ali.trace.spy.intercepter.MethodTreeIntercepter; 6 | import com.ali.trace.spy.intercepter.CommonTreeIntercepter; 7 | import com.ali.trace.spy.intercepter.CompressTreeIntercepter; 8 | import com.ali.trace.spy.jetty.vo.DataRet; 9 | import com.ali.trace.spy.jetty.vo.MetaVO; 10 | import com.ali.trace.spy.jetty.vo.RecordVO; 11 | import com.ali.trace.spy.jetty.vo.SetVO; 12 | import com.ali.trace.spy.jetty.vo.TraceVO; 13 | import com.ali.trace.spy.util.BaseNode; 14 | import com.ali.trace.spy.util.RootNode; 15 | import org.apache.commons.lang.math.NumberUtils; 16 | 17 | import java.io.IOException; 18 | import java.io.PrintWriter; 19 | import java.text.SimpleDateFormat; 20 | import java.util.ArrayList; 21 | import java.util.Calendar; 22 | import java.util.List; 23 | import java.util.Map; 24 | 25 | /** 26 | * @author nkhanlang@163.com 27 | */ 28 | public class TraceHandler implements ITraceHttpHandler { 29 | 30 | private volatile MethodTreeIntercepter intercepter; 31 | private final NodePool nodePool = NodePool.getPool(); 32 | 33 | @TracerPath(value = "/trace/set", order = 1) 34 | public DataRet set(PrintWriter writer, @TraceParam("class") String cname, 35 | @TraceParam("method") String mname, 36 | @TraceParam("size") String sizeStr, 37 | @TraceParam("type") String type) throws IOException { 38 | DataRet ret = null; 39 | try { 40 | if (NumberUtils.isDigits(sizeStr)) { 41 | nodePool.setSize(Integer.valueOf(sizeStr)); 42 | } 43 | if (cname != null && mname != null) { 44 | if("CompressTreeIntercepter".equalsIgnoreCase(type)){ 45 | intercepter = new CompressTreeIntercepter(cname, mname); 46 | }else { 47 | intercepter = new CommonTreeIntercepter(cname, mname); 48 | } 49 | ConfigPool.getPool().setIntercepter(intercepter); 50 | }else{ 51 | ConfigPool.getPool().delIntercepter(); 52 | intercepter = null; 53 | } 54 | ret = new DataRet(true, 0, "set class[" + cname + "]method[" + mname + "]size[" + sizeStr + "]"); 55 | } catch (Exception e) { 56 | e.printStackTrace(); 57 | ret = new DataRet(false, -1, "set class[" + cname + "]method[" + mname + "]failed" + e.getMessage()); 58 | } 59 | return ret; 60 | } 61 | 62 | @TracerPath(value = "/trace/getSet", order = 1) 63 | public DataRet getSet() throws IOException { 64 | DataRet ret = null; 65 | try { 66 | String cname = null; 67 | String mname = null; 68 | String type = null; 69 | if (intercepter != null) { 70 | cname = intercepter.getC(); 71 | mname = intercepter.getM(); 72 | type = intercepter.getClass().getSimpleName(); 73 | } 74 | long size = nodePool.getSize(); 75 | int mode = nodePool.getMode(); 76 | MetaVO metaVO = new MetaVO(cname, mname); 77 | ret = new DataRet(true, 0, "get ok"); 78 | ret.setData(new SetVO(metaVO, type, size, mode)); 79 | } catch (Exception e) { 80 | ret = new DataRet(false, -1, "getSet failed" + e.getMessage()); 81 | } 82 | return ret; 83 | } 84 | 85 | @TracerPath(value = "/trace/list", order = 1) 86 | public DataRet> list() throws IOException { 87 | DataRet> ret = null; 88 | try { 89 | List list = new ArrayList(); 90 | Map nodes = nodePool.getNodes(); 91 | SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.S"); 92 | Calendar cal = Calendar.getInstance(); 93 | for (Map.Entry entry : nodes.entrySet()) { 94 | long seed = entry.getKey(); 95 | RootNode root = entry.getValue(); 96 | String[] names = BaseNode.getName(root.getNode().getId()); 97 | cal.setTimeInMillis(root.getStart()); 98 | String time = sdf.format(cal.getTime()); 99 | long rt = root.getNode().getT(); 100 | list.add(new RecordVO(seed, root.getType(), new MetaVO(names[0], names[1]), time, rt)); 101 | } 102 | ret = new DataRet>(true, 0, "get ok"); 103 | ret.setData(list); 104 | } catch (Exception e) { 105 | ret = new DataRet(false, -1, "list failed" + e.getMessage()); 106 | } 107 | return ret; 108 | } 109 | 110 | @TracerPath(value = "/trace/get.json", order = 1) 111 | public DataRet getjson(@TraceParam("id") String id) throws IOException, InterruptedException { 112 | DataRet ret = null; 113 | try { 114 | Long seed = Long.valueOf(id); 115 | RootNode node = nodePool.getNode(seed); 116 | Map metas = node.getNode().getMetas(); 117 | ret = new DataRet(true, 0, "getjson id:[" + id + "]success"); 118 | ret.setData(new TraceVO(node.getType(), node.getNode(), metas)); 119 | } catch (Exception e) { 120 | ret = new DataRet(false, -1, "getjson id:[" + id + "]failed" + e.getMessage()); 121 | } 122 | return ret; 123 | } 124 | 125 | @TracerPath(value = "/trace/get.xml", order = 1) 126 | public void get(@TraceParam("id") String id, PrintWriter writer) throws IOException, InterruptedException { 127 | Long seed = Long.valueOf(id); 128 | if (intercepter != null) { 129 | RootNode node = nodePool.getNode(seed); 130 | if (node != null) { 131 | writer.write(""); 132 | node.getNode().writeFile(writer); 133 | } else { 134 | writer.write("no result no record"); 135 | } 136 | } else { 137 | writer.write("no result intercepter is null"); 138 | } 139 | } 140 | 141 | @TracerPath(value = "/trace", order = 1) 142 | @TraceView 143 | public String trace(ModelMap map, @TraceParam("id") String id) throws IOException { 144 | map.put("id", id); 145 | return "trace"; 146 | } 147 | 148 | } 149 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/jetty/io/AgentResVmLoader.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.jetty.io; 2 | 3 | import org.apache.commons.collections.ExtendedProperties; 4 | import org.apache.velocity.exception.ResourceNotFoundException; 5 | import org.apache.velocity.runtime.resource.Resource; 6 | import org.apache.velocity.runtime.resource.loader.ResourceLoader; 7 | 8 | import java.io.InputStream; 9 | 10 | /** 11 | * @author nkhanlang@163.com 12 | */ 13 | public class AgentResVmLoader extends ResourceLoader { 14 | 15 | private static AgentResVmLoader instance; 16 | private ClassLoader loader; 17 | 18 | public AgentResVmLoader() { 19 | loader = getClass().getClassLoader(); 20 | instance = this; 21 | } 22 | 23 | public static AgentResVmLoader getInstance(){ 24 | if(instance == null){ 25 | instance = new AgentResVmLoader(); 26 | } 27 | return instance; 28 | } 29 | @Override 30 | public void init(ExtendedProperties extendedProperties) { 31 | } 32 | 33 | @Override 34 | public InputStream getResourceStream(String s) throws ResourceNotFoundException { 35 | return loader.getResourceAsStream(s); 36 | } 37 | 38 | @Override 39 | public boolean isSourceModified(Resource resource) { 40 | return false; 41 | } 42 | 43 | @Override 44 | public long getLastModified(Resource resource) { 45 | return 0; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/jetty/io/StaticResResolver.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.jetty.io; 2 | 3 | import org.apache.velocity.Template; 4 | import org.apache.velocity.VelocityContext; 5 | import org.apache.velocity.app.VelocityEngine; 6 | 7 | import java.io.BufferedReader; 8 | import java.io.InputStream; 9 | import java.io.InputStreamReader; 10 | import java.io.Writer; 11 | import java.util.Map; 12 | import java.util.Properties; 13 | 14 | /** 15 | * @author nkhanlang@163.com 16 | */ 17 | public class StaticResResolver { 18 | 19 | public static void resolve(String file, Writer writer) { 20 | try { 21 | InputStream in = AgentResVmLoader.getInstance().getResourceStream(file); 22 | BufferedReader br = new BufferedReader(new InputStreamReader(in)); 23 | String temp = null; 24 | while ((temp = br.readLine()) != null) { 25 | writer.write(temp); 26 | writer.write("\r\n"); 27 | } 28 | } catch (Exception e) { 29 | //e.printStackTrace(); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/jetty/io/VmViewResolver.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.jetty.io; 2 | 3 | import org.apache.velocity.Template; 4 | import org.apache.velocity.VelocityContext; 5 | import org.apache.velocity.app.VelocityEngine; 6 | 7 | import java.io.Writer; 8 | import java.util.Map; 9 | import java.util.Properties; 10 | 11 | /** 12 | * @author nkhanlang@163.com 13 | */ 14 | public class VmViewResolver { 15 | private static VelocityEngine ve = new VelocityEngine(); 16 | static{ 17 | try { 18 | Properties p = new Properties(); 19 | p.setProperty("resource.loader", "agent"); 20 | p.setProperty("agent.resource.loader.class", AgentResVmLoader.class.getName()); 21 | p.setProperty("input.encoding", "UTF-8"); 22 | ve.init(p); 23 | } catch (Exception e) { 24 | e.printStackTrace(); 25 | } 26 | } 27 | 28 | public static void resolve(String template, Map params, Writer writer) { 29 | try { 30 | Template t = ve.getTemplate(template); 31 | t.merge(new VelocityContext(params), writer); 32 | } catch (Exception e) { 33 | //e.printStackTrace(); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/jetty/support/HandlerConfig.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.jetty.support; 2 | 3 | import com.ali.trace.spy.jetty.handler.ClassHandler; 4 | import com.ali.trace.spy.jetty.handler.ITraceHttpHandler; 5 | import com.ali.trace.spy.jetty.handler.ITraceHttpHandler.TracerPath; 6 | import com.ali.trace.spy.jetty.handler.IndexHandler; 7 | import com.ali.trace.spy.jetty.handler.StaticHandler; 8 | import com.ali.trace.spy.jetty.handler.ThreadHandler; 9 | import com.ali.trace.spy.jetty.handler.TraceHandler; 10 | 11 | import java.lang.reflect.Method; 12 | import java.util.Set; 13 | import java.util.TreeSet; 14 | 15 | /** 16 | * @author nkhanlang@163.com 17 | * @date 2019-08-21 23:26 18 | */ 19 | public class HandlerConfig { 20 | 21 | private static final HandlerConfig INSTANCE = new HandlerConfig(); 22 | private Module defaultModule; 23 | private Set modules = new TreeSet(); 24 | 25 | private HandlerConfig() { 26 | ITraceHttpHandler handler = new IndexHandler(); 27 | addHandler(handler); 28 | setDefaultModule(handler); 29 | addHandler(new ThreadHandler()); 30 | addHandler(new ClassHandler()); 31 | addHandler(new TraceHandler()); 32 | addHandler(new StaticHandler()); 33 | } 34 | 35 | public static HandlerConfig getInstance() { 36 | return INSTANCE; 37 | } 38 | 39 | public Set getModules() { 40 | return modules; 41 | } 42 | 43 | public Module getDefaultModule() { 44 | return defaultModule; 45 | } 46 | 47 | public void addHandler(ITraceHttpHandler handler) { 48 | Class> clasz = handler.getClass(); 49 | Method[] methods = clasz.getDeclaredMethods(); 50 | for (Method method : methods) { 51 | TracerPath tracerPath = method.getAnnotation(TracerPath.class); 52 | if (tracerPath != null) { 53 | String path = tracerPath.value(); 54 | if (path != null && (path = path.trim()).length() > 0) { 55 | if (path.charAt(0) != '/') { 56 | path = "/" + path; 57 | } 58 | Module module = new Module(path, method, handler, tracerPath.order()); 59 | modules.add(module); 60 | } 61 | } 62 | } 63 | } 64 | 65 | public void setDefaultModule(ITraceHttpHandler handler) { 66 | for (Module module : modules) { 67 | if (module.getHttpHandler() == handler) { 68 | this.defaultModule = module; 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/jetty/support/Module.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.jetty.support; 2 | 3 | 4 | import com.ali.trace.spy.jetty.handler.ITraceHttpHandler; 5 | 6 | import java.lang.reflect.Method; 7 | import java.util.regex.Pattern; 8 | /** 9 | * @author nkhanlang@163.com 10 | * @date 2019-08-21 23:30 11 | */ 12 | public class Module implements Comparable { 13 | private Pattern pattern; 14 | private Method method; 15 | private ITraceHttpHandler httpHandler; 16 | private int order; 17 | private String path; 18 | 19 | public Module(String path, Method method, ITraceHttpHandler httpHandler, int order) { 20 | this.path = path; 21 | this.method = method; 22 | this.httpHandler = httpHandler; 23 | this.order = order; 24 | this.pattern = Pattern.compile("^" + path + "$"); 25 | } 26 | public ITraceHttpHandler getHttpHandler(){ 27 | return httpHandler; 28 | } 29 | public Method getMethod(){ 30 | return method; 31 | } 32 | 33 | public boolean match(String path) { 34 | return pattern.matcher(path).find(); 35 | } 36 | 37 | public int compareTo(Module o) { 38 | int compare = order - o.order; 39 | if (compare == 0) { 40 | compare = o.path.length() - path.length(); 41 | } 42 | if (compare == 0) { 43 | compare = o.path.compareTo(path); 44 | } 45 | return compare; 46 | } 47 | } -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/jetty/vo/DataRet.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.jetty.vo; 2 | 3 | import com.ali.trace.spy.util.BaseNode; 4 | import com.ali.trace.spy.util.CommonNode; 5 | import com.ali.trace.spy.util.CompressNode; 6 | import com.google.gson.Gson; 7 | import com.google.gson.GsonBuilder; 8 | import com.google.gson.JsonElement; 9 | import com.google.gson.JsonNull; 10 | import com.google.gson.JsonSerializationContext; 11 | import com.google.gson.JsonSerializer; 12 | 13 | import java.lang.reflect.Type; 14 | import java.util.ArrayList; 15 | import java.util.Collection; 16 | import java.util.LinkedHashMap; 17 | import java.util.List; 18 | 19 | /** 20 | * @author nkhanlang@163.com 21 | * @date 2019-08-21 00:52 22 | */ 23 | 24 | public class DataRet { 25 | private final boolean status; 26 | private final int code; 27 | private final String msg; 28 | private T data; 29 | 30 | public DataRet(boolean status, int code, String msg) { 31 | this.status = status; 32 | this.code = code; 33 | this.msg = msg; 34 | } 35 | 36 | public void setData(T data) { 37 | this.data = data; 38 | } 39 | 40 | public T getData() { 41 | return data; 42 | } 43 | 44 | public boolean isStatus() { 45 | return status; 46 | } 47 | 48 | public int getCode() { 49 | return code; 50 | } 51 | 52 | public String getMsg() { 53 | return msg; 54 | } 55 | 56 | @Override 57 | public String toString() { 58 | try{ 59 | return gson.toJson(this); 60 | }catch(Throwable t){ 61 | t.printStackTrace(); 62 | } 63 | return "{'error':'e'}"; 64 | } 65 | 66 | private static Gson gson = new GsonBuilder()/*.registerTypeAdapter(BaseNode.class, new JsonSerializer() { 67 | public JsonElement serialize(BaseNode src, Type typeOfSrc, JsonSerializationContext context) { 68 | return gson.toJsonTree(src.build(new StringBuilder())); 69 | } 70 | })*/.registerTypeAdapter(LinkedHashMap.class, new JsonSerializer() { 71 | public JsonElement serialize(LinkedHashMap src, Type typeOfSrc, JsonSerializationContext context) { 72 | return !src.isEmpty() ? gson.toJsonTree(src.values()): JsonNull.INSTANCE; 73 | } 74 | }).registerTypeAdapter(List.class, new JsonSerializer() { 75 | public JsonElement serialize(List src, Type typeOfSrc, JsonSerializationContext context) { 76 | return !src.isEmpty() ? gson.toJsonTree(src): JsonNull.INSTANCE; 77 | } 78 | }).create(); 79 | 80 | 81 | public static void main(String[] args) { 82 | 83 | DataRet ret = new DataRet(true, 0, ""); 84 | long id = BaseNode.getId("com.test.Service", "main"); 85 | 86 | 87 | CompressNode node = new CompressNode(id); 88 | node.addSon(BaseNode.getId("com.test.Service", "main1")); 89 | node.addSon(BaseNode.getId("com.test.Service1", "main")); 90 | node.addSon(BaseNode.getId("com.test.Service1", "main")) 91 | .addSon(BaseNode.getId("com.test.Service1", "main")); 92 | 93 | ret.setData(node); 94 | System.out.println(gson.toJson(ret)); 95 | 96 | CommonNode node1 = new CommonNode(id); 97 | node1.addSon(BaseNode.getId("com.test.Service", "main1")); 98 | node1.addSon(BaseNode.getId("com.test.Service1", "main")); 99 | node1.addSon(BaseNode.getId("com.test.Service1", "main")) 100 | .addSon(BaseNode.getId("com.test.Service1", "main")); 101 | 102 | 103 | ret.setData(node1); 104 | System.out.println(gson.toJson(ret)); 105 | 106 | System.out.println(ret); 107 | 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/jetty/vo/MetaVO.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.jetty.vo; 2 | 3 | /** 4 | * @author nkhanlang@163.com 5 | * @date 2019-08-21 00:51 6 | */ 7 | public class MetaVO { 8 | private String cname; 9 | private String mname; 10 | public MetaVO(String cname, String mname){ 11 | this.cname = cname; 12 | this.mname = mname; 13 | } 14 | public String getCname() { 15 | return cname; 16 | } 17 | 18 | public void setCname(String cname) { 19 | this.cname = cname; 20 | } 21 | 22 | public String getMname() { 23 | return mname; 24 | } 25 | 26 | public void setMname(String mname) { 27 | this.mname = mname; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/jetty/vo/RecordVO.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.jetty.vo; 2 | 3 | /** 4 | * @author nkhanlang@163.com 5 | * @date 2019-08-21 00:51 6 | */ 7 | public class RecordVO { 8 | private MetaVO metaVO; 9 | private String type; 10 | private Long seed; 11 | private String time; 12 | private long rt; 13 | 14 | public RecordVO(long seed, String type, MetaVO metaVO, String time, long rt){ 15 | this.seed = seed; 16 | this.type = type; 17 | this.metaVO = metaVO; 18 | this.time = time; 19 | this.rt = rt; 20 | } 21 | 22 | public MetaVO getMetaVO() { 23 | return metaVO; 24 | } 25 | 26 | public void setMetaVO(MetaVO metaVO) { 27 | this.metaVO = metaVO; 28 | } 29 | 30 | public Long getSeed() { 31 | return seed; 32 | } 33 | 34 | public void setSeed(Long seed) { 35 | this.seed = seed; 36 | } 37 | 38 | public String getType() { 39 | return type; 40 | } 41 | 42 | public void setType(String type) { 43 | this.type = type; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/jetty/vo/SetVO.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.jetty.vo; 2 | 3 | /** 4 | * @author nkhanlang@163.com 5 | * @date 2019-08-21 00:51 6 | */ 7 | public class SetVO { 8 | private MetaVO metaVO; 9 | private String type; 10 | private long size; 11 | private int mode; 12 | 13 | public SetVO(MetaVO metaVO, String type, long size, int mode){ 14 | this.metaVO = metaVO; 15 | this.type = type; 16 | this.size = size; 17 | this.mode = mode; 18 | } 19 | public MetaVO getMetaVO() { 20 | return metaVO; 21 | } 22 | 23 | public void setMetaVO(MetaVO metaVO) { 24 | this.metaVO = metaVO; 25 | } 26 | 27 | public long getSize() { 28 | return size; 29 | } 30 | 31 | public void setSize(long size) { 32 | this.size = size; 33 | } 34 | 35 | public String getType() { 36 | return type; 37 | } 38 | 39 | public void setType(String type) { 40 | this.type = type; 41 | } 42 | 43 | public int getMode() { 44 | return mode; 45 | } 46 | 47 | public void setMode(int mode) { 48 | this.mode = mode; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/jetty/vo/TraceVO.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.jetty.vo; 2 | 3 | import com.ali.trace.spy.util.BaseNode; 4 | import com.ali.trace.spy.util.CompressNode; 5 | 6 | import java.util.Map; 7 | 8 | /** 9 | * @author nkhanlang@163.com 10 | * @date 2019-08-21 00:51 11 | */ 12 | public class TraceVO { 13 | private String type; 14 | private BaseNode node; 15 | private Map metas; 16 | 17 | public TraceVO(String type, BaseNode node, Map metas){ 18 | this.type = type; 19 | this.node = node; 20 | this.metas = metas; 21 | } 22 | 23 | public String getType() { 24 | return type; 25 | } 26 | 27 | public void setType(String type) { 28 | this.type = type; 29 | } 30 | 31 | public BaseNode getNode() { 32 | return node; 33 | } 34 | 35 | public void setNode(BaseNode node) { 36 | this.node = node; 37 | } 38 | 39 | public Map getMetas() { 40 | return metas; 41 | } 42 | 43 | public void setMetas(Map metas) { 44 | this.metas = metas; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/util/BaseNode.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.util; 2 | 3 | import com.google.gson.*; 4 | 5 | import java.io.BufferedWriter; 6 | import java.io.FileWriter; 7 | import java.io.IOException; 8 | import java.io.Writer; 9 | import java.lang.reflect.Type; 10 | import java.util.*; 11 | import java.util.concurrent.atomic.AtomicLong; 12 | 13 | /** 14 | * @author nkhanlang@163.com 15 | */ 16 | public abstract class BaseNode> { 17 | 18 | protected long i; 19 | protected long t; 20 | private static AtomicLong seq = new AtomicLong(0); 21 | private static Map> idMap = new HashMap>(); 22 | private static Map nameMap = new HashMap(); 23 | 24 | public static long getId(String service, String method) { 25 | Map cMap = null; 26 | if ((cMap = idMap.get(service)) == null) { 27 | synchronized (idMap) { 28 | if ((cMap = idMap.get(service)) == null) { 29 | idMap.put(service, cMap = new HashMap()); 30 | } 31 | } 32 | } 33 | 34 | Long id = null; 35 | if ((id = cMap.get(method)) == null) { 36 | synchronized (cMap) { 37 | if ((id = cMap.get(method)) == null) { 38 | cMap.put(method, id = seq.incrementAndGet()); 39 | nameMap.put(id, new String[]{service, method}); 40 | } 41 | } 42 | } 43 | return id; 44 | } 45 | 46 | public static String[] getName(long id) { 47 | return nameMap.get(id); 48 | } 49 | 50 | 51 | protected BaseNode(long id) { 52 | this.i = id; 53 | } 54 | 55 | public boolean equal(String service, String method) { 56 | return getId(service, method) == i; 57 | } 58 | 59 | public String[] getName() { 60 | return nameMap.get(i); 61 | } 62 | 63 | public long getId() { 64 | return i; 65 | } 66 | 67 | public long getT() { 68 | return t; 69 | } 70 | 71 | public void addRt(long rt) { 72 | this.t += rt; 73 | } 74 | 75 | public Map getMetas() { 76 | Map metas = new HashMap(); 77 | Stack> stack = new Stack>(); 78 | stack.push(this); 79 | while (!stack.isEmpty()) { 80 | BaseNode node = stack.pop(); 81 | if (!metas.containsKey(node.i)) { 82 | metas.put(node.i, getName(node.i)); 83 | } 84 | Collection ss = node.getSons(); 85 | if (!ss.isEmpty()) { 86 | stack.addAll(ss); 87 | } 88 | } 89 | return metas; 90 | } 91 | 92 | public void writeFile(Writer writer) throws IOException { 93 | writeFile(writer, Integer.MAX_VALUE); 94 | } 95 | 96 | public abstract void writeFile(Writer writer, int depth) throws IOException; 97 | 98 | public abstract BaseNode addSon(long id) ; 99 | 100 | public abstract Collection getSons(); 101 | 102 | protected StringBuilder buildInner(StringBuilder builder) { 103 | return builder; 104 | } 105 | 106 | public final StringBuilder build(StringBuilder builder) { 107 | //{"s":[{"i":763,"t":0}],"i":763,"t":0} 108 | builder.append("{'i':"); 109 | builder.append(i); 110 | builder.append(",'t':"); 111 | builder.append(t); 112 | buildInner(builder); 113 | Collection s = getSons(); 114 | if(!s.isEmpty()){ 115 | builder.append(",'s':["); 116 | String split = ""; 117 | for(T node : s){ 118 | builder.append(split); 119 | node.build(builder); 120 | split = ","; 121 | } 122 | builder.append("]"); 123 | } 124 | builder.append("}"); 125 | return builder; 126 | } 127 | 128 | } 129 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/util/ClassDigest.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.util; 2 | //package com.ali.trace.util; 3 | // 4 | //import java.io.IOException; 5 | //import java.util.Arrays; 6 | //import java.util.Collections; 7 | //import java.util.HashSet; 8 | //import java.util.Set; 9 | // 10 | //import com.ali.asm.AnnotationVisitor; 11 | //import com.ali.asm.ClassReader; 12 | //import com.ali.asm.ClassVisitor; 13 | //import com.ali.asm.ClassWriter; 14 | //import com.ali.asm.FieldVisitor; 15 | //import com.ali.asm.Handle; 16 | //import com.ali.asm.Label; 17 | //import com.ali.asm.MethodVisitor; 18 | //import com.ali.asm.Opcodes; 19 | // 20 | //public class ClassDigest extends ClassVisitor { 21 | // 22 | // private Set imports = new HashSet(); 23 | // 24 | // public String[] getImports() { 25 | // return imports.toArray(new String[0]); 26 | // } 27 | // 28 | // public ClassDigest(ClassVisitor cv) { 29 | // super(Opcodes.ASM5, cv); 30 | // } 31 | // 32 | // @Override 33 | // public FieldVisitor visitField(int access, String name, String desc, String signature, 34 | // Object value) { 35 | // imports.add(desc); 36 | // return super.visitField(access, name, desc, signature, value); 37 | // } 38 | // 39 | // public AnnotationVisitor visitAnnotation(String desc, boolean visible) { 40 | // imports.add(desc); 41 | // return super.visitAnnotation(desc, visible); 42 | // } 43 | // 44 | // @Override 45 | // public void visit(int version, int access, String name, String signature, String superName, 46 | // String[] interfaces) { 47 | // imports.add(superName); 48 | // Collections.addAll(imports, interfaces); 49 | // super.visit(version, access, name, signature, superName, interfaces); 50 | // } 51 | // 52 | // @Override 53 | // public MethodVisitor visitMethod(int access, String name, String desc, String signature, 54 | // String[] exceptions) { 55 | // 56 | // imports.add(desc); 57 | // return new ModifyMethod(super.visitMethod(access, name, desc, signature, exceptions), 58 | // access, name, desc); 59 | // } 60 | // 61 | // class ModifyMethod extends MethodVisitor implements Opcodes { 62 | // public ModifyMethod(MethodVisitor mv, int access, String mName, String vName) { 63 | // super(Opcodes.ASM5, mv); 64 | // } 65 | // 66 | // @Override 67 | // public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, 68 | // Object... bsmArgs) { 69 | // System.out.println("visitInvokeDynamicInsn :[" + name + "," + desc + "," + bsm + "]"); 70 | // super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs); 71 | // } 72 | // 73 | // @Override 74 | // public void visitMethodInsn(int opcode, String owner, String name, String desc) { 75 | // System.out.println("visitMethodInsn :[" + name + "," + desc + "]"); 76 | // super.visitMethodInsn(opcode, owner, name, desc); 77 | // } 78 | // 79 | // @Override 80 | // public AnnotationVisitor visitAnnotation(String desc, boolean visible) { 81 | // System.out.println("visitMethodInsn :[" + desc + "]"); 82 | // return super.visitAnnotation(desc, visible); 83 | // } 84 | // 85 | // public void visitLocalVariable(String name, String desc, String signature, Label start, 86 | // Label end, int index) { 87 | // System.out.println("visitLocalVariable :[" + desc + "," + signature + "]"); 88 | // if (mv != null) { 89 | // mv.visitLocalVariable(name, desc, signature, start, end, index); 90 | // } 91 | // } 92 | // 93 | // public void visitFieldInsn(int opcode, String owner, String name, String desc) { 94 | // System.out.println("visitFieldInsn :[" + name + "," + desc + "]"); 95 | // if (mv != null) { 96 | // mv.visitFieldInsn(opcode, owner, name, desc); 97 | // } 98 | // } 99 | // } 100 | // 101 | // private static void digest(Class> clasz) throws IOException { 102 | // ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS); 103 | // ClassDigest digest = new ClassDigest(classWriter); 104 | // new ClassReader(clasz.getName()).accept(digest, ClassReader.EXPAND_FRAMES); 105 | // System.out.println(Arrays.toString(digest.getImports())); 106 | // 107 | // } 108 | // 109 | // public static void main(String[] args) throws IOException{ 110 | // digest(ClassUtils.class); 111 | // } 112 | // 113 | //} 114 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/util/ClassUtils.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.util; 2 | 3 | import java.lang.reflect.Method; 4 | 5 | /** 6 | * @author nkhanlang@163.com 7 | */ 8 | public class ClassUtils { 9 | 10 | public static void main(String[] args) throws Exception { 11 | 12 | Method[] methods = ClassUtils.class.getMethods(); 13 | //ASMifier.main(new String[]{"/u01/eclipse/wdk-backend/wdkloc/loc-order/target/classes/com/taobao/loc/order/serivce/InvoiceServiceImpl.class"}); 14 | //ASMifier.main(new String[]{TestAsmImport.class.getName()}); 15 | 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/util/CommonNode.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.util; 2 | 3 | import com.google.gson.*; 4 | 5 | import java.io.BufferedWriter; 6 | import java.io.FileWriter; 7 | import java.io.IOException; 8 | import java.io.Writer; 9 | import java.lang.reflect.Type; 10 | import java.util.*; 11 | 12 | /** 13 | * @author nkhanlang@163.com 14 | */ 15 | public class CommonNode extends BaseNode { 16 | 17 | private List s = new ArrayList(); 18 | 19 | public CommonNode(long id) { 20 | super(id); 21 | } 22 | 23 | public CommonNode addSon(long id) { 24 | CommonNode son = new CommonNode(id); 25 | s.add(son); 26 | return son; 27 | } 28 | 29 | public Collection getSons() { 30 | return new ArrayList(s); 31 | } 32 | 33 | 34 | public void writeFile(Writer writer, int depth) throws IOException { 35 | if (depth > 0) { 36 | String[] items =getName(i); 37 | if (items == null) { 38 | throw new RuntimeException("name not exists ![" + i + "]"); 39 | } 40 | writer.write("<"); 41 | writer.write(items[1]); 42 | writer.write(" rt='" + t + "'"); 43 | writer.write(">\r\n"); 44 | for (CommonNode son : s) { 45 | son.writeFile(writer, depth--); 46 | } 47 | writer.write(""); 48 | writer.write(items[1]); 49 | writer.write(">\r\n"); 50 | } 51 | } 52 | 53 | public static void main(String[] args) throws IOException { 54 | long id = CommonNode.getId("com.test.Service", "main"); 55 | CommonNode node = new CommonNode(id); 56 | node.addSon(CommonNode.getId("com.test.Service", "main1")); 57 | node.addSon(CommonNode.getId("com.test.Service1", "main")); 58 | node.addSon(CommonNode.getId("com.test.Service1", "main")) 59 | .addSon(CommonNode.getId("com.test.Service1", "main")) 60 | .addSon(CommonNode.getId("com.test.Service", "main")); 61 | BufferedWriter writer = null; 62 | try { 63 | writer = new BufferedWriter(new FileWriter("/tmp/test.xml")); 64 | node.writeFile(writer); 65 | } finally { 66 | if (writer != null) { 67 | writer.close(); 68 | } 69 | } 70 | System.out.println(new Gson().toJson(node)); 71 | 72 | Map map = new LinkedHashMap(); 73 | map.put(1, 12); 74 | map.put(3, 12); 75 | map.put(4, 12); 76 | map.put(6, 12); 77 | map.put(2, 12); 78 | System.out.println("map : " + new Gson().toJson(map)); 79 | 80 | System.out.println(new GsonBuilder().registerTypeAdapter(LinkedHashMap.class, new JsonSerializer() { 81 | public JsonElement serialize(LinkedHashMap src, Type typeOfSrc, JsonSerializationContext context) { 82 | if(!src.isEmpty()){ 83 | return new GsonBuilder().registerTypeAdapter(LinkedHashMap.class, this).create().toJsonTree(src.values()); 84 | }else{ 85 | return null; 86 | } 87 | } 88 | }).create().toJson(node)); 89 | 90 | System.out.println(node.build(new StringBuilder())); 91 | 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/util/CompressNode.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.util; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.GsonBuilder; 5 | import com.google.gson.JsonElement; 6 | import com.google.gson.JsonSerializationContext; 7 | import com.google.gson.JsonSerializer; 8 | 9 | import java.io.BufferedWriter; 10 | import java.io.FileWriter; 11 | import java.io.IOException; 12 | import java.io.Writer; 13 | import java.lang.reflect.Type; 14 | import java.util.*; 15 | 16 | /** 17 | * @author nkhanlang@163.com 18 | */ 19 | public class CompressNode extends BaseNode { 20 | 21 | private long c; 22 | private LinkedHashMap s = new LinkedHashMap(); 23 | 24 | public CompressNode(long id) { 25 | super(id); 26 | } 27 | 28 | public CompressNode addSon(long id) { 29 | CompressNode son = s.get(id); 30 | if (son == null) { 31 | s.put(id, son = new CompressNode(id)); 32 | } 33 | son.c ++; 34 | return son; 35 | } 36 | 37 | public Collection getSons() { 38 | return new ArrayList(s.values()); 39 | } 40 | @Override 41 | protected StringBuilder buildInner(StringBuilder builder) { 42 | builder.append(",'c':"); 43 | builder.append(c); 44 | return builder; 45 | } 46 | public void writeFile(Writer writer, int depth) throws IOException { 47 | if (depth > 0) { 48 | String[] items = getName(i); 49 | if (items == null) { 50 | throw new RuntimeException("name not exists ![" + i + "]"); 51 | } 52 | writer.write("<"); 53 | writer.write(items[1]); 54 | writer.write(" cnt='" + c + "'"); 55 | writer.write(" rt='" + t + "'"); 56 | writer.write(" c='" + items[0] + "'"); 57 | writer.write(">\r\n"); 58 | for (CompressNode son : s.values()) { 59 | son.writeFile(writer, depth--); 60 | } 61 | writer.write(""); 62 | writer.write(items[1]); 63 | writer.write(">\r\n"); 64 | } 65 | } 66 | 67 | public static void main(String[] args) throws IOException { 68 | long id = CompressNode.getId("com.test.Service", "main"); 69 | CompressNode node = new CompressNode(id); 70 | node.addSon(CompressNode.getId("com.test.Service", "main1")); 71 | node.addSon(CompressNode.getId("com.test.Service1", "main")); 72 | node.addSon(CompressNode.getId("com.test.Service1", "main")) 73 | .addSon(CompressNode.getId("com.test.Service1", "main")) 74 | .addSon(CompressNode.getId("com.test.Service", "main")); 75 | BufferedWriter writer = null; 76 | try { 77 | writer = new BufferedWriter(new FileWriter("/tmp/test.xml")); 78 | node.writeFile(writer); 79 | } finally { 80 | if (writer != null) { 81 | writer.close(); 82 | } 83 | } 84 | System.out.println(new Gson().toJson(node)); 85 | 86 | Map map = new LinkedHashMap(); 87 | map.put(1, 12); 88 | map.put(3, 12); 89 | map.put(4, 12); 90 | map.put(6, 12); 91 | map.put(2, 12); 92 | System.out.println("map : " + new Gson().toJson(map)); 93 | 94 | System.out.println(new GsonBuilder().registerTypeAdapter(LinkedHashMap.class, new JsonSerializer() { 95 | public JsonElement serialize(LinkedHashMap src, Type typeOfSrc, JsonSerializationContext context) { 96 | if(!src.isEmpty()){ 97 | return new GsonBuilder().registerTypeAdapter(LinkedHashMap.class, this).create().toJsonTree(src.values()); 98 | }else{ 99 | return null; 100 | } 101 | } 102 | }).create().toJson(node)); 103 | 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/util/CrunchifyReverseLineReader.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.util; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import java.io.RandomAccessFile; 6 | import java.io.UnsupportedEncodingException; 7 | import java.nio.ByteBuffer; 8 | import java.nio.channels.FileChannel; 9 | 10 | /** 11 | * @author nkhanlang@163.com 12 | */ 13 | class CrunchifyReverseLineReader { 14 | private static final int BUFFER_SIZE = 8192; 15 | private final FileChannel channel; 16 | private final String encoding; 17 | private long filePos; 18 | private ByteBuffer buf; 19 | private int bufPos; 20 | private ByteArrayOutputStream baos = new ByteArrayOutputStream(); 21 | private RandomAccessFile raf; 22 | 23 | public CrunchifyReverseLineReader(String fileName) throws IOException { 24 | this(fileName, null); 25 | } 26 | 27 | public CrunchifyReverseLineReader(String fileName, String encoding) throws IOException { 28 | raf = new RandomAccessFile(fileName, "r"); 29 | channel = raf.getChannel(); 30 | filePos = raf.length(); 31 | this.encoding = encoding; 32 | } 33 | 34 | public void close() throws IOException { 35 | raf.close(); 36 | } 37 | 38 | public String readLine() throws IOException { 39 | byte c; 40 | while (true) { 41 | if (bufPos < 0) { 42 | if (filePos == 0) { 43 | if (baos == null) { 44 | return null; 45 | } 46 | String line = bufToString(); 47 | baos = null; 48 | return line; 49 | } 50 | 51 | long start = Math.max(filePos - BUFFER_SIZE, 0); 52 | long end = filePos; 53 | long len = end - start; 54 | 55 | buf = channel.map(FileChannel.MapMode.READ_ONLY, start, len); 56 | bufPos = (int)len; 57 | filePos = start; 58 | c = buf.get(--bufPos); 59 | Byte preC = null; 60 | if (c == '\r' || c == '\n') { 61 | while (bufPos > 0 && (c == '\r' || c == '\n')) { 62 | bufPos--; 63 | preC = c; 64 | c = buf.get(bufPos); 65 | } 66 | } 67 | if (!(c == '\r' || c == '\n')) { 68 | bufPos++; 69 | if (preC != null && (preC == '\r' || preC == '\n')) { 70 | bufPos++; 71 | } 72 | } 73 | } 74 | while (bufPos-- > 0) { 75 | c = buf.get(bufPos); 76 | if (c == '\r' || c == '\n') { 77 | while (bufPos > 0 && (c == '\r' || c == '\n')) { 78 | c = buf.get(--bufPos); 79 | } 80 | if (!(c == '\r' || c == '\n')) 81 | bufPos++; 82 | return bufToString(); 83 | } 84 | baos.write(c); 85 | } 86 | } 87 | } 88 | 89 | private String bufToString() throws UnsupportedEncodingException { 90 | if (baos.size() == 0) { 91 | return ""; 92 | } 93 | byte[] bytes = baos.toByteArray(); 94 | for (int i = 0; i < bytes.length / 2; i++) { 95 | byte t = bytes[i]; 96 | bytes[i] = bytes[bytes.length - i - 1]; 97 | bytes[bytes.length - i - 1] = t; 98 | } 99 | 100 | baos.reset(); 101 | if (encoding != null) { 102 | return new String(bytes, encoding); 103 | } else { 104 | return new String(bytes); 105 | } 106 | } 107 | } -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/util/NameUtils.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.util; 2 | 3 | import java.net.URL; 4 | import java.security.MessageDigest; 5 | import java.security.NoSuchAlgorithmException; 6 | 7 | /** 8 | * @author nkhanlang@163.com 9 | */ 10 | public class NameUtils { 11 | 12 | /** 13 | * delete chars like <, >, $ 14 | * 15 | * @param str 16 | * @return 17 | */ 18 | public static final String replace(String str) { 19 | return str == null ? "" : str.replaceAll("<|>|\\$", ""); 20 | } 21 | 22 | /** 23 | * with file system path and class name get the byte-code file 24 | * 25 | * @param path 26 | * @param name 27 | * @return 28 | */ 29 | public static final String getClassFile(String path, String name) { 30 | return String.valueOf(new StringBuffer(path).append('/').append(getClassPath(name)).append(".class")); 31 | } 32 | 33 | /** 34 | * with class name get the path com.ali.bat convert to com/ali/bat 35 | * 36 | * @param name 37 | * @return 38 | */ 39 | public static final String getClassPath(String name) { 40 | return name.replace('.', '/'); 41 | } 42 | 43 | /** 44 | * com/ali/bat to com.ali.bat 45 | */ 46 | public static final String getClassName(String path) { 47 | return replace(path.replace('/', '.')); 48 | } 49 | 50 | 51 | private static final String MD5_ALGORITHM_NAME = "MD5"; 52 | private static final char[] CHARS_HEX = "0123456789abcdef".toCharArray(); 53 | 54 | public static String getHexMd5(String content) { 55 | try { 56 | byte[] bytes = MessageDigest.getInstance(MD5_ALGORITHM_NAME).digest(content.getBytes()); 57 | char chars[] = new char[32]; 58 | for (int i = 0; i < chars.length; i = i + 2) { 59 | byte b = bytes[i / 2]; 60 | chars[i] = CHARS_HEX[(b >>> 0x4) & 0xf]; 61 | chars[i + 1] = CHARS_HEX[b & 0xf]; 62 | } 63 | return new String(chars); 64 | } catch (NoSuchAlgorithmException ex) { 65 | throw new IllegalStateException("Could not find MessageDigest with algorithm MD5 ", ex); 66 | } 67 | } 68 | 69 | 70 | 71 | public static final String getMethodName(String methodName) { 72 | return replace(methodName.replaceAll("<\\|>", "")); 73 | } 74 | 75 | public static String getJarPath() { 76 | URL url = NameUtils.class.getProtectionDomain().getCodeSource().getLocation(); 77 | return url.getPath(); 78 | } 79 | 80 | public static void main(String[] args) { 81 | System.out.println(getJarPath()); 82 | System.out.println(getMethodName("")); 83 | 84 | System.out.println("".replaceAll("<|>", "")); 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/util/RootNode.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.util; 2 | 3 | /** 4 | * @auther nkhanlang@163.com 5 | * @date 2019-08-29 20:22 6 | */ 7 | public class RootNode { 8 | private final long id; 9 | private final String type; 10 | private final BaseNode node; 11 | private final long start; 12 | 13 | 14 | public RootNode(long id, BaseNode node, String type) { 15 | this.id = id; 16 | this.node = node; 17 | this.type = type; 18 | this.start = System.currentTimeMillis(); 19 | } 20 | 21 | public long getId() { 22 | return id; 23 | } 24 | 25 | public String getType() { 26 | return type; 27 | } 28 | 29 | public BaseNode getNode() { 30 | return node; 31 | } 32 | 33 | public long getStart() { 34 | return start; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/util/SelectiveFilter.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.util; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.BufferedWriter; 5 | import java.io.File; 6 | import java.io.FileReader; 7 | import java.io.FileWriter; 8 | import java.util.ArrayList; 9 | import java.util.HashMap; 10 | import java.util.List; 11 | import java.util.Map; 12 | import java.util.Scanner; 13 | import java.util.Stack; 14 | 15 | /** 16 | * @author nkhanlang@163.com 17 | */ 18 | public class SelectiveFilter { 19 | 20 | public static void main(String[] args) throws Exception { 21 | 22 | Scanner scanner = new Scanner(System.in); 23 | if (args.length > 0) { 24 | String[] filters = args[0].split(","); 25 | Map> map = new HashMap>(); 26 | for (String filter : filters) { 27 | int idx = filter.lastIndexOf("."); 28 | String mName = filter.substring(idx + 1); 29 | String cName = filter.substring(0, idx); 30 | List list = map.get(mName); 31 | if (list == null) { 32 | map.put(mName, list = new ArrayList()); 33 | } 34 | list.add(cName); 35 | } 36 | 37 | while (true) { 38 | System.out.print("please input xml fileName or directory and press q to exit: "); 39 | String input = scanner.nextLine(); 40 | if ("q".equalsIgnoreCase(input)) { 41 | break; 42 | } 43 | File file = new File(input); 44 | if (file.exists()) { 45 | if (file.isDirectory()) { 46 | for (File subFile : file.listFiles()) { 47 | String xml = subFile.getAbsolutePath(); 48 | String newXml = xml + "_filter.xml"; 49 | System.out.println("generate file : " + newXml); 50 | filter(xml, newXml, map); 51 | } 52 | } else { 53 | String xml = file.getAbsolutePath(); 54 | String newXml = xml + "_filter.xml"; 55 | System.out.println("generate file : " + newXml); 56 | filter(xml, newXml, map); 57 | } 58 | } else { 59 | System.err.println("input [" + input + "] not exists !!!"); 60 | } 61 | } 62 | } 63 | } 64 | 65 | private static void filter(String fileName, String newFileName, Map> filters) 66 | throws Exception { 67 | BufferedReader reader = null; 68 | BufferedWriter writer = null; 69 | try { 70 | reader = new BufferedReader(new FileReader(fileName)); 71 | writer = new BufferedWriter(new FileWriter(newFileName)); 72 | String line = null; 73 | Stack printBeans = new Stack(); 74 | while ((line = reader.readLine()) != null) { 75 | char c = line.charAt(1); 76 | if (c != '/') { 77 | int blankIdx = line.indexOf(' '); 78 | int quateIdx = line.indexOf("c='"); 79 | if (blankIdx > 0 && quateIdx > 0) { 80 | String mName = line.substring(1, blankIdx); 81 | String cName = line.substring(quateIdx + 3, line.length() - 2); 82 | LineBean bean = new LineBean(line, cName + "." + mName); 83 | List cNameList = filters.get(mName); 84 | if (cNameList != null) { 85 | boolean match = false; 86 | for(String cNameItem : cNameList){ 87 | if(cNameItem.equals("*") || cNameItem.equalsIgnoreCase(cName)){ 88 | match = true; 89 | break; 90 | }else{ 91 | int splitIdx = cNameItem.indexOf("#"); 92 | if(!printBeans.isEmpty() && splitIdx > 0){ 93 | String superRegex = cNameItem.substring(0, splitIdx); 94 | if(superRegex.equalsIgnoreCase(printBeans.peek().name)){ 95 | match = true; 96 | break; 97 | } 98 | } 99 | } 100 | } 101 | printBeans.push(bean); 102 | if (match) { 103 | for (LineBean preBean : printBeans) { 104 | if (!preBean.print) { 105 | writer.write(preBean.start); 106 | writer.write("\r\n"); 107 | preBean.print = true; 108 | } 109 | } 110 | } 111 | }else{ 112 | printBeans.push(bean); 113 | } 114 | } 115 | 116 | } else { 117 | if (printBeans.pop().print) { 118 | writer.write(line); 119 | writer.write("\r\n"); 120 | } 121 | } 122 | } 123 | } finally { 124 | if (reader != null) { 125 | reader.close(); 126 | } 127 | if (writer != null) { 128 | writer.close(); 129 | } 130 | } 131 | } 132 | 133 | private static class LineBean { 134 | String start; 135 | String name; 136 | boolean print; 137 | 138 | LineBean(String start, String name) { 139 | this.start = start; 140 | this.name = name; 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/util/TestAsmImport.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.util; 2 | 3 | import javax.annotation.Resource; 4 | 5 | @Resource 6 | public class TestAsmImport { 7 | 8 | private Long name;// = new String("abc"); 9 | 10 | public int getAge(String type) { 11 | new StringBuilder("abc").append(12); 12 | System.out.println(name); 13 | return new Integer(0); 14 | } 15 | 16 | public int getAge(String type, StringBuilder sb) { 17 | new StringBuilder("abc").append(12); 18 | //System.out.println(name); 19 | return new Integer(0); 20 | } 21 | 22 | 23 | 24 | } 25 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/util/XmlUtils.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.util; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.BufferedWriter; 5 | import java.io.File; 6 | import java.io.FileReader; 7 | import java.io.FileWriter; 8 | import java.io.IOException; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | import java.util.Scanner; 12 | import java.util.Stack; 13 | 14 | import com.ali.trace.spy.helper.IFileNameGenerator; 15 | import com.ali.trace.spy.intercepter.CompressIntercepter; 16 | 17 | /** 18 | * used to format XML generated by tracer 19 | * @author nkhanlang@163.com 20 | */ 21 | public class XmlUtils { 22 | 23 | public static void main(String[] args) throws Exception { 24 | Scanner scanner = new Scanner(System.in); 25 | String type = "common"; 26 | if (args.length > 0) { 27 | type = args[0]; 28 | } 29 | 30 | while (true) { 31 | System.out.print("please input xml fileName or directory and press q to exit: "); 32 | String input = scanner.nextLine(); 33 | if ("q".equalsIgnoreCase(input)) { 34 | break; 35 | } 36 | File file = new File(input); 37 | if (file.exists()) { 38 | List fileNames = new ArrayList(); 39 | if (file.isDirectory()) { 40 | for (File subFile : file.listFiles()) { 41 | fileNames.add(subFile.getAbsolutePath()); 42 | } 43 | } else { 44 | fileNames.add(file.getAbsolutePath()); 45 | } 46 | formatXml(fileNames, type); 47 | } else { 48 | System.err.println("input [" + input + "] not exists !!!"); 49 | } 50 | } 51 | } 52 | 53 | public static void formatXml(List fileNames, String type) throws Exception { 54 | if (type.equalsIgnoreCase("compress")) { 55 | for (String fileName : fileNames) { 56 | String newFile = fileName + ".xml"; 57 | String tmpFile = fileName + ".tmp"; 58 | System.out.println("generate file : " + newFile); 59 | fillXml(fileName, tmpFile); 60 | compressXml(tmpFile, newFile); 61 | restoreXml(newFile, tmpFile); 62 | reverseFile(tmpFile, newFile); 63 | } 64 | } else if (type.equalsIgnoreCase("stastic")) { 65 | stasticXml(fileNames, "/tmp/statstic.xml"); 66 | } else { 67 | for (String fileName : fileNames) { 68 | String newFile = fileName + ".xml"; 69 | String tmpFile = fileName + ".tmp"; 70 | System.out.println("generate file : " + newFile); 71 | fillXml(fileName, newFile); 72 | restoreXml(newFile, tmpFile); 73 | reverseFile(tmpFile, newFile); 74 | } 75 | } 76 | 77 | } 78 | 79 | public static void stasticXml(List fileNames, String newFile) throws Exception{ 80 | 81 | CompressNode root = new CompressNode(CompressNode.getId("test", "root")); 82 | Stack stack = new Stack(); 83 | stack.push(root); 84 | for(String fileName : fileNames){ 85 | BufferedReader reader = null; 86 | try { 87 | reader = new BufferedReader(new FileReader(fileName)); 88 | Stack cs = new Stack(); 89 | String line = null; 90 | while ((line = reader.readLine()) != null) { 91 | if (line.trim().length() > 0) { 92 | String[] items = line.split("<|'| "); 93 | String m = items[1]; 94 | if (m.charAt(0) == '/') { 95 | CompressNode son = stack.pop(); 96 | Long rt = Long.valueOf(items[3]); 97 | son.addRt(rt); 98 | } else { 99 | String c = items[items.length - 2]; 100 | cs.push(c); 101 | stack.push(stack.peek().addSon(BaseNode.getId(c, m))); 102 | } 103 | } 104 | } 105 | } finally { 106 | if (reader != null) { 107 | reader.close(); 108 | } 109 | } 110 | } 111 | BufferedWriter writer = null; 112 | try { 113 | writer = new BufferedWriter(new FileWriter(newFile)); 114 | root.writeFile(writer); 115 | } finally { 116 | if (writer != null) { 117 | writer.close(); 118 | } 119 | } 120 | } 121 | 122 | public static void compressXml(String fileName, final String newFile) throws Exception { 123 | CompressIntercepter intecepter = new CompressIntercepter(newFile); 124 | intecepter.setNameGenerator(new IFileNameGenerator() { 125 | @Override 126 | public String getName() { 127 | return newFile; 128 | } 129 | }); 130 | Stack cs = new Stack(); 131 | BufferedReader br = null; 132 | try { 133 | br = new BufferedReader(new FileReader(fileName)); 134 | String line = null; 135 | intecepter.start("c", "m"); 136 | while ((line = br.readLine()) != null) { 137 | if (line.trim().length() > 0) { 138 | String[] items = line.split("<|'| "); 139 | String m = items[1]; 140 | if (m.charAt(0) == '/') { 141 | String c = cs.pop(); 142 | intecepter.end(c, m); 143 | } else { 144 | String c = items[items.length - 2]; 145 | cs.push(c); 146 | intecepter.start(c, m); 147 | } 148 | } 149 | } 150 | intecepter.end("c", "m"); 151 | } finally { 152 | if (br != null) { 153 | br.close(); 154 | } 155 | } 156 | } 157 | 158 | public static void fillXml(String fileName, String fillFile) throws IOException { 159 | BufferedReader reader = null; 160 | BufferedWriter writer = null; 161 | try { 162 | reader = new BufferedReader(new FileReader(fileName)); 163 | writer = new BufferedWriter(new FileWriter(fillFile)); 164 | String line = null; 165 | Stack params = new Stack(); 166 | while ((line = reader.readLine()) != null) { 167 | char c = line.charAt(1); 168 | if (c != '/') { 169 | int idx = line.indexOf(' '); 170 | if (idx > 0) { 171 | String param = line.substring(1, idx); 172 | params.push(param); 173 | } 174 | } else if (!params.isEmpty()) { 175 | params.pop(); 176 | } 177 | writer.write(line); 178 | writer.write("\r\n"); 179 | } 180 | if (!params.isEmpty()) { 181 | while (!params.isEmpty()) { 182 | String param = params.pop(); 183 | writer.write(""); 184 | writer.write(param); 185 | writer.write(" _f='false'>\r\n"); 186 | } 187 | } 188 | } finally { 189 | if (reader != null) { 190 | reader.close(); 191 | } 192 | if (writer != null) { 193 | writer.close(); 194 | } 195 | } 196 | } 197 | 198 | public static void restoreXml(String fileName, String reverseFile) throws IOException { 199 | CrunchifyReverseLineReader reader = null; 200 | BufferedWriter writer = null; 201 | try { 202 | reader = new CrunchifyReverseLineReader(fileName); 203 | writer = new BufferedWriter(new FileWriter(reverseFile)); 204 | String line = null; 205 | Stack params = new Stack(); 206 | while ((line = reader.readLine()) != null) { 207 | if (line.length() > 1) { 208 | char c = line.charAt(1); 209 | int idx = line.indexOf(' '); 210 | if (idx > 0) { 211 | String prefix = line.substring(0, idx); 212 | String param = line.substring(idx, line.length() - 1); 213 | writer.write(prefix); 214 | if (c == '/') { 215 | params.push(param); 216 | } else { 217 | writer.write(params.pop()); 218 | writer.write(param); 219 | } 220 | writer.write(">"); 221 | writer.write("\r\n"); 222 | } 223 | } 224 | } 225 | } finally { 226 | if (reader != null) { 227 | reader.close(); 228 | } 229 | if (writer != null) { 230 | writer.close(); 231 | } 232 | } 233 | } 234 | 235 | public static void reverseFile(String fileName, String reverseFile) throws IOException { 236 | CrunchifyReverseLineReader reader = null; 237 | BufferedWriter writer = null; 238 | try { 239 | reader = new CrunchifyReverseLineReader(fileName); 240 | writer = new BufferedWriter(new FileWriter(reverseFile)); 241 | String line = null; 242 | while ((line = reader.readLine()) != null) { 243 | if (line != null && !"".equals(line.trim())) { 244 | writer.write(line); 245 | writer.write("\r\n"); 246 | } 247 | } 248 | } finally { 249 | if (reader != null) { 250 | reader.close(); 251 | } 252 | if (writer != null) { 253 | writer.close(); 254 | } 255 | } 256 | } 257 | } 258 | -------------------------------------------------------------------------------- /tracer-spy/src/main/java/com/ali/trace/spy/xml/XmlNode.java: -------------------------------------------------------------------------------- 1 | package com.ali.trace.spy.xml; 2 | 3 | import java.io.IOException; 4 | import java.io.Writer; 5 | import java.util.Collection; 6 | 7 | /** 8 | * @author nkhanlang@163.com 9 | */ 10 | public abstract class XmlNode> { 11 | 12 | protected abstract Collection getChildren(); 13 | 14 | protected abstract String getStart(); 15 | 16 | protected abstract String getEnd(); 17 | 18 | public void write(Writer writer) { 19 | try { 20 | writer.write(getStart()); 21 | for (XmlNode child : getChildren()) { 22 | child.write(writer); 23 | } 24 | writer.write(getEnd()); 25 | } catch (IOException e) { 26 | e.printStackTrace(); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tracer-spy/src/main/resources/static/css/home.css: -------------------------------------------------------------------------------- 1 | .input-group-addon{ 2 | min-width:100px; 3 | text-align: left; 4 | } 5 | .sequence-op{ 6 | min-width:50px; 7 | } 8 | .list-demo{ 9 | display: none; 10 | } 11 | .spinner { 12 | width: 100px; 13 | } 14 | .spinner input { 15 | text-align: right; 16 | } 17 | .input-group-btn-vertical { 18 | position: relative; 19 | white-space: nowrap; 20 | width: 25px; 21 | vertical-align: middle; 22 | display: table-cell; 23 | } 24 | .input-group-btn-vertical > .btn { 25 | display: block; 26 | float: none; 27 | width: 100%; 28 | max-width: 100%; 29 | padding: 8px; 30 | margin-left: 0px; 31 | position: relative; 32 | border-radius: 0; 33 | } 34 | .input-group-btn-vertical > .btn:first-child { 35 | border-top-right-radius: 4px; 36 | } 37 | .input-group-btn-vertical > .btn:last-child { 38 | margin-top: -2px; 39 | border-bottom-right-radius: 4px; 40 | } 41 | .input-group-btn-vertical i{ 42 | position: absolute; 43 | top: 0; 44 | left: 4px; 45 | } 46 | svg tspan { cursor:pointer } 47 | ul.tree-list-group{ 48 | list-style:none; 49 | text-indent:-3px; 50 | padding:0px; 51 | padding-left:20px; 52 | margin:0px; 53 | } 54 | 55 | .big-content{ 56 | overflow: scroll; 57 | } -------------------------------------------------------------------------------- /tracer-spy/src/main/resources/static/js/home.js: -------------------------------------------------------------------------------- 1 | 2 | var data = null; 3 | $('#refresh').click(function(){ 4 | $.post("/trace/getSet", function(str){ 5 | var ret = JSON.parse(str); 6 | if(ret.status){ 7 | data = ret.data; 8 | if(data.mode > 0){ 9 | $('#form_set').hide(); 10 | }else { 11 | if (data.metaVO.hasOwnProperty('cname') && data.metaVO.hasOwnProperty('mname')) { 12 | $('label[name=cname]', $('#form_set')).html(data.metaVO.cname); 13 | $('label[name=mname]', $('#form_set')).html(data.metaVO.mname); 14 | $('label[name=type]', $('#form_set')).html(data.type); 15 | } 16 | $('label[name=size]', $('#form_set')).html(data.size); 17 | } 18 | } 19 | }); 20 | $.post("/trace/list", function(str){ 21 | var ret = JSON.parse(str); 22 | if(ret.status){ 23 | $('.list-show-item', $('#form_list')).remove(); 24 | for(var i in ret.data){ 25 | var item = ret.data[i]; 26 | var demo = $('.list-demo', $('#form_list')); 27 | var tr = demo.clone(); 28 | tr.removeClass('list-demo'); 29 | tr.addClass('list-show-item'); 30 | $('#form_href', tr).attr('href', '/trace?id=' + item.seed); 31 | $('[name=type]', tr).html(item.type); 32 | $('[name=time]', tr).html(item.time); 33 | $('[name=cname_mname]', tr).html(item.metaVO.cname + "." + item.metaVO.mname); 34 | $('[name=rt]', tr).html(item.rt); 35 | demo.after(tr); 36 | } 37 | } 38 | }); 39 | }); 40 | $('#refresh').click(); 41 | $('#set').click(function(){ 42 | if(data){ 43 | $('input[name=model_cname]').val(data.metaVO.cname); 44 | $('input[name=model_mname]').val(data.metaVO.mname); 45 | $('select[name=model_type]').val(data.type); 46 | $('input[name=model_size]').val(data.size); 47 | } 48 | }); 49 | 50 | $('#confirm').click(function(){ 51 | var cname = $('input[name=model_cname]').val(); 52 | var mname = $('input[name=model_mname]').val(); 53 | var type = $('input[name=model_type]').val(); 54 | var size = $('input[name=model_size]').val(); 55 | if(confirm("set class:[" + cname + "]method:[" + mname + "] type:[" + type + "] size:[" + size + "] ? ")){ 56 | $.post("/trace/set", {class:cname, method:mname, type:type, size:size}, function(str){ 57 | var ret = JSON.parse(str); 58 | if(ret.status){ 59 | alert("set sucess!"); 60 | location.reload(); 61 | }else{ 62 | alert("set failed :[" + ret.msg + "]"); 63 | } 64 | }); 65 | } 66 | }); 67 | 68 | -------------------------------------------------------------------------------- /tracer-spy/src/main/resources/static/js/sequence.js: -------------------------------------------------------------------------------- 1 | function TreeNode(name, arr, meta){ 2 | if(arr.length > 0){ 3 | meta.arr[name] = arr; 4 | } 5 | this.name = name; 6 | this.arr = arr; 7 | this.getSon = function(n){ 8 | n = n ? n : this; 9 | n.son = []; 10 | var m = {}; 11 | var idx = n.name.length+1; 12 | for(var i in n.arr){ 13 | var s = n.arr[i]; 14 | var idxx = s.indexOf('.', idx); 15 | var f = s.charAt(idx); 16 | if(f>='a' && f<='z' && idxx > 0){ 17 | var pname = s.substr(0, idxx); 18 | if(!m.hasOwnProperty(pname)){ 19 | m[pname] = []; 20 | } 21 | m[pname].push(s); 22 | }else { 23 | m[s] = [s]; 24 | } 25 | } 26 | for(var i in m){ 27 | var s = m[i]; 28 | if(s.length == 1){ 29 | n.son.push(new TreeNode(s[0], [], meta)); 30 | }else{ 31 | var ns = new TreeNode(i, s, meta); 32 | if(ns.hasOwnProperty('son') && $.isArray(ns.son) && ns.son.length == 1){ 33 | n.son.push(ns.son[0]); 34 | }else{ 35 | n.son.push(ns); 36 | } 37 | } 38 | } 39 | return n.son; 40 | } 41 | this.son = this.getSon(); 42 | this.getTree = function(n){ 43 | n = n ? n : this; 44 | var ul = null; 45 | for(var i in n.son){ 46 | var s = n.son[i]; 47 | if(s.hasOwnProperty('son') && s.son.length > 0){ 48 | if(!ul){ 49 | ul = $(""); 50 | ul.addClass("tree-list-group"); 51 | } 52 | var li = $(""); 53 | li.append("" + s.name); 54 | li.append(this.getTree(s)); 55 | li.addClass("tree-list-item"); 56 | ul.append(li); 57 | } 58 | } 59 | return ul; 60 | } 61 | } 62 | 63 | function Meta(type, node, metas){ 64 | this.type = type; 65 | this.node = node; 66 | this.metas = metas; 67 | this.arr = {}; 68 | this.getCmeta = function(){ 69 | var cmeta = {}; 70 | for(var id in this.metas){ 71 | var meta = this.metas[id]; 72 | if(!cmeta.hasOwnProperty(meta[0])){ 73 | cmeta[meta[0]] = []; 74 | } 75 | cmeta[meta[0]].push(parseInt(id)); 76 | } 77 | return cmeta; 78 | } 79 | this.cmeta = this.getCmeta(); 80 | this.getWithout = function(wnames){ 81 | var m = {}; 82 | for(var i in wnames){ 83 | if(this.arr.hasOwnProperty(wnames[i])){ 84 | var cnames = this.arr[wnames[i]]; 85 | for(var j in cnames){ 86 | var ids = this.cmeta[cnames[j]]; 87 | for(var i in ids){ 88 | m[ids[i]]=ids[i]; 89 | } 90 | } 91 | }else if(this.cmeta.hasOwnProperty(wnames[i])){ 92 | var ids = this.cmeta[wnames[i]]; 93 | for(var i in ids){ 94 | m[ids[i]]=ids[i]; 95 | } 96 | } 97 | } 98 | return m; 99 | } 100 | } 101 | 102 | function DynSeq(parent, node, meta){ 103 | this.parent = parent; 104 | this.node = node; 105 | this.meta = meta; 106 | this.set = {}; 107 | this.classes = {}; 108 | this.cnames = {}; 109 | this.getName = function(str){ 110 | var len = str.length; 111 | var idx = 0; 112 | while(idx++='A' && c<='Z'){ 115 | break; 116 | } 117 | } 118 | if(idx >= len){ 119 | idx = str.lastIndexOf('.'); 120 | } 121 | return str.substr(idx); 122 | //return str.substr(str.lastIndexOf('.')+1); 123 | }; 124 | this.setActor = function(cname, name){ 125 | if(!this.set.hasOwnProperty(name)){ 126 | console.log(cname , name); 127 | this.set[name] = cname; 128 | this.classes[name] = cname; 129 | return "Participant " + name + " [cname='" + cname + "',fillcolor='#fed', type='actor']"; 130 | } 131 | }; 132 | this.addCname = function(cname){ 133 | this.cnames[cname] = cname; 134 | } 135 | this.delCname = function(cname){ 136 | delete this.cnames[cname] 137 | } 138 | this.getWithout = function(){ 139 | return this.meta.getWithout(Object.keys(this.cnames)); 140 | } 141 | this.filter = function(without, depth, n){ 142 | if(depth > 0 && n.hasOwnProperty('s')){ 143 | var m = {}; 144 | var ss = []; 145 | for(var i in n.s){ 146 | var s = n.s[i]; 147 | if(without.hasOwnProperty(s.i)){ 148 | s = this.filter(without, depth, s); 149 | if(s.hasOwnProperty('s')){ 150 | for(var j in s.s){ 151 | var g = s.s[j]; 152 | if(m.hasOwnProperty(g.i) && this.meta.type == "CompressTreeIntercepter"){ 153 | m[g.i].t += g.t; 154 | m[g.i].c += g.c; 155 | }else{ 156 | m[g.i] = g; 157 | ss.push(g); 158 | } 159 | } 160 | } 161 | }else{ 162 | if(m.hasOwnProperty(s.i) && this.meta.type == "CompressTreeIntercepter"){ 163 | m[s.i].t += s.t; 164 | m[s.i].c += s.c; 165 | }else{ 166 | m[s.i] = s; 167 | ss.push(s); 168 | } 169 | } 170 | } 171 | for(var i in ss){ 172 | this.filter(without, depth-1, ss[i]); 173 | } 174 | n.s = ss; 175 | } 176 | return n; 177 | } 178 | this.getNode = function(path, n){ 179 | n = n ? n : node; 180 | var idx = 0; 181 | while((idx = path.indexOf('/')) == 0){ 182 | path = path.substr(idx+1); 183 | } 184 | var p = path; 185 | if(idx != -1){ 186 | p = path.substr(0, idx); 187 | } 188 | if(n.hasOwnProperty('s') && n.s.length > p){ 189 | return idx != -1 ? this.getNode(path.substr(idx+1), n.s[p]) : n.s[p]; 190 | } 191 | return n; 192 | }; 193 | this.getSon = function(path){ 194 | var son = new DynSeq(this, this.getNode(path, this.filter(this.getWithout(), path.split('/').length-1, this.node)), this.meta); 195 | son.cnames = $.extend(true, {}, this.cnames); 196 | return son; 197 | } 198 | this.showLines = function(depth){ 199 | return this.getLines(this.filter(this.getWithout(), depth, $.extend(true, {}, this.node)), "", depth, 0); 200 | }; 201 | this.getLines = function(n, path, depth, count, invoke){ 202 | if(depth > 0 && n.hasOwnProperty('s')){ 203 | var lines = []; 204 | var src = this.meta.metas[n.i]; 205 | if(count == 0){ 206 | this.set = {}; 207 | var cnt = (n.c && n.c > 1) ? ":cnt:" + n.c : ""; 208 | var rt = n.t > 1 ? ":rt:" + n.t : ""; 209 | lines.push("Title:" + src[0] + "." + src[1] + "\\n" + cnt + rt + " [fillcolor='#fef']"); 210 | } 211 | var srcName = this.getName(src[0]); 212 | var srcActor = this.setActor(src[0], srcName); 213 | if(srcActor){ 214 | lines.push(srcActor); 215 | } 216 | for(var i in n.s){ 217 | var son = n.s[i]; 218 | var dst = this.meta.metas[son.i]; 219 | var dstName = this.getName(dst[0]); 220 | var dstActor = this.setActor(dst[0], dstName); 221 | if(dstActor){ 222 | lines.push(dstActor); 223 | } 224 | var nextInvoke = invoke ? (invoke + "." + (parseInt(i)+1)) : ("" + (parseInt(i)+1)); 225 | var subLines = this.getLines(son, path + "/" + i, depth-1, count+1, nextInvoke); 226 | 227 | var id = "id='" + son.i + "'"; 228 | var pa = "path='" + path + "/" + i + "'"; 229 | 230 | var cnt = son.c > 1 ? ":cnt:" + son.c : ""; 231 | var rt = son.t > 1 ? ":rt:" + son.t : ""; 232 | 233 | if(subLines){ 234 | lines.push(srcName + "->" + dstName + ":" + nextInvoke + "." + dst[1] + cnt + " [" + id + "," + pa + ", fontcolor='#0af', type='in']"); 235 | lines = lines.concat(subLines); 236 | lines.push(dstName + "-->" + srcName + ":" + nextInvoke + "." + dst[1] + rt + " [fontcolor='#0af', type='out']"); 237 | }else if(son.hasOwnProperty('s')){ 238 | lines.push(srcName + "->" + dstName + ":" + nextInvoke + "." + dst[1] + cnt + rt + " [" + id + "," + pa + ",fontcolor='#a0f', type='in']"); 239 | }else{ 240 | lines.push(srcName + "->" + dstName + ":" + nextInvoke + "." + dst[1] + cnt + rt + " [" + id + "," + pa + ", type='all']"); 241 | } 242 | } 243 | return lines; 244 | } 245 | } 246 | this.getList = function(){ 247 | ul = $(""); 248 | ul.addClass("tree-list-group"); 249 | for(var i in this.classes){ 250 | var s = this.classes[i]; 251 | var li = $(""); 252 | if(this.cnames.hasOwnProperty(s)){ 253 | li.append("" + i); 254 | }else if(this.set.hasOwnProperty(i)){ 255 | li.append("" + i); 256 | } 257 | li.addClass("tree-list-item"); 258 | ul.append(li); 259 | } 260 | return ul; 261 | } 262 | } 263 | 264 | function Chart(type, node, metas){ 265 | this.meta = new Meta(type, node, metas); 266 | this.seq = new DynSeq(null, node, this.meta); 267 | this.getSetDepth = function(cnt){ 268 | var val = parseInt($('.sequence-op[name=depth-value]').val()); 269 | if(isNaN(val)){ 270 | val = 2; 271 | } 272 | if(cnt){ 273 | val += cnt; 274 | val = val<1 ? 1 : val; 275 | $('.sequence-op[name=depth-value]').val(val); 276 | this.showChart(); 277 | } 278 | return val; 279 | } 280 | this.showChart = function(){ 281 | var lines = this.seq.showLines(this.getSetDepth()); 282 | if(lines){ 283 | $('#sequence').empty(); 284 | Diagram.parse(lines.join('\r\n')).drawSVG("sequence", {theme: 'simple'}); 285 | this.setClassModel(); 286 | } 287 | } 288 | this.back = function(cnt){ 289 | cnt = cnt ? cnt : 10000; 290 | var parent = null; 291 | while(cnt-->0 && (parent=this.seq.parent)){ 292 | this.seq = parent; 293 | } 294 | this.showChart(); 295 | } 296 | this.changeCname = function(cname, type){ 297 | if(type == 1){ 298 | this.seq.addCname(cname); 299 | }else{ 300 | this.seq.delCname(cname); 301 | } 302 | this.showChart(); 303 | } 304 | this.enterSon = function(path){ 305 | this.seq = this.seq.getSon(path); 306 | this.showChart(); 307 | } 308 | this.setPackageModel = function(){ 309 | $('#packages').append(new TreeNode("", Object.keys(this.meta.cmeta), this.meta).getTree()); 310 | } 311 | this.setClassModel = function(){ 312 | $('#classes').empty(); 313 | $('#classes').append(this.seq.getList()); 314 | } 315 | this.setPackageModel(); 316 | this.showChart(); 317 | } 318 | 319 | var chart = null; 320 | var init = function(id){ 321 | $.post("/trace/get.json", {id:id}, function(str){ 322 | var ret = JSON.parse(str); 323 | if(ret.status){ 324 | chart = new Chart(ret.data.type, ret.data.node, ret.data.metas) 325 | } 326 | }); 327 | } 328 | 329 | $("[data-toggle='tooltip']").tooltip(); 330 | $('.sequence-op').click(function(){ 331 | var name = $(this).attr("name"); 332 | if(name == "depth-add"){ 333 | chart.getSetDepth(1); 334 | }else if(name == "depth-sub"){ 335 | chart.getSetDepth(-1); 336 | }else if(name == "fast-back"){ 337 | chart.back(); 338 | }else if(name == "step-back"){ 339 | chart.back(1); 340 | } 341 | }); 342 | 343 | $('body').on('click', 'svg text', function(){ 344 | var dataStr = $(this).prop('data'); 345 | if(dataStr){ 346 | var data = JSON.parse(dataStr); 347 | if(data.hasOwnProperty('type')){ 348 | if(data.type == 'in'){ 349 | chart.enterSon(data.path); 350 | }else if(data.type == 'actor'){ 351 | if(confirm("delete[" + data.cname + "]?")){ 352 | chart.changeCname(data.cname, 1); 353 | } 354 | } 355 | } 356 | } 357 | }); 358 | $('body').on('change', '[type=checkbox]', function(){ 359 | var cname = $(this).val(); 360 | if($(this).is(":checked")){ 361 | $(this).next().hide(); 362 | chart.changeCname(cname, 1); 363 | }else{ 364 | $(this).next().show(); 365 | chart.changeCname(cname, -1); 366 | } 367 | }); 368 | -------------------------------------------------------------------------------- /tracer-spy/src/main/resources/static/vm/index.vm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | java-tracer 16 | 17 | 18 | 19 | home 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | system info 32 | 33 | 34 | 35 | 36 | 37 | forward 38 | 39 | 40 | classLoader & class 41 | 42 | 43 | 44 | 45 | 46 | 47 | forward 48 | 49 | 50 | thread 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | trace 59 | 60 | 61 | 62 | 63 | 64 | cname: 65 | 66 | 67 | 68 | 69 | 70 | mname: 71 | 72 | 73 | 74 | 75 | 76 | type: 77 | 78 | 79 | 80 | 81 | 82 | size: 83 | 84 | 85 | 86 | 87 | 88 | set 89 | refresh 90 | 91 | 92 | 93 | 94 | result list 95 | 96 | 97 | name 98 | start 99 | service 100 | rt 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | × 120 | set method to trace 121 | 122 | 123 | 124 | 125 | cname 126 | 127 | 128 | 129 | 130 | mname 131 | 132 | 133 | 134 | 135 | type 136 | 137 | CompressTreeIntercepter 138 | CommonTreeIntercepter 139 | 140 | 141 | 142 | 143 | size 144 | 145 | 146 | 147 | 148 | 149 | 152 | 153 | 154 | 155 | 156 | 157 |