mirror of
https://github.com/alibaba/arthas.git
synced 2026-10-21 08:04:33 +00:00
Transform stack command
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
+9
-6
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user