Improve the way to get traceid #1362

This commit is contained in:
hengyunabc 2020-07-23 23:25:34 +08:00
parent 75d5b15ad6
commit 694cbfc069
7 changed files with 73 additions and 130 deletions

View File

@ -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,

View File

@ -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);
}

View File

@ -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())) {

View File

@ -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();
}

View File

@ -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);
}
}

View File

@ -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() {

View File

@ -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
}
}