feature-addThreadCpuUsage (#1)

* 增加线程的CPU使用率

* 修改版本号

* 增加排序

---------

Co-authored-by: zhaoxiang <zhaoxiang@tianyancha.com>
This commit is contained in:
romanticmj 2024-04-08 17:14:59 +08:00 committed by GitHub
parent fb7c64cde7
commit 427d99f93e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 90 additions and 4 deletions

View File

@ -6,6 +6,16 @@
<option name="name" value="Central Repository" /> <option name="name" value="Central Repository" />
<option name="url" value="https://repo.maven.apache.org/maven2" /> <option name="url" value="https://repo.maven.apache.org/maven2" />
</remote-repository> </remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="http://maven.jindidata.com/nexus/content/groups/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="nexus" />
<option name="name" value="Nexus" />
<option name="url" value="http://maven.jindidata.com/nexus/content/groups/public/" />
</remote-repository>
<remote-repository> <remote-repository>
<option name="id" value="central" /> <option name="id" value="central" />
<option name="name" value="Maven Central repository" /> <option name="name" value="Maven Central repository" />

View File

@ -6,7 +6,7 @@
<groupId>cn.langpy</groupId> <groupId>cn.langpy</groupId>
<artifactId>ko-time</artifactId> <artifactId>ko-time</artifactId>
<version>2.4.3</version> <version>2.4.4</version>
<name>KoTime</name> <name>KoTime</name>
<description>A springboot tool for tracking the paths of the methods,which can help you find method's performances easily.</description> <description>A springboot tool for tracking the paths of the methods,which can help you find method's performances easily.</description>
<licenses> <licenses>

View File

@ -25,6 +25,8 @@ import java.util.*;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static cn.langpy.kotime.model.ThreadInfo.COMPARATOR;
/** /**
* zhangchang * zhangchang
*/ */
@ -372,7 +374,7 @@ public class KoTimeController {
public Map getThreadsInfo(String state) { public Map getThreadsInfo(String state) {
ThreadUsageService usageService = ThreadUsageService.newInstance(); ThreadUsageService usageService = ThreadUsageService.newInstance();
List<ThreadInfo> threads = usageService.getThreads(); List<ThreadInfo> threads = usageService.getThreads();
threads = threads.stream().sorted(Comparator.comparing(ThreadInfo::getState)).collect(Collectors.toList()); threads = threads.stream().sorted(COMPARATOR).collect(Collectors.toList());
Map<String, Long> stateCounting = threads.stream().collect(Collectors.groupingBy(ThreadInfo::getState, Collectors.counting())); Map<String, Long> stateCounting = threads.stream().collect(Collectors.groupingBy(ThreadInfo::getState, Collectors.counting()));
stateCounting.put("all",(long)threads.size()); stateCounting.put("all",(long)threads.size());

View File

@ -1,8 +1,13 @@
package cn.langpy.kotime.model; package cn.langpy.kotime.model;
import java.math.BigDecimal;
import java.util.Comparator;
import java.util.List; import java.util.List;
public class ThreadInfo { public class ThreadInfo {
public static final ThreadInfoComparator COMPARATOR = new ThreadInfoComparator();
private Long id; private Long id;
private String name; private String name;
private String classType; private String classType;
@ -10,6 +15,7 @@ public class ThreadInfo {
private Boolean isInterrupted; private Boolean isInterrupted;
private Boolean isDaemon; private Boolean isDaemon;
private Integer priority; private Integer priority;
private BigDecimal cpuUsage;
private List<StackTraceElement> stacks; private List<StackTraceElement> stacks;
public Long getId() { public Long getId() {
@ -68,6 +74,14 @@ public class ThreadInfo {
this.priority = priority; this.priority = priority;
} }
public BigDecimal getCpuUsage() {
return cpuUsage;
}
public void setCpuUsage(BigDecimal cpuUsage) {
this.cpuUsage = cpuUsage;
}
public List<StackTraceElement> getStacks() { public List<StackTraceElement> getStacks() {
return stacks; return stacks;
} }
@ -75,4 +89,18 @@ public class ThreadInfo {
public void setStacks(List<StackTraceElement> stacks) { public void setStacks(List<StackTraceElement> stacks) {
this.stacks = stacks; this.stacks = stacks;
} }
/**
* 状态码排序 + CPU使用率倒排
*/
public static class ThreadInfoComparator implements Comparator<ThreadInfo> {
@Override
public int compare(ThreadInfo a, ThreadInfo b) {
if (a.getState().compareTo(b.getState()) == 0 ) {
return b.getCpuUsage().compareTo(a.getCpuUsage());
}
return a.getState().compareTo(b.getState());
}
}
} }

View File

@ -1,9 +1,16 @@
package cn.langpy.kotime.service; package cn.langpy.kotime.service;
import cn.langpy.kotime.model.ThreadInfo; import cn.langpy.kotime.model.ThreadInfo;
import cn.langpy.kotime.util.Context;
import org.springframework.util.CollectionUtils;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;
import java.math.BigDecimal;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -17,6 +24,7 @@ public class ThreadUsageService {
public List<ThreadInfo> getThreads() { public List<ThreadInfo> getThreads() {
ThreadGroup threadGroup = Thread.currentThread().getThreadGroup(); ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();;
int activeCount = threadGroup.activeCount(); int activeCount = threadGroup.activeCount();
Thread[] threads = new Thread[activeCount]; Thread[] threads = new Thread[activeCount];
threadGroup.enumerate(threads); threadGroup.enumerate(threads);
@ -25,6 +33,8 @@ public class ThreadUsageService {
Thread thread = threads[i]; Thread thread = threads[i];
ThreadInfo threadInfo = new ThreadInfo(); ThreadInfo threadInfo = new ThreadInfo();
threadInfo.setId(thread.getId()); threadInfo.setId(thread.getId());
threadInfo.setCpuUsage(BigDecimal.valueOf(threadMXBean.getThreadCpuTime(thread.getId()))
.divide(BigDecimal.valueOf(threadMXBean.getThreadUserTime(thread.getId())), 2, BigDecimal.ROUND_HALF_UP));
threadInfo.setName(thread.getName()); threadInfo.setName(thread.getName());
threadInfo.setClassType(thread.getClass().getSimpleName()); threadInfo.setClassType(thread.getClass().getSimpleName());
threadInfo.setState(thread.getState().name()); threadInfo.setState(thread.getState().name());
@ -35,6 +45,7 @@ public class ThreadUsageService {
threadInfo.setStacks(Arrays.stream(stackTrace).collect(Collectors.toList())); threadInfo.setStacks(Arrays.stream(stackTrace).collect(Collectors.toList()));
list.add(threadInfo); list.add(threadInfo);
} }
Collections.sort(list, Comparator.comparing(ThreadInfo::getCpuUsage).reversed());
return list; return list;
} }

View File

@ -553,6 +553,22 @@
} }
}); });
} }
const cpuUsageColorMap = {
'RED': '#cc0c0c',
'YELLOW': '#f0ad4e',
'LIGHT_BLUE': '#5bc0de'
};
function getCpuUsageColor(usage) {
if (usage > 50) {
return cpuUsageColorMap['RED'];
} else if (usage >= 20 && usage <= 50) {
return cpuUsageColorMap['YELLOW'];
} else {
return cpuUsageColorMap['LIGHT_BLUE'];
}
}
let threadMap = new Map(); let threadMap = new Map();
function loadThreadsInfo(queryState) { function loadThreadsInfo(queryState) {
queryState = queryState || ''; queryState = queryState || '';
@ -586,8 +602,10 @@
let classType = thread['classType']; let classType = thread['classType'];
let state = thread['state']; let state = thread['state'];
let stacks = thread['stacks']; let stacks = thread['stacks'];
let cpuUsage = thread['cpuUsage'];
let cpuUsageColor = getCpuUsageColor(cpuUsage);
threadMap[id+''] = stacks; threadMap[id+''] = stacks;
html+=`<li onclick="showThreadInfo('${id}')" style='color: #333;font-weight: 400;font-size: 14px;'>id=<span style="font-size: 16px;font-weight: 500;">${id}</span>&nbsp; &nbsp;name=${name}&nbsp; &nbsp;class=${classType}&nbsp; &nbsp;<span style='font-size: 10px;background-color: ${colors[state]};' class="uk-label uk-label-success">${state}</span></li>`; html+=`<li onclick="showThreadInfo('${id}')" style='color: #333;font-weight: 400;font-size: 14px;'>id=<span style="font-size: 16px;font-weight: 500;">${id}</span>&nbsp; &nbsp;name=${name}&nbsp; &nbsp;class=${classType}&nbsp; &nbsp;<span style="font-size: 10px;background-color: ${cpuUsageColor};" class="uk-label uk-label-success">CPU-UsagePercent:${cpuUsage}%</span>&nbsp; &nbsp;<span style='font-size: 10px;background-color: ${colors[state]};' class="uk-label uk-label-success">${state}</span></li>`;
} }
element.innerHTML = html; element.innerHTML = html;
}); });

View File

@ -546,6 +546,21 @@
}); });
} }
const cpuUsageColorMap = {
'RED': '#cc0c0c',
'YELLOW': '#f0ad4e',
'LIGHT_BLUE': '#5bc0de'
};
function getCpuUsageColor(usage) {
if (usage > 50) {
return cpuUsageColorMap['RED'];
} else if (usage >= 20 && usage <= 50) {
return cpuUsageColorMap['YELLOW'];
} else {
return cpuUsageColorMap['LIGHT_BLUE'];
}
}
let threadMap = new Map(); let threadMap = new Map();
function loadThreadsInfo(queryState) { function loadThreadsInfo(queryState) {
queryState = queryState || ''; queryState = queryState || '';
@ -579,8 +594,10 @@
let classType = thread['classType']; let classType = thread['classType'];
let state = thread['state']; let state = thread['state'];
let stacks = thread['stacks']; let stacks = thread['stacks'];
let cpuUsage = thread['cpuUsage'];
let cpuUsageColor = getCpuUsageColor(cpuUsage);
threadMap[id+''] = stacks; threadMap[id+''] = stacks;
html+=`<li onclick="showThreadInfo('${id}')" style='color: #333;font-weight: 400;font-size: 14px;'>id=<span style="font-size: 16px;font-weight: 500;">${id}</span>&nbsp; &nbsp;name=${name}&nbsp; &nbsp;class=${classType}&nbsp; &nbsp;<span style='font-size: 10px;background-color: ${colors[state]};' class="uk-label uk-label-success">${state}</span></li>`; html+=`<li onclick="showThreadInfo('${id}')" style='color: #333;font-weight: 400;font-size: 14px;'>id=<span style="font-size: 16px;font-weight: 500;">${id}</span>&nbsp; &nbsp;name=${name}&nbsp; &nbsp;class=${classType}&nbsp; &nbsp;<span style="font-size: 10px;background-color: ${cpuUsageColor};" class="uk-label uk-label-success">CPU使用率:${cpuUsage}%</span>&nbsp; &nbsp;<span style='font-size: 10px;background-color: ${colors[state]};' class="uk-label uk-label-success">${state}</span></li>`;
} }
element.innerHTML = html; element.innerHTML = html;
}); });