Transform stack command

This commit is contained in:
gongdewei
2020-04-13 15:14:47 +08:00
parent e5e498f6c3
commit bac11b3f8a
5 changed files with 203 additions and 10 deletions
@@ -0,0 +1,105 @@
package com.taobao.arthas.core.command.model;
/**
* StackCommand result model
* @author gongdewei 2020/4/13
*/
public class StackModel extends ResultModel {
private String ts;
private double cost;
private String traceId;
private String rpcId;
private String threadName;
private String threadId;
private boolean daemon;
private int priority;
/* Thread Current ClassLoader */
private String tccl;
private StackTraceElement[] stackTrace;
@Override
public String getType() {
return "stack";
}
public String getTs() {
return ts;
}
public void setTs(String ts) {
this.ts = ts;
}
public double getCost() {
return cost;
}
public void setCost(double cost) {
this.cost = cost;
}
public String getThreadName() {
return threadName;
}
public void setThreadName(String threadName) {
this.threadName = threadName;
}
public String getThreadId() {
return threadId;
}
public void setThreadId(String threadId) {
this.threadId = threadId;
}
public boolean isDaemon() {
return daemon;
}
public void setDaemon(boolean daemon) {
this.daemon = daemon;
}
public int getPriority() {
return priority;
}
public void setPriority(int priority) {
this.priority = priority;
}
public String getTccl() {
return tccl;
}
public void setTccl(String tccl) {
this.tccl = tccl;
}
public String getTraceId() {
return traceId;
}
public void setTraceId(String traceId) {
this.traceId = traceId;
}
public String getRpcId() {
return rpcId;
}
public void setRpcId(String rpcId) {
this.rpcId = rpcId;
}
public StackTraceElement[] getStackTrace() {
return stackTrace;
}
public void setStackTrace(StackTraceElement[] stackTrace) {
this.stackTrace = stackTrace;
}
}
@@ -1,6 +1,7 @@
package com.taobao.arthas.core.command.monitor200;
import com.taobao.arthas.core.advisor.ReflectAdviceListenerAdapter;
import com.taobao.arthas.core.command.model.StackModel;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.alibaba.arthas.deps.org.slf4j.Logger;
import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
@@ -17,7 +18,7 @@ import com.taobao.arthas.core.util.ThreadUtil;
public class StackAdviceListener extends ReflectAdviceListenerAdapter {
private static final Logger logger = LoggerFactory.getLogger(StackAdviceListener.class);
private final ThreadLocal<String> stackThreadLocal = new ThreadLocal<String>();
private final ThreadLocal<StackModel> stackThreadLocal = new ThreadLocal<StackModel>();
private final ThreadLocalWatch threadLocalWatch = new ThreadLocalWatch();
private StackCommand command;
private CommandProcess process;
@@ -30,7 +31,7 @@ public class StackAdviceListener extends ReflectAdviceListenerAdapter {
@Override
public void before(ClassLoader loader, Class<?> clazz, ArthasMethod method, Object target, Object[] args)
throws Throwable {
stackThreadLocal.set(ThreadUtil.getThreadStack(Thread.currentThread()));
stackThreadLocal.set(ThreadUtil.getThreadStackModel(Thread.currentThread()));
// 开始计算本次方法调用耗时
threadLocalWatch.start();
}
@@ -55,7 +56,10 @@ public class StackAdviceListener extends ReflectAdviceListenerAdapter {
double cost = threadLocalWatch.costInMillis();
if (isConditionMet(command.getConditionExpress(), advice, cost)) {
// TODO: concurrency issues for process.write
process.write("ts=" + DateUtils.getCurrentDate() + ";" + stackThreadLocal.get() + "\n");
// TODO: should clear stackThreadLocal?
StackModel stackModel = stackThreadLocal.get();
stackModel.setTs(DateUtils.getCurrentDate());
process.appendResult(stackModel);
process.times().incrementAndGet();
if (isLimitExceeded(command.getNumberOfLimit(), process.times().get())) {
abortProcess(process, command.getNumberOfLimit());
@@ -63,9 +67,8 @@ public class StackAdviceListener extends ReflectAdviceListenerAdapter {
}
} catch (Exception e) {
logger.warn("stack failed.", e);
process.write("stack failed, condition is: " + command.getConditionExpress() + ", " + e.getMessage()
+ ", visit " + LogUtil.loggingFile() + " for more details.\n");
process.end();
process.end(-1, "stack failed, condition is: " + command.getConditionExpress() + ", " + e.getMessage()
+ ", visit " + LogUtil.loggingFile() + " for more details.");
}
}
}
@@ -45,6 +45,7 @@ public class ResultViewResolver {
registerView(new ClassInfoModel(), new ClassInfoView());
registerView(new RowAffectModel(), new RowAffectView());
registerView(new MethodModel(), new MethodView());
registerView(new StackModel(), new StackView());
} catch (Throwable e) {
logger.error("register result view failed", e);
}
@@ -0,0 +1,39 @@
package com.taobao.arthas.core.command.view;
import com.taobao.arthas.core.command.model.StackModel;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.arthas.core.util.ThreadUtil;
/**
* @author gongdewei 2020/4/13
*/
public class StackView extends ResultView<StackModel> {
@Override
public void draw(CommandProcess process, StackModel result) {
StringBuilder sb = new StringBuilder();
sb.append(ThreadUtil.getThreadTitle(result)).append("\n");
StackTraceElement[] stackTraceElements = result.getStackTrace();
StackTraceElement locationStackTraceElement = stackTraceElements[0];
String locationString = String.format(" @%s.%s()", locationStackTraceElement.getClassName(),
locationStackTraceElement.getMethodName());
sb.append(locationString).append("\n");
int skip = 1;
for (int index = skip; index < stackTraceElements.length; index++) {
StackTraceElement ste = stackTraceElements[index];
sb.append(" at ")
.append(ste.getClassName())
.append(".")
.append(ste.getMethodName())
.append("(")
.append(ste.getFileName())
.append(":")
.append(ste.getLineNumber())
.append(")\n");
}
process.write("ts=" + result.getTs() + ";" + sb.toString() + "\n");
}
}
@@ -1,5 +1,6 @@
package com.taobao.arthas.core.util;
import com.taobao.arthas.core.command.model.StackModel;
import com.taobao.arthas.core.view.Ansi;
import java.lang.management.*;
@@ -372,6 +373,26 @@ abstract public class ThreadUtil {
return builder.toString();
}
public static StackModel getThreadStackModel(Thread currentThread) {
StackModel stackModel = new StackModel();
stackModel.setThreadName(currentThread.getName());
stackModel.setThreadId(Long.toHexString(currentThread.getId()));
stackModel.setDaemon(currentThread.isDaemon());
stackModel.setPriority(currentThread.getPriority());
stackModel.setTccl(getTCCL(currentThread));
getEagleeyeTraceInfo(currentThread, stackModel);
//stack
StackTraceElement[] stackTraceElementArray = currentThread.getStackTrace();
//drop top 10 frames of Enhancer
int droppingFrames = 10;
StackTraceElement[] actualStackFrames = new StackTraceElement[stackTraceElementArray.length - droppingFrames];
System.arraycopy(stackTraceElementArray, droppingFrames, actualStackFrames, 0, actualStackFrames.length);
stackModel.setStackTrace(actualStackFrames);
return stackModel;
}
public static String getThreadTitle(Thread currentThread) {
StringBuilder sb = new StringBuilder("thread_name=");
sb.append(currentThread.getName())
@@ -379,7 +400,31 @@ abstract public class ThreadUtil {
.append(";is_daemon=").append(currentThread.isDaemon())
.append(";priority=").append(currentThread.getPriority())
.append(";TCCL=").append(getTCCL(currentThread));
getEagleeyeTraceInfo(currentThread, sb);
StackModel stackModel = new StackModel();
getEagleeyeTraceInfo(currentThread, stackModel);
if (stackModel.getTraceId() != null) {
sb.append(";trace_id=").append(stackModel.getTraceId());
}
if (stackModel.getRpcId() != null) {
sb.append(";rpc_id=").append(stackModel.getRpcId());
}
return sb.toString();
}
public static String getThreadTitle(StackModel stackModel) {
StringBuilder sb = new StringBuilder("thread_name=");
sb.append(stackModel.getThreadName())
.append(";id=").append(stackModel.getThreadId())
.append(";is_daemon=").append(stackModel.isDaemon())
.append(";priority=").append(stackModel.getPriority())
.append(";TCCL=").append(stackModel.getTccl());
if (stackModel.getTraceId() != null) {
sb.append(";trace_id=").append(stackModel.getTraceId());
}
if (stackModel.getRpcId() != null) {
sb.append(";rpc_id=").append(stackModel.getRpcId());
}
return sb.toString();
}
@@ -392,7 +437,7 @@ abstract public class ThreadUtil {
}
}
private static void getEagleeyeTraceInfo(Thread currentThread, StringBuilder sb) {
private static void getEagleeyeTraceInfo(Thread currentThread, StackModel stackModel) {
try {
// access to Thread#threadlocals field
Field threadLocalsField = Thread.class.getDeclaredField("threadLocals");
@@ -416,12 +461,12 @@ abstract public class ThreadUtil {
Method getTraceIdMethod = threadLocalValue.getClass().getMethod("getTraceId");
getTraceIdMethod.setAccessible(true);
String traceId = (String)getTraceIdMethod.invoke(threadLocalValue);
sb.append(";trace_id=").append(traceId);
stackModel.setTraceId(traceId);
// get rpc id
Method getRpcIdMethod = threadLocalValue.getClass().getMethod("getRpcId");
getTraceIdMethod.setAccessible(true);
String rpcId = (String)getRpcIdMethod.invoke(threadLocalValue);
sb.append(";rpc_id=").append(rpcId);
stackModel.setRpcId(rpcId);
return;
}
}