mirror of
https://gitee.com/arthas/arthas.git
synced 2024-12-02 04:08:34 +08:00
Improve the way to get traceid #1362
This commit is contained in:
parent
75d5b15ad6
commit
694cbfc069
@ -17,6 +17,7 @@ public interface InvokeTraceable {
|
||||
* @throws Throwable 通知过程出错
|
||||
*/
|
||||
void invokeBeforeTracing(
|
||||
ClassLoader classLoader,
|
||||
String tracingClassName,
|
||||
String tracingMethodName,
|
||||
String tracingMethodDesc,
|
||||
@ -32,6 +33,7 @@ public interface InvokeTraceable {
|
||||
* @throws Throwable 通知过程出错
|
||||
*/
|
||||
void invokeThrowTracing(
|
||||
ClassLoader classLoader,
|
||||
String tracingClassName,
|
||||
String tracingMethodName,
|
||||
String tracingMethodDesc,
|
||||
@ -48,6 +50,7 @@ public interface InvokeTraceable {
|
||||
* @throws Throwable 通知过程出错
|
||||
*/
|
||||
void invokeAfterTracing(
|
||||
ClassLoader classLoader,
|
||||
String tracingClassName,
|
||||
String tracingMethodName,
|
||||
String tracingMethodDesc,
|
||||
|
@ -114,7 +114,7 @@ public class SpyImpl extends AbstractSpy {
|
||||
continue;
|
||||
}
|
||||
final InvokeTraceable listener = (InvokeTraceable) adviceListener;
|
||||
listener.invokeBeforeTracing(owner, methodName, methodDesc, Integer.parseInt(info[3]));
|
||||
listener.invokeBeforeTracing(classLoader, owner, methodName, methodDesc, Integer.parseInt(info[3]));
|
||||
} catch (Throwable e) {
|
||||
logger.error("class: {}, invokeInfo: {}", clazz.getName(), invokeInfo, e);
|
||||
}
|
||||
@ -139,7 +139,7 @@ public class SpyImpl extends AbstractSpy {
|
||||
continue;
|
||||
}
|
||||
final InvokeTraceable listener = (InvokeTraceable) adviceListener;
|
||||
listener.invokeAfterTracing(owner, methodName, methodDesc, Integer.parseInt(info[3]));
|
||||
listener.invokeAfterTracing(classLoader, owner, methodName, methodDesc, Integer.parseInt(info[3]));
|
||||
} catch (Throwable e) {
|
||||
logger.error("class: {}, invokeInfo: {}", clazz.getName(), invokeInfo, e);
|
||||
}
|
||||
@ -166,7 +166,7 @@ public class SpyImpl extends AbstractSpy {
|
||||
continue;
|
||||
}
|
||||
final InvokeTraceable listener = (InvokeTraceable) adviceListener;
|
||||
listener.invokeThrowTracing(owner, methodName, methodDesc, Integer.parseInt(info[3]));
|
||||
listener.invokeThrowTracing(classLoader, owner, methodName, methodDesc, Integer.parseInt(info[3]));
|
||||
} catch (Throwable e) {
|
||||
logger.error("class: {}, invokeInfo: {}", clazz.getName(), invokeInfo, e);
|
||||
}
|
||||
|
@ -18,13 +18,7 @@ public class AbstractTraceAdviceListener extends AdviceListenerAdapter {
|
||||
protected TraceCommand command;
|
||||
protected CommandProcess process;
|
||||
|
||||
protected final ThreadLocal<TraceEntity> threadBoundEntity = new ThreadLocal<TraceEntity>() {
|
||||
|
||||
@Override
|
||||
protected TraceEntity initialValue() {
|
||||
return new TraceEntity();
|
||||
}
|
||||
};
|
||||
protected final ThreadLocal<TraceEntity> threadBoundEntity = new ThreadLocal<TraceEntity>();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@ -34,6 +28,15 @@ public class AbstractTraceAdviceListener extends AdviceListenerAdapter {
|
||||
this.process = process;
|
||||
}
|
||||
|
||||
protected TraceEntity threadLocalTraceEntity(ClassLoader loader) {
|
||||
TraceEntity traceEntity = threadBoundEntity.get();
|
||||
if (traceEntity == null) {
|
||||
traceEntity = new TraceEntity(loader);
|
||||
threadBoundEntity.set(traceEntity);
|
||||
}
|
||||
return traceEntity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
threadBoundEntity.remove();
|
||||
@ -42,8 +45,9 @@ public class AbstractTraceAdviceListener extends AdviceListenerAdapter {
|
||||
@Override
|
||||
public void before(ClassLoader loader, Class<?> clazz, ArthasMethod method, Object target, Object[] args)
|
||||
throws Throwable {
|
||||
threadBoundEntity.get().tree.begin(clazz.getName(), method.getName(), -1, false);
|
||||
threadBoundEntity.get().deep++;
|
||||
TraceEntity traceEntity = threadLocalTraceEntity(loader);
|
||||
traceEntity.tree.begin(clazz.getName(), method.getName(), -1, false);
|
||||
traceEntity.deep++;
|
||||
// 开始计算本次方法调用耗时
|
||||
threadLocalWatch.start();
|
||||
}
|
||||
@ -51,28 +55,29 @@ public class AbstractTraceAdviceListener extends AdviceListenerAdapter {
|
||||
@Override
|
||||
public void afterReturning(ClassLoader loader, Class<?> clazz, ArthasMethod method, Object target, Object[] args,
|
||||
Object returnObject) throws Throwable {
|
||||
threadBoundEntity.get().tree.end();
|
||||
threadLocalTraceEntity(loader).tree.end();
|
||||
final Advice advice = Advice.newForAfterRetuning(loader, clazz, method, target, args, returnObject);
|
||||
finishing(advice);
|
||||
finishing(loader, advice);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterThrowing(ClassLoader loader, Class<?> clazz, ArthasMethod method, Object target, Object[] args,
|
||||
Throwable throwable) throws Throwable {
|
||||
int lineNumber = throwable.getStackTrace()[0].getLineNumber();
|
||||
threadBoundEntity.get().tree.end(throwable, lineNumber);
|
||||
threadLocalTraceEntity(loader).tree.end(throwable, lineNumber);
|
||||
final Advice advice = Advice.newForAfterThrowing(loader, clazz, method, target, args, throwable);
|
||||
finishing(advice);
|
||||
finishing(loader, advice);
|
||||
}
|
||||
|
||||
public TraceCommand getCommand() {
|
||||
return command;
|
||||
}
|
||||
|
||||
private void finishing(Advice advice) {
|
||||
private void finishing(ClassLoader loader, Advice advice) {
|
||||
// 本次调用的耗时
|
||||
TraceEntity traceEntity = threadLocalTraceEntity(loader);
|
||||
double cost = threadLocalWatch.costInMillis();
|
||||
if (--threadBoundEntity.get().deep == 0) {
|
||||
if (--traceEntity.deep == 0) {
|
||||
try {
|
||||
boolean conditionResult = isConditionMet(command.getConditionExpress(), advice, cost);
|
||||
if (this.isVerbose()) {
|
||||
@ -82,7 +87,7 @@ public class AbstractTraceAdviceListener extends AdviceListenerAdapter {
|
||||
// 满足输出条件
|
||||
process.times().incrementAndGet();
|
||||
// TODO: concurrency issues for process.write
|
||||
process.appendResult(threadBoundEntity.get().getModel());
|
||||
process.appendResult(traceEntity.getModel());
|
||||
|
||||
// 是否到达数量限制
|
||||
if (isLimitExceeded(command.getNumberOfLimit(), process.times().get())) {
|
||||
|
@ -33,7 +33,7 @@ public class StackAdviceListener extends AdviceListenerAdapter {
|
||||
@Override
|
||||
public void before(ClassLoader loader, Class<?> clazz, ArthasMethod method, Object target, Object[] args)
|
||||
throws Throwable {
|
||||
stackThreadLocal.set(ThreadUtil.getThreadStackModel(Thread.currentThread()));
|
||||
stackThreadLocal.set(ThreadUtil.getThreadStackModel(loader, Thread.currentThread()));
|
||||
// 开始计算本次方法调用耗时
|
||||
threadLocalWatch.start();
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package com.taobao.arthas.core.command.monitor200;
|
||||
|
||||
import com.taobao.arthas.core.advisor.InvokeTraceable;
|
||||
import com.taobao.arthas.core.shell.command.CommandProcess;
|
||||
import com.taobao.arthas.core.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @author beiwei30 on 29/11/2016.
|
||||
@ -21,22 +20,22 @@ public class TraceAdviceListener extends AbstractTraceAdviceListener implements
|
||||
* trace 会在被观测的方法体中,在每个方法调用前后插入字节码,所以方法调用开始,结束,抛异常的时候,都会回调下面的接口
|
||||
*/
|
||||
@Override
|
||||
public void invokeBeforeTracing(String tracingClassName, String tracingMethodName, String tracingMethodDesc, int tracingLineNumber)
|
||||
public void invokeBeforeTracing(ClassLoader classLoader, String tracingClassName, String tracingMethodName, String tracingMethodDesc, int tracingLineNumber)
|
||||
throws Throwable {
|
||||
// normalize className later
|
||||
threadBoundEntity.get().tree.begin(tracingClassName, tracingMethodName, tracingLineNumber, true);
|
||||
threadLocalTraceEntity(classLoader).tree.begin(tracingClassName, tracingMethodName, tracingLineNumber, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invokeAfterTracing(String tracingClassName, String tracingMethodName, String tracingMethodDesc, int tracingLineNumber)
|
||||
public void invokeAfterTracing(ClassLoader classLoader, String tracingClassName, String tracingMethodName, String tracingMethodDesc, int tracingLineNumber)
|
||||
throws Throwable {
|
||||
threadBoundEntity.get().tree.end();
|
||||
threadLocalTraceEntity(classLoader).tree.end();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invokeThrowTracing(String tracingClassName, String tracingMethodName, String tracingMethodDesc, int tracingLineNumber)
|
||||
public void invokeThrowTracing(ClassLoader classLoader, String tracingClassName, String tracingMethodName, String tracingMethodDesc, int tracingLineNumber)
|
||||
throws Throwable {
|
||||
threadBoundEntity.get().tree.end(true);
|
||||
threadLocalTraceEntity(classLoader).tree.end(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,8 +13,8 @@ public class TraceEntity {
|
||||
protected TraceTree tree;
|
||||
protected int deep;
|
||||
|
||||
public TraceEntity() {
|
||||
this.tree = createTraceTree();
|
||||
public TraceEntity(ClassLoader loader) {
|
||||
this.tree = createTraceTree(loader);
|
||||
this.deep = 0;
|
||||
}
|
||||
|
||||
@ -26,8 +26,8 @@ public class TraceEntity {
|
||||
this.deep = deep;
|
||||
}
|
||||
|
||||
private TraceTree createTraceTree() {
|
||||
return new TraceTree(ThreadUtil.getThreadNode(Thread.currentThread()));
|
||||
private TraceTree createTraceTree(ClassLoader loader) {
|
||||
return new TraceTree(ThreadUtil.getThreadNode(loader, Thread.currentThread()));
|
||||
}
|
||||
|
||||
public TraceModel getModel() {
|
||||
|
@ -7,7 +7,6 @@ import com.taobao.arthas.core.view.Ansi;
|
||||
|
||||
import java.arthas.SpyAPI;
|
||||
import java.lang.management.*;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
|
||||
@ -21,9 +20,9 @@ abstract public class ThreadUtil {
|
||||
private static final BlockingLockInfo EMPTY_INFO = new BlockingLockInfo();
|
||||
|
||||
private static ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
|
||||
private static Field threadLocalsField;
|
||||
private static Field threadLocalsTableFiled;
|
||||
private static Field threadLocalEntryValueField;
|
||||
|
||||
private static boolean detectedEagleEye = false;
|
||||
public static boolean foundEagleEye = false;
|
||||
|
||||
public static ThreadGroup getRoot() {
|
||||
ThreadGroup group = Thread.currentThread().getThreadGroup();
|
||||
@ -370,40 +369,7 @@ abstract public class ThreadUtil {
|
||||
*
|
||||
* @return 方法堆栈信息
|
||||
*/
|
||||
public static String getThreadStack(Thread currentThread) {
|
||||
StackTraceElement[] stackTraceElementArray = currentThread.getStackTrace();
|
||||
int magicStackDepth = findTheSpyAPIDepth(stackTraceElementArray);
|
||||
|
||||
StackTraceElement locationStackTraceElement = stackTraceElementArray[magicStackDepth];
|
||||
String locationString = String.format(" @%s.%s()", locationStackTraceElement.getClassName(),
|
||||
locationStackTraceElement.getMethodName());
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(getThreadTitle(currentThread)).append("\n").append(locationString).append("\n");
|
||||
|
||||
int skip = magicStackDepth + 1;
|
||||
for (int index = skip; index < stackTraceElementArray.length; index++) {
|
||||
StackTraceElement ste = stackTraceElementArray[index];
|
||||
builder.append(" at ")
|
||||
.append(ste.getClassName())
|
||||
.append(".")
|
||||
.append(ste.getMethodName())
|
||||
.append("(")
|
||||
.append(ste.getFileName())
|
||||
.append(":")
|
||||
.append(ste.getLineNumber())
|
||||
.append(")\n");
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取方法执行堆栈信息
|
||||
*
|
||||
* @return 方法堆栈信息
|
||||
*/
|
||||
public static StackModel getThreadStackModel(Thread currentThread) {
|
||||
public static StackModel getThreadStackModel(ClassLoader loader, Thread currentThread) {
|
||||
StackModel stackModel = new StackModel();
|
||||
stackModel.setThreadName(currentThread.getName());
|
||||
stackModel.setThreadId(Long.toHexString(currentThread.getId()));
|
||||
@ -411,7 +377,7 @@ abstract public class ThreadUtil {
|
||||
stackModel.setPriority(currentThread.getPriority());
|
||||
stackModel.setClassloader(getTCCL(currentThread));
|
||||
|
||||
getEagleeyeTraceInfo(currentThread, stackModel);
|
||||
getEagleeyeTraceInfo(loader, currentThread, stackModel);
|
||||
|
||||
|
||||
//stack
|
||||
@ -423,26 +389,7 @@ abstract public class ThreadUtil {
|
||||
return stackModel;
|
||||
}
|
||||
|
||||
public static String getThreadTitle(Thread currentThread) {
|
||||
StringBuilder sb = new StringBuilder("thread_name=");
|
||||
sb.append(currentThread.getName())
|
||||
.append(";id=").append(Long.toHexString(currentThread.getId()))
|
||||
.append(";is_daemon=").append(currentThread.isDaemon())
|
||||
.append(";priority=").append(currentThread.getPriority())
|
||||
.append(";TCCL=").append(getTCCL(currentThread));
|
||||
|
||||
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 ThreadNode getThreadNode(Thread currentThread) {
|
||||
public static ThreadNode getThreadNode(ClassLoader loader, Thread currentThread) {
|
||||
ThreadNode threadNode = new ThreadNode();
|
||||
threadNode.setThreadId(currentThread.getId());
|
||||
threadNode.setThreadName(currentThread.getName());
|
||||
@ -452,7 +399,7 @@ abstract public class ThreadUtil {
|
||||
|
||||
//trace_id
|
||||
StackModel stackModel = new StackModel();
|
||||
getEagleeyeTraceInfo(currentThread, stackModel);
|
||||
getEagleeyeTraceInfo(loader, currentThread, stackModel);
|
||||
threadNode.setTraceId(stackModel.getTraceId());
|
||||
threadNode.setRpcId(stackModel.getRpcId());
|
||||
return threadNode;
|
||||
@ -487,48 +434,37 @@ abstract public class ThreadUtil {
|
||||
}
|
||||
}
|
||||
|
||||
private static void getEagleeyeTraceInfo(Thread currentThread, StackModel stackModel) {
|
||||
try {
|
||||
// access to Thread#threadlocals field
|
||||
if (threadLocalsField == null) {
|
||||
threadLocalsField = Thread.class.getDeclaredField("threadLocals");
|
||||
private static void getEagleeyeTraceInfo(ClassLoader loader, Thread currentThread, StackModel stackModel) {
|
||||
if(loader == null) {
|
||||
return;
|
||||
}
|
||||
Class<?> eagleEyeClass = null;
|
||||
if (!detectedEagleEye) {
|
||||
try {
|
||||
eagleEyeClass = loader.loadClass("com.taobao.eagleeye.EagleEye");
|
||||
foundEagleEye = true;
|
||||
} catch (Throwable e) {
|
||||
// ignore
|
||||
}
|
||||
threadLocalsField.setAccessible(true);
|
||||
Object threadLocalMap = threadLocalsField.get(currentThread);
|
||||
detectedEagleEye = true;
|
||||
}
|
||||
|
||||
// access to ThreadLocal$ThreadLocalMap#table filed
|
||||
if (threadLocalsTableFiled == null) {
|
||||
threadLocalsTableFiled = threadLocalMap.getClass().getDeclaredField("table");
|
||||
if (!foundEagleEye) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (eagleEyeClass == null) {
|
||||
eagleEyeClass = loader.loadClass("com.taobao.eagleeye.EagleEye");
|
||||
}
|
||||
threadLocalsTableFiled.setAccessible(true);
|
||||
Object[] tableEntries = (Object[]) threadLocalsTableFiled.get(threadLocalMap);
|
||||
for (Object entry: tableEntries) {
|
||||
if (entry == null) {
|
||||
continue;
|
||||
}
|
||||
// access to ThreadLocal$ThreadLocalMap$Entry#value field
|
||||
if (threadLocalEntryValueField == null) {
|
||||
threadLocalEntryValueField = entry.getClass().getDeclaredField("value");
|
||||
}
|
||||
threadLocalEntryValueField.setAccessible(true);
|
||||
Object threadLocalValue = threadLocalEntryValueField.get(entry);
|
||||
if (threadLocalValue != null &&
|
||||
"com.taobao.eagleeye.RpcContext_inner".equals(threadLocalValue.getClass().getName())) {
|
||||
// finally we got the chance to access trace id
|
||||
Method getTraceIdMethod = threadLocalValue.getClass().getMethod("getTraceId");
|
||||
getTraceIdMethod.setAccessible(true);
|
||||
String traceId = (String)getTraceIdMethod.invoke(threadLocalValue);
|
||||
stackModel.setTraceId(traceId);
|
||||
// get rpc id
|
||||
Method getRpcIdMethod = threadLocalValue.getClass().getMethod("getRpcId");
|
||||
getTraceIdMethod.setAccessible(true);
|
||||
String rpcId = (String)getRpcIdMethod.invoke(threadLocalValue);
|
||||
stackModel.setRpcId(rpcId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
Method getTraceIdMethod = eagleEyeClass.getMethod("getTraceId");
|
||||
String traceId = (String) getTraceIdMethod.invoke(null);
|
||||
stackModel.setTraceId(traceId);
|
||||
Method getRpcIdMethod = eagleEyeClass.getMethod("getRpcId");
|
||||
String rpcId = (String) getRpcIdMethod.invoke(null);
|
||||
stackModel.setRpcId(rpcId);
|
||||
} catch (Throwable e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user