diff --git a/core/src/main/java/com/taobao/arthas/core/advisor/InvokeTraceable.java b/core/src/main/java/com/taobao/arthas/core/advisor/InvokeTraceable.java index 7690d6cd..feba31a7 100644 --- a/core/src/main/java/com/taobao/arthas/core/advisor/InvokeTraceable.java +++ b/core/src/main/java/com/taobao/arthas/core/advisor/InvokeTraceable.java @@ -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, diff --git a/core/src/main/java/com/taobao/arthas/core/advisor/SpyImpl.java b/core/src/main/java/com/taobao/arthas/core/advisor/SpyImpl.java index 607ceb2f..4e4a339a 100644 --- a/core/src/main/java/com/taobao/arthas/core/advisor/SpyImpl.java +++ b/core/src/main/java/com/taobao/arthas/core/advisor/SpyImpl.java @@ -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); } diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/AbstractTraceAdviceListener.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/AbstractTraceAdviceListener.java index e359eed4..6cd3a388 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/AbstractTraceAdviceListener.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/AbstractTraceAdviceListener.java @@ -18,13 +18,7 @@ public class AbstractTraceAdviceListener extends AdviceListenerAdapter { protected TraceCommand command; protected CommandProcess process; - protected final ThreadLocal threadBoundEntity = new ThreadLocal() { - - @Override - protected TraceEntity initialValue() { - return new TraceEntity(); - } - }; + protected final ThreadLocal threadBoundEntity = new ThreadLocal(); /** * 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())) { diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/StackAdviceListener.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/StackAdviceListener.java index 6a6636f5..88855d72 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/StackAdviceListener.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/StackAdviceListener.java @@ -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(); } diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/TraceAdviceListener.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/TraceAdviceListener.java index 0873bdd8..448fae54 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/TraceAdviceListener.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/TraceAdviceListener.java @@ -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); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/TraceEntity.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/TraceEntity.java index 44dd172b..c2e1ecbf 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/TraceEntity.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/TraceEntity.java @@ -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() { diff --git a/core/src/main/java/com/taobao/arthas/core/util/ThreadUtil.java b/core/src/main/java/com/taobao/arthas/core/util/ThreadUtil.java index ac54a090..63329777 100644 --- a/core/src/main/java/com/taobao/arthas/core/util/ThreadUtil.java +++ b/core/src/main/java/com/taobao/arthas/core/util/ThreadUtil.java @@ -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 } }