Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

添加line命令,用来观测方法内的局部变量,可以通过行号或者LineCode来指定位置 #2852

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,28 @@ ts=2018-09-18 10:26:28;result=@ArrayList[
]
```

#### line

* https://arthas.aliyun.com/doc/en/line

Observe the local variables before the method `demo.MathGame#run` executes up to line 25.

```bash
$ line demo.MathGame run 25 -x 2
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 17 ms, listenerId: 2
method=demo.MathGame.run line=25
ts=2024-06-21 09:57:34.452; result=@HashMap[
@String[primeFactors]:@ArrayList[
@Integer[2],
@Integer[7],
@Integer[7],
@Integer[991],
],
@String[number]:@Integer[97118],
]
```

#### Monitor

* https://arthas.aliyun.com/doc/en/monitor
Expand Down
22 changes: 22 additions & 0 deletions README_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,28 @@ ts=2018-09-18 10:26:28;result=@ArrayList[
]
```

#### line

* https://arthas.aliyun.com/doc/line

观察方法 `demo.MathGame#run` 执行到第25行之前时的局部变量。

```bash
$ line demo.MathGame run 25 -x 2
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 17 ms, listenerId: 2
method=demo.MathGame.run line=25
ts=2024-06-21 09:57:34.452; result=@HashMap[
@String[primeFactors]:@ArrayList[
@Integer[2],
@Integer[7],
@Integer[7],
@Integer[991],
],
@String[number]:@Integer[97118],
]
```

#### Monitor

* https://arthas.aliyun.com/doc/monitor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,30 @@ public void atInvokeException(Class<?> clazz, String invokeInfo, Object target,
}
}

@Override
public void atLine(Class<?> clazz, String methodInfo, Object target, Object[] args, String line, Object[] vars, String[] varNames) {
ClassLoader classLoader = clazz.getClassLoader();

String[] info = StringUtils.splitMethodInfo(methodInfo);
String methodName = info[0];
String methodDesc = info[1];

List<AdviceListener> listeners = com.taobao.arthas.core.advisor.AdviceListenerManager.queryLineAdviceListeners(classLoader, clazz.getName(), line,
methodName, methodDesc);
if (listeners != null) {
for (AdviceListener adviceListener : listeners) {
try {
if (skipAdviceListener(adviceListener)) {
continue;
}
adviceListener.atLine(clazz, methodName, methodDesc, target, args, line, vars, varNames);
} catch (Throwable e) {
logger.error("class: {}, methodInfo: {}, line: {}", clazz.getName(), methodInfo, line, e);
}
}
}
}

private static boolean skipAdviceListener(AdviceListener adviceListener) {
if (adviceListener instanceof ProcessAware) {
ProcessAware processAware = (ProcessAware) adviceListener;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package com.taobao.arthas.core.advisor;

public enum AccessPoint {
ACCESS_BEFORE(1, "AtEnter"), ACCESS_AFTER_RETUNING(1 << 1, "AtExit"), ACCESS_AFTER_THROWING(1 << 2, "AtExceptionExit");

ACCESS_BEFORE(1, "AtEnter"), ACCESS_AFTER_RETUNING(1 << 1, "AtExit"), ACCESS_AFTER_THROWING(1 << 2, "AtExceptionExit"), ACCESS_AT_LINE(1 << 3, "atLine");

private int value;

Expand Down
29 changes: 29 additions & 0 deletions core/src/main/java/com/taobao/arthas/core/advisor/Advice.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.taobao.arthas.core.advisor;

import java.util.Map;

/**
* 通知点 Created by vlinux on 15/5/20.
*/
Expand All @@ -12,6 +14,7 @@ public class Advice {
private final Object[] params;
private final Object returnObj;
private final Throwable throwExp;
private final Map<String,Object> varMap;
private final boolean isBefore;
private final boolean isThrow;
private final boolean isReturn;
Expand Down Expand Up @@ -66,6 +69,7 @@ public ArthasMethod getMethod() {
* @param params 调用参数
* @param returnObj 返回值
* @param throwExp 抛出异常
* @param varMap 变量的Map
* @param access 进入场景
*/
private Advice(
Expand All @@ -76,6 +80,7 @@ private Advice(
Object[] params,
Object returnObj,
Throwable throwExp,
Map<String, Object> varMap,
int access) {
this.loader = loader;
this.clazz = clazz;
Expand All @@ -84,6 +89,7 @@ private Advice(
this.params = params;
this.returnObj = returnObj;
this.throwExp = throwExp;
this.varMap = varMap;
isBefore = (access & AccessPoint.ACCESS_BEFORE.getValue()) == AccessPoint.ACCESS_BEFORE.getValue();
isThrow = (access & AccessPoint.ACCESS_AFTER_THROWING.getValue()) == AccessPoint.ACCESS_AFTER_THROWING.getValue();
isReturn = (access & AccessPoint.ACCESS_AFTER_RETUNING.getValue()) == AccessPoint.ACCESS_AFTER_RETUNING.getValue();
Expand All @@ -102,6 +108,7 @@ public static Advice newForBefore(ClassLoader loader,
params,
null, //returnObj
null, //throwExp
null, //varMap
AccessPoint.ACCESS_BEFORE.getValue()
);
}
Expand All @@ -120,6 +127,7 @@ public static Advice newForAfterReturning(ClassLoader loader,
params,
returnObj,
null, //throwExp
null, //varMap
AccessPoint.ACCESS_AFTER_RETUNING.getValue()
);
}
Expand All @@ -138,9 +146,30 @@ public static Advice newForAfterThrowing(ClassLoader loader,
params,
null, //returnObj
throwExp,
null, //varMap
AccessPoint.ACCESS_AFTER_THROWING.getValue()
);

}

public static Advice newForLine(ClassLoader loader,
Class<?> clazz,
ArthasMethod method,
Object target,
Object[] params,
Map<String, Object> varMap) {
return new Advice(
loader,
clazz,
method,
target,
params,
null, //returnObj
null, //throwExp
varMap,
AccessPoint.ACCESS_AT_LINE.getValue()
);

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,20 @@ void afterThrowing(
Object target, Object[] args,
Throwable throwable) throws Throwable;

/**
* 行观测的监听回调方法
* line 命令中使用,查看本地变量等
*
* @param clazz 类
* @param methodName 方法名
* @param methodDesc 方法描述
* @param target 目标类实例,若目标为静态方法,则为null
* @param args 参数列表
* @param line 行标识,可能是行号(LineNumber),也可能是行的特殊标号(LineCode)
* @param vars 本地变量数组
* @param varNames 本地变量名数组
* @throws Throwable 通知过程出错
*/
void atLine(Class<?> clazz, String methodName, String methodDesc, Object target, Object[] args, String line, Object[] vars, String[] varNames) throws Throwable;

}
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
package com.taobao.arthas.core.advisor;

import java.util.concurrent.atomic.AtomicLong;

import com.taobao.arthas.core.command.express.ExpressException;
import com.taobao.arthas.core.command.express.ExpressFactory;
import com.taobao.arthas.core.command.monitor200.LineHelper;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.arthas.core.shell.system.Process;
import com.taobao.arthas.core.shell.system.ProcessAware;
import com.taobao.arthas.core.util.Constants;
import com.taobao.arthas.core.util.StringUtils;

import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;

/**
*
* @author hengyunabc 2020-05-20
Expand Down Expand Up @@ -106,6 +108,38 @@ public abstract void afterReturning(ClassLoader loader, Class<?> clazz, ArthasMe
public abstract void afterThrowing(ClassLoader loader, Class<?> clazz, ArthasMethod method, Object target,
Object[] args, Throwable throwable) throws Throwable;


/**
* 行观测的监听回调方法
* line 命令中使用,查看本地变量等
*
* @param clazz 类
* @param methodName 方法名
* @param methodDesc 方法描述
* @param target 目标类实例,若目标为静态方法,则为null
* @param args 参数列表
* @param line 行标识,可能是行号(LineNumber),也可能是行的特殊标号(LineCode)
* @param vars 本地变量数组
* @param varNames 本地变量名数组
* @throws Throwable 通知过程出错
*/
@Override
public void atLine(Class<?> clazz, String methodName, String methodDesc, Object target, Object[] args, String line, Object[] vars, String[] varNames) throws Throwable {
Map<String, Object> varMap = LineHelper.buildVarMap(vars, varNames);
Advice advice = Advice.newForLine(clazz.getClassLoader(), clazz, new ArthasMethod(clazz, methodName, methodDesc), target, args, varMap);
atLine(advice, line);
}


/**
* line命令中使用,在行间观测
* 主要用于查看本地变量
*/
public void atLine(Advice advice, String line) throws Throwable {
//doing nothing by default

}

/**
* 判断条件是否满足,满足的情况下需要输出结果
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
package com.taobao.arthas.core.advisor;

import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

import com.alibaba.arthas.deps.org.slf4j.Logger;
import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
import com.taobao.arthas.common.concurrent.ConcurrentWeakKeyHashMap;
Expand All @@ -14,6 +8,12 @@
import com.taobao.arthas.core.shell.system.Process;
import com.taobao.arthas.core.shell.system.ProcessAware;

import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
*
* TODO line 的记录 listener方式? 还是有string为key,不过 classname|method|desc|num 这样子?
Expand Down Expand Up @@ -111,6 +111,14 @@ private String keyForTrace(String className, String owner, String methodName, St
return className + owner + methodName + methodDesc;
}

/**
* 获取行观测对应的key
* @param line line 行标识,可能是行号(LineNumber),也可能是行的特殊标号(LineCode)
*/
private String keyForLine(String className, String line, String methodName, String methodDesc) {
return className + line + methodName + methodDesc;
}

public void registerAdviceListener(String className, String methodName, String methodDesc,
AdviceListener listener) {
synchronized (this) {
Expand Down Expand Up @@ -162,6 +170,40 @@ public List<AdviceListener> queryTraceAdviceListeners(String className, String o

return listeners;
}

/**
* 注册对应行的Listener
* @param line line 行标识,可能是行号(LineNumber),也可能是行的特殊标号(LineCode)
*/
public void registerLineAdviceListener(String className, String line, String methodName, String methodDesc,
AdviceListener listener) {

className = className.replace('/', '.');
String key = keyForLine(className, line, methodName, methodDesc);

List<AdviceListener> listeners = map.get(key);
if (listeners == null) {
listeners = new ArrayList<AdviceListener>();
map.put(key, listeners);
}
if (!listeners.contains(listener)) {
listeners.add(listener);
}
}

/**
* 查询对应行的Listener
* @param line line 行标识,可能是行号(LineNumber),也可能是行的特殊标号(LineCode)
*/
public List<AdviceListener> queryLineAdviceListeners(String className, String line, String methodName,
String methodDesc) {
className = className.replace('/', '.');
String key = keyForLine(className, line, methodName, methodDesc);

List<AdviceListener> listeners = map.get(key);

return listeners;
}
}

public static void registerAdviceListener(ClassLoader classLoader, String className, String methodName,
Expand Down Expand Up @@ -222,6 +264,41 @@ public static List<AdviceListener> queryTraceAdviceListeners(ClassLoader classLo
return null;
}

/**
* 注册对应行的Listener
* @param line line 行标识,可能是行号(LineNumber),也可能是行的特殊标号(LineCode)
*/
public static void registerLineAdviceListener(ClassLoader classLoader, String className, String line,
String methodName, String methodDesc, AdviceListener listener) {
classLoader = wrap(classLoader);
className = className.replace('/', '.');

ClassLoaderAdviceListenerManager manager = adviceListenerMap.get(classLoader);

if (manager == null) {
manager = new ClassLoaderAdviceListenerManager();
adviceListenerMap.put(classLoader, manager);
}
manager.registerLineAdviceListener(className, line, methodName, methodDesc, listener);
}

/**
* 查询对应行的Listener
* @param line line 行标识,可能是行号(LineNumber),也可能是行的特殊标号(LineCode)
*/
public static List<AdviceListener> queryLineAdviceListeners(ClassLoader classLoader, String className,
String line, String methodName, String methodDesc) {
classLoader = wrap(classLoader);
className = className.replace('/', '.');
ClassLoaderAdviceListenerManager manager = adviceListenerMap.get(classLoader);

if (manager != null) {
return manager.queryLineAdviceListeners(className, line, methodName, methodDesc);
}

return null;
}

private static ClassLoader wrap(ClassLoader classLoader) {
if (classLoader != null) {
return classLoader;
Expand Down
Loading