|
|
|
@ -14,30 +14,35 @@ import com.taobao.arthas.core.shell.system.ProcessAware;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
|
* TODO line 的记录 listener方式? 还是有string为key,不过 classname|method|desc|num 这样子? 判断是否已插入了,可以在两行中间查询,有没有 SpyAPI 的invoke?
|
|
|
|
|
* TODO line 的记录 listener方式? 还是有string为key,不过 classname|method|desc|num 这样子?
|
|
|
|
|
* 判断是否已插入了,可以在两行中间查询,有没有 SpyAPI 的invoke?
|
|
|
|
|
*
|
|
|
|
|
* TODO trace的怎么搞? trace 只记录一次就可以了 classname|method|desc|trace ? 怎么避免 trace 到 SPY的invoke ?直接忽略?
|
|
|
|
|
* TODO trace的怎么搞? trace 只记录一次就可以了 classname|method|desc|trace ? 怎么避免 trace 到
|
|
|
|
|
* SPY的invoke ?直接忽略?
|
|
|
|
|
*
|
|
|
|
|
* TODO trace命令可以动态的增加 新的函数进去不?只要关联上同一个 Listener应该是可以的。
|
|
|
|
|
*
|
|
|
|
|
* TODO 在SPY里放很多的 Object数组,然后动态的设置进去? 比如有新的 Listener来的时候。 这样子连查表都不用了。 甚至可以动态生成 存放这些 Listener数组的类?
|
|
|
|
|
* 这样子的话,只要有 Binding那里,查询到一个具体分配好的类, 这样子就可以了? 甚至每个ClassLoader里都动态生成这样子的 存放类,那么这样子不可以避免查 ClassLoader了么?
|
|
|
|
|
* TODO 在SPY里放很多的 Object数组,然后动态的设置进去? 比如有新的 Listener来的时候。 这样子连查表都不用了。 甚至可以动态生成
|
|
|
|
|
* 存放这些 Listener数组的类? 这样子的话,只要有 Binding那里,查询到一个具体分配好的类, 这样子就可以了?
|
|
|
|
|
* 甚至每个ClassLoader里都动态生成这样子的 存放类,那么这样子不可以避免查 ClassLoader了么?
|
|
|
|
|
*
|
|
|
|
|
* 动态为每一个增强类,生成一个新的类,新的类里,有各种的 ID 数组,保存每一个类的每一种 trace 点的信息??
|
|
|
|
|
*
|
|
|
|
|
* 多个 watch命令 对同一个类,现在的逻辑是,每个watch都有一个自己的 TransForm,但不会重复增强,因为做了判断。 watch命令停止时,也没有去掉增强的代码。
|
|
|
|
|
* 只有reset时 才会去掉。
|
|
|
|
|
* 多个 watch命令 对同一个类,现在的逻辑是,每个watch都有一个自己的 TransForm,但不会重复增强,因为做了判断。
|
|
|
|
|
* watch命令停止时,也没有去掉增强的代码。 只有reset时 才会去掉。
|
|
|
|
|
*
|
|
|
|
|
* 其实用户想查看局部变量,并不是想查看哪一行! 而是想看某个函数里子调用时的 局部变量的值! 所以实际上是想要一个新的命令,比如 watchinmethod ,
|
|
|
|
|
* 可以 在某个子调用里,
|
|
|
|
|
* 其实用户想查看局部变量,并不是想查看哪一行! 而是想看某个函数里子调用时的 局部变量的值! 所以实际上是想要一个新的命令,比如 watchinmethod
|
|
|
|
|
* , 可以 在某个子调用里,
|
|
|
|
|
*
|
|
|
|
|
* TODO 现在的trace 可以输出行号,可能不是很精确,但是可以对应上的。 这个在新的方式里怎么支持? 增加一个 linenumber binding? 从mehtodNode,向上查找到最近的行号?
|
|
|
|
|
* TODO 现在的trace 可以输出行号,可能不是很精确,但是可以对应上的。 这个在新的方式里怎么支持? 增加一个 linenumber binding?
|
|
|
|
|
* 从mehtodNode,向上查找到最近的行号?
|
|
|
|
|
*
|
|
|
|
|
* TODO 防止重复增强,最重要的应该还是动态增加 annotation,这个才是真正可以做到某一行,某一个子 invoke 都能识别出来的! 无论是 transform多少次!
|
|
|
|
|
* 字节码怎么动态加 annotation ? annotation里签名用 url ?的key/value方式表达! 这样子可以有效还原信息
|
|
|
|
|
* TODO 防止重复增强,最重要的应该还是动态增加 annotation,这个才是真正可以做到某一行,某一个子 invoke 都能识别出来的! 无论是
|
|
|
|
|
* transform多少次! 字节码怎么动态加 annotation ? annotation里签名用 url ?的key/value方式表达!
|
|
|
|
|
* 这样子可以有效还原信息
|
|
|
|
|
*
|
|
|
|
|
* TODO 是否考虑一个 trace /watch命令之后,得到一个具体的 Listener ID, 允许在另外的窗口里,再次 trace/watch时指定这个ID,就会查找到,并处理。
|
|
|
|
|
* 这样子的话,真正达到了动态灵活的,一层一层增加的trace !
|
|
|
|
|
* TODO 是否考虑一个 trace /watch命令之后,得到一个具体的 Listener ID, 允许在另外的窗口里,再次
|
|
|
|
|
* trace/watch时指定这个ID,就会查找到,并处理。 这样子的话,真正达到了动态灵活的,一层一层增加的trace !
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* @author hengyunabc 2020-04-24
|
|
|
|
@ -46,6 +51,7 @@ import com.taobao.arthas.core.shell.system.ProcessAware;
|
|
|
|
|
public class AdviceListenerManager {
|
|
|
|
|
|
|
|
|
|
private static Timer timer = ArthasBootstrap.getInstance().getTimer();
|
|
|
|
|
private static final FakeBootstrapClassLoader FAKEBOOTSTRAPCLASSLOADER = new FakeBootstrapClassLoader();
|
|
|
|
|
|
|
|
|
|
static {
|
|
|
|
|
timer.scheduleAtFixedRate(new TimerTask() {
|
|
|
|
@ -106,7 +112,7 @@ public class AdviceListenerManager {
|
|
|
|
|
listeners = new ArrayList<AdviceListener>();
|
|
|
|
|
map.put(key, listeners);
|
|
|
|
|
}
|
|
|
|
|
if(!listeners.contains(listener)) {
|
|
|
|
|
if (!listeners.contains(listener)) {
|
|
|
|
|
listeners.add(listener);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -121,7 +127,6 @@ public class AdviceListenerManager {
|
|
|
|
|
return listeners;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void registerTraceAdviceListener(String className, String owner, String methodName, String methodDesc,
|
|
|
|
|
AdviceListener listener) {
|
|
|
|
|
|
|
|
|
@ -133,12 +138,13 @@ public class AdviceListenerManager {
|
|
|
|
|
listeners = new ArrayList<AdviceListener>();
|
|
|
|
|
map.put(key, listeners);
|
|
|
|
|
}
|
|
|
|
|
if(!listeners.contains(listener)) {
|
|
|
|
|
if (!listeners.contains(listener)) {
|
|
|
|
|
listeners.add(listener);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public List<AdviceListener> queryTraceAdviceListeners(String className, String owner, String methodName, String methodDesc) {
|
|
|
|
|
public List<AdviceListener> queryTraceAdviceListeners(String className, String owner, String methodName,
|
|
|
|
|
String methodDesc) {
|
|
|
|
|
className = className.replace('/', '.');
|
|
|
|
|
String key = keyForTrace(className, owner, methodName, methodDesc);
|
|
|
|
|
|
|
|
|
@ -150,6 +156,7 @@ public class AdviceListenerManager {
|
|
|
|
|
|
|
|
|
|
public static void registerAdviceListener(ClassLoader classLoader, String className, String methodName,
|
|
|
|
|
String methodDesc, AdviceListener listener) {
|
|
|
|
|
classLoader = wrap(classLoader);
|
|
|
|
|
className = className.replace('/', '.');
|
|
|
|
|
|
|
|
|
|
ClassLoaderAdviceListenerManager manager = adviceListenerMap.get(classLoader);
|
|
|
|
@ -167,6 +174,7 @@ public class AdviceListenerManager {
|
|
|
|
|
|
|
|
|
|
public static List<AdviceListener> queryAdviceListeners(ClassLoader classLoader, String className,
|
|
|
|
|
String methodName, String methodDesc) {
|
|
|
|
|
classLoader = wrap(classLoader);
|
|
|
|
|
className = className.replace('/', '.');
|
|
|
|
|
ClassLoaderAdviceListenerManager manager = adviceListenerMap.get(classLoader);
|
|
|
|
|
|
|
|
|
@ -177,8 +185,9 @@ public class AdviceListenerManager {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void registerTraceAdviceListener(ClassLoader classLoader, String className, String owner, String methodName,
|
|
|
|
|
String methodDesc, AdviceListener listener) {
|
|
|
|
|
public static void registerTraceAdviceListener(ClassLoader classLoader, String className, String owner,
|
|
|
|
|
String methodName, String methodDesc, AdviceListener listener) {
|
|
|
|
|
classLoader = wrap(classLoader);
|
|
|
|
|
className = className.replace('/', '.');
|
|
|
|
|
|
|
|
|
|
ClassLoaderAdviceListenerManager manager = adviceListenerMap.get(classLoader);
|
|
|
|
@ -189,8 +198,10 @@ public class AdviceListenerManager {
|
|
|
|
|
}
|
|
|
|
|
manager.registerTraceAdviceListener(className, owner, methodName, methodDesc, listener);
|
|
|
|
|
}
|
|
|
|
|
public static List<AdviceListener> queryTraceAdviceListeners(ClassLoader classLoader, String className, String owner,
|
|
|
|
|
String methodName, String methodDesc) {
|
|
|
|
|
|
|
|
|
|
public static List<AdviceListener> queryTraceAdviceListeners(ClassLoader classLoader, String className,
|
|
|
|
|
String owner, String methodName, String methodDesc) {
|
|
|
|
|
classLoader = wrap(classLoader);
|
|
|
|
|
className = className.replace('/', '.');
|
|
|
|
|
ClassLoaderAdviceListenerManager manager = adviceListenerMap.get(classLoader);
|
|
|
|
|
|
|
|
|
@ -200,4 +211,15 @@ public class AdviceListenerManager {
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static ClassLoader wrap(ClassLoader classLoader) {
|
|
|
|
|
if (classLoader != null) {
|
|
|
|
|
return classLoader;
|
|
|
|
|
}
|
|
|
|
|
return FAKEBOOTSTRAPCLASSLOADER;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static class FakeBootstrapClassLoader extends ClassLoader {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|