From e474601e17595ae48b14fb19ea058bc489e8c861 Mon Sep 17 00:00:00 2001 From: qxo <49526356@qq.com> Date: Sat, 28 Oct 2023 00:02:42 +0800 Subject: [PATCH 1/2] feat: add -p for thread/dashboard to filter thread --- .../command/monitor200/DashboardCommand.java | 28 +++++++++++++++++-- .../command/monitor200/ThreadCommand.java | 27 +++++++++++++++++- .../core/command/view/DashboardView.java | 9 ++++-- 3 files changed, 58 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/DashboardCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/DashboardCommand.java index 49b14c87ceb..de1d8ece072 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/DashboardCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/DashboardCommand.java @@ -7,6 +7,7 @@ import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.atomic.AtomicLong; +import java.util.regex.Pattern; import com.alibaba.arthas.deps.org.slf4j.Logger; import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; @@ -59,6 +60,8 @@ public class DashboardCommand extends AnnotatedCommand { private final AtomicLong count = new AtomicLong(0); private volatile Timer timer; + private Pattern threadNamePattern; + @Option(shortName = "n", longName = "number-of-execution") @Description("The number of times this command will be executed.") public void setNumOfExecutions(int numOfExecutions) { @@ -71,6 +74,23 @@ public void setInterval(long interval) { this.interval = interval; } + @Option(shortName = "p",longName = "threadNamePattern") + @Description("Include thread name by regex pattern.") + public void setThreadNamePattern(final String pattern) { + if (pattern != null && !pattern.isEmpty()) { + this.threadNamePattern = Pattern.compile(pattern); + } else { + this.threadNamePattern = null; + } + } + + private boolean runtimeInfoOff; + + @Option(longName = "runtimeInfoOff", flag = true, required = false) + @Description("Hiden runtimeInfo area.") + public void setRuntimeInfoOff(boolean off) { + this.runtimeInfoOff = off; + } @Override public void process(final CommandProcess process) { @@ -239,6 +259,7 @@ public void run() { //thread sample List threads = ThreadUtil.getThreads(); + ThreadCommand.filterThreadByPattern(threads, threadNamePattern); dashboardModel.setThreads(threadSampler.sample(threads)); //memory @@ -247,9 +268,10 @@ public void run() { //gc addGcInfo(dashboardModel); - //runtime - addRuntimeInfo(dashboardModel); - + if (!runtimeInfoOff) { + //runtime + addRuntimeInfo(dashboardModel); + } //tomcat try { addTomcatInfo(dashboardModel); diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/ThreadCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/ThreadCommand.java index 2ef0db2383e..d5a3c66f49a 100755 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/ThreadCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/ThreadCommand.java @@ -25,10 +25,12 @@ import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; +import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.regex.Pattern; /** * @author hengyunabc 2015年12月7日 下午2:06:21 @@ -58,6 +60,8 @@ public class ThreadCommand extends AnnotatedCommand { private boolean lockedSynchronizers = false; private boolean all = false; + private Pattern namePattern; + static { states = new HashSet(State.values().length); for (State state : State.values()) { @@ -113,6 +117,16 @@ public void setLockedSynchronizers(boolean lockedSynchronizers) { this.lockedSynchronizers = lockedSynchronizers; } + @Option(shortName = "p",longName = "namePattern") + @Description("Include thread name by regex pattern.") + public void setNamePattern(final String pattern) { + if (pattern != null && !pattern.isEmpty()) { + this.namePattern = Pattern.compile(pattern); + } else { + this.namePattern = null; + } + } + @Override public void process(CommandProcess process) { ExitStatus exitStatus; @@ -160,7 +174,7 @@ private ExitStatus processAllThreads(CommandProcess process) { } else { resultThreads = threads; } - + filterThreadByPattern(resultThreads, namePattern); //thread stats ThreadSampler threadSampler = new ThreadSampler(); threadSampler.setIncludeInternalThreads(includeInternalThreads); @@ -172,6 +186,17 @@ private ExitStatus processAllThreads(CommandProcess process) { return ExitStatus.success(); } + static void filterThreadByPattern(Collection threads, Pattern pattern) { + if (!threads.isEmpty() && pattern != null) { + for (Iterator iter = threads.iterator(); iter.hasNext();) { + ThreadVO thread = iter.next(); + if (!pattern.matcher(thread.getName()).find()) { + iter.remove(); + } + } + } + } + private ExitStatus processBlockingThread(CommandProcess process) { BlockingLockInfo blockingLockInfo = ThreadUtil.findMostBlockingLock(); if (blockingLockInfo.getThreadInfo() == null) { diff --git a/core/src/main/java/com/taobao/arthas/core/command/view/DashboardView.java b/core/src/main/java/com/taobao/arthas/core/command/view/DashboardView.java index 3d311b8f37c..2b549d5236a 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/view/DashboardView.java +++ b/core/src/main/java/com/taobao/arthas/core/command/view/DashboardView.java @@ -47,10 +47,12 @@ public void draw(CommandProcess process, DashboardModel result) { } //runtime - TableElement runtimeInfoTable = drawRuntimeInfo(result.getRuntimeInfo()); + RuntimeInfoVO runtimeInfo = result.getRuntimeInfo(); + TableElement runtimeInfoTable = runtimeInfo == null ? null : drawRuntimeInfo(runtimeInfo); //tomcat TableElement tomcatInfoTable = drawTomcatInfo(result.getTomcatInfo()); - int runtimeInfoHeight = Math.max(runtimeInfoTable.getRows().size(), tomcatInfoTable == null ? 0 : tomcatInfoTable.getRows().size()); + int runtimeInfoHeight = Math.max(runtimeInfoTable == null ? 0 : runtimeInfoTable.getRows().size(), + tomcatInfoTable == null ? 0 : tomcatInfoTable.getRows().size()); if (runtimeInfoHeight < lowerHalf - memoryInfoHeight) { //如果runtimeInfo高度有剩余,则增大MemoryInfo的高度 memoryInfoHeight = lowerHalf - runtimeInfoHeight; @@ -107,6 +109,9 @@ String drawRuntimeInfoAndTomcatInfo(TableElement runtimeInfoTable, TableElement } else { resultTable = runtimeInfoTable; } + if (runtimeInfoTable == null) { + return ""; + } return RenderUtil.render(resultTable, width, height); } From b247a7c078bce4c9141fc01cab2815b7100c8710 Mon Sep 17 00:00:00 2001 From: qxo <49526356@qq.com> Date: Sat, 9 Dec 2023 09:49:00 +0000 Subject: [PATCH 2/2] :fixup! feat: add -p for thread/dashboard to filter thread --- .../command/monitor200/ThreadCommand.java | 3 +- .../taobao/arthas/core/util/ThreadUtil.java | 28 ++++++++++++++----- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/ThreadCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/ThreadCommand.java index d5a3c66f49a..c180dc5f04a 100755 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/ThreadCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/ThreadCommand.java @@ -198,7 +198,7 @@ static void filterThreadByPattern(Collection threads, Pattern pattern) } private ExitStatus processBlockingThread(CommandProcess process) { - BlockingLockInfo blockingLockInfo = ThreadUtil.findMostBlockingLock(); + final BlockingLockInfo blockingLockInfo = ThreadUtil.findMostBlockingLock(this.namePattern); if (blockingLockInfo.getThreadInfo() == null) { return ExitStatus.failure(1, "No most blocking thread found!"); } @@ -211,6 +211,7 @@ private ExitStatus processTopBusyThreads(CommandProcess process) { threadSampler.sample(ThreadUtil.getThreads()); threadSampler.pause(sampleInterval); List threadStats = threadSampler.sample(ThreadUtil.getThreads()); + filterThreadByPattern(threadStats, namePattern); int limit = Math.min(threadStats.size(), topNBusy); 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 b709857cb7f..c9e1685707f 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 @@ -1,5 +1,18 @@ package com.taobao.arthas.core.util; +import java.arthas.SpyAPI; +import java.lang.management.LockInfo; +import java.lang.management.ManagementFactory; +import java.lang.management.MonitorInfo; +import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + import com.taobao.arthas.core.command.model.BlockingLockInfo; import com.taobao.arthas.core.command.model.BusyThreadInfo; import com.taobao.arthas.core.command.model.StackModel; @@ -7,11 +20,6 @@ import com.taobao.arthas.core.command.model.ThreadVO; import com.taobao.arthas.core.view.Ansi; -import java.arthas.SpyAPI; -import java.lang.management.*; -import java.lang.reflect.Method; -import java.util.*; - /** * * @author hengyunabc 2015年12月7日 下午2:29:28 @@ -96,7 +104,11 @@ public static List getThreadList() { * * @return the BlockingLockInfo object, or an empty object if not found. */ - public static BlockingLockInfo findMostBlockingLock() { + public static BlockingLockInfo findMostBlockingLock() { + return findMostBlockingLock(null); + } + + public static BlockingLockInfo findMostBlockingLock(final Pattern threadNamePattern) { ThreadInfo[] infos = threadMXBean.dumpAllThreads(threadMXBean.isObjectMonitorUsageSupported(), threadMXBean.isSynchronizerUsageSupported()); @@ -109,7 +121,9 @@ public static BlockingLockInfo findMostBlockingLock() { if (info == null) { continue; } - + if (threadNamePattern != null && ! threadNamePattern.matcher(info.getThreadName()).find()) { + continue; + } LockInfo lockInfo = info.getLockInfo(); if (lockInfo != null) { // the current thread is blocked waiting on some condition