Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#513] Virtual thread pin event metric and alarm #517

Open
wants to merge 18 commits into
base: springboot3-dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,28 @@ private DingNotifyConst() { }

public static final String DING_NOTICE_TITLE = "动态线程池通知";

public static final String DING_ALARM_TEMPLATE =
public static final String DING_ALARM_TEMPLATE_PREFIX =
"<font color=#EA9F00>【报警】 </font> 动态线程池运行告警 \n\n" +
"<font color=#664B4B size=2>服务名称:%s</font> \n\n " +
"<font color=#664B4B size=2>实例信息:%s</font> \n\n " +
"<font color=#664B4B size=2>环境:%s</font> \n\n " +
"<font color=#664B4B size=2>线程池名称:%s</font> \n\n " +
"<font color=alarmType size=2>报警项:%s</font> \n\n " +
"<font color=alarmValue size=2>报警阈值 / 当前值:%s</font> \n\n " +
"<font color=alarmValue size=2>报警阈值 / 当前值:%s</font> \n\n ";

public static final String DING_ALARM_COMMON_TEMPLATE =
"<font color=#664B4B size=2>%s</font> \n\n ";

public static final String DING_ALARM_TEMPLATE_SUFFIX =
"<font color=#664B4B size=2>上次报警时间:%s</font> \n\n" +
"<font color=#664B4B size=2>报警时间:%s</font> \n\n" +
"<font color=#664B4B size=2>接收人:@%s</font> \n\n" +
"<font color=#664B4B size=2>trace 信息:%s</font> \n\n" +
"<font color=#22B838 size=2>报警间隔:%ss</font> \n\n" +
"<font color=#664B4B size=2>扩展信息:%s</font> \n\n";

public static final String DING_ALARM_TEMPLATE =
DING_ALARM_TEMPLATE_PREFIX +
"<font color=corePoolSize size=2>核心线程数:%d</font> \n\n " +
"<font color=maximumPoolSize size=2>最大线程数:%d</font> \n\n " +
"<font color=poolSize size=2>当前线程数:%d</font> \n\n " +
Expand All @@ -65,12 +79,7 @@ private DingNotifyConst() { }
"<font color=rejectCount size=2>总拒绝任务数量:%s</font> \n\n " +
"<font color=runTimeoutCount size=2>总执行超时任务数量:%s</font> \n\n " +
"<font color=queueTimeoutCount size=2>总等待超时任务数量:%s</font> \n\n " +
"<font color=#664B4B size=2>上次报警时间:%s</font> \n\n" +
"<font color=#664B4B size=2>报警时间:%s</font> \n\n" +
"<font color=#664B4B size=2>接收人:@%s</font> \n\n" +
"<font color=#664B4B size=2>trace 信息:%s</font> \n\n" +
"<font color=#22B838 size=2>报警间隔:%ss</font> \n\n" +
"<font color=#664B4B size=2>扩展信息:%s</font> \n\n";
DING_ALARM_TEMPLATE_SUFFIX;

public static final String DING_CHANGE_NOTICE_TEMPLATE =
"<font color=#5AB030>【通知】</font> 动态线程池参数变更 \n\n " +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,15 @@ private DynamicTpConst() { }
public static final String FALSE_STR = "false";

/**
* jre
* jre 21
*/
public static final String THREAD_PER_TASK_EXECUTOR = "java.util.concurrent.ThreadPerTaskExecutor";

public static final String PINNED_EVENT = "jdk.VirtualThreadPinned";

public static final String MAX_PINNED_TIME = "maxPinnedTime";

public static final String TOTAL_PINNED_TIME = "totalPinnedTime";

public static final String PINNED_DURATION = "pinnedDuration";
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,20 @@ private LarkNotifyConst() { }

public static final String SIGN_PARAM_PREFIX = "{\"timestamp\": \"%s\",\"sign\": \"%s\",";

public static final String LARK_ALARM_JSON_STR_PREFIX =
"{\"msg_type\":\"interactive\",\"card\":{\"config\":{\"wide_screen_mode\":true},\"header\":{\"template\":\"red\",\"title\":{\"tag\":\"plain_text\",\"content\":\"【报警】 动态线程池告警\"}},\"elements\":[{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**服务名称:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**实例信息:**\\n%s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**环境:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**线程池名称:**\\n%s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"alarmType **报警项:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"alarmValue **报警阈值 / 当前值:**\\n%s\"}}]},{\"tag\":\"hr\"},";

public static final String LARK_ALARM_JSON_COMMON_STR =
"{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"%s\"}}]},";

public static final String LARK_ALARM_JSON_STR_SUFFIX =
"{\"tag\":\"hr\"},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**上次报警时间:**\\n %s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**报警时间:**\\n %s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**接收人:**\\n %s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**trace 信息:**\\n %s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**报警间隔:**\\n %ss\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**扩展信息:**\\n %s\"}}]}]}}";

/**
* lark alarm json str
*/
public static final String LARK_ALARM_JSON_STR =
"{\"msg_type\":\"interactive\",\"card\":{\"config\":{\"wide_screen_mode\":true},\"header\":{\"template\":\"red\",\"title\":{\"tag\":\"plain_text\",\"content\":\"【报警】 动态线程池告警\"}},\"elements\":[{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**服务名称:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**实例信息:**\\n%s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**环境:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**线程池名称:**\\n%s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"alarmType **报警项:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"alarmValue **报警阈值 / 当前值:**\\n%s\"}}]},{\"tag\":\"hr\"},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"corePoolSize **核心线程数:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"maximumPoolSize **最大线程数:**\\n%s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"poolSize **当前线程数:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"activeCount **活跃线程数:**\\n%s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**历史最大线程数:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**任务总数:**\\n%s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**执行完成任务数:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**等待执行任务数:**\\n%s\"}}]},{\"tag\":\"hr\"},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"queueType **队列类型:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"queueCapacity **队列容量:**\\n%s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"queueSize **队列任务数量:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"queueRemaining **队列剩余容量:**\\n%s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"rejectType **拒绝策略:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"rejectCount **总拒绝任务数量:**\\n%s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"runTimeoutCount **总执行超时任务数量:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"queueTimeoutCount **总等待超时任务数量:**\\n%s\"}}]},{\"tag\":\"hr\"},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**上次报警时间:**\\n %s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**报警时间:**\\n %s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**接收人:**\\n %s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**trace 信息:**\\n %s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**报警间隔:**\\n %ss\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**扩展信息:**\\n %s\"}}]}]}}";
LARK_ALARM_JSON_STR_PREFIX + "{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"corePoolSize **核心线程数:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"maximumPoolSize **最大线程数:**\\n%s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"poolSize **当前线程数:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"activeCount **活跃线程数:**\\n%s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**历史最大线程数:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**任务总数:**\\n%s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**执行完成任务数:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**等待执行任务数:**\\n%s\"}}]},{\"tag\":\"hr\"},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"queueType **队列类型:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"queueCapacity **队列容量:**\\n%s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"queueSize **队列任务数量:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"queueRemaining **队列剩余容量:**\\n%s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"rejectType **拒绝策略:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"rejectCount **总拒绝任务数量:**\\n%s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"runTimeoutCount **总执行超时任务数量:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"queueTimeoutCount **总等待超时任务数量:**\\n%s\"}}]}," + LARK_ALARM_JSON_STR_SUFFIX;

/**
* lark notice json str
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,31 @@ private WechatNotifyConst() { }

public static final String COMMENT_COLOR = "comment";

/**
* receivers only supports userid, view more, see <a href="https://developer.work.weixin.qq.com/document/path/91770">more</a>.
*/
public static final String WECHAT_ALARM_TEMPLATE =
public static final String WECHAT_ALARM_TEMPLATE_PREFIX =
"<font color='warning'>【报警】</font> 动态线程池告警 \n" +
"> <font color='comment'>服务名称:%s</font> \n" +
"> <font color='comment'>实例信息:%s</font> \n" +
"> <font color='comment'>环境:%s</font> \n" +
"> <font color='comment'>线程池名称:%s</font> \n" +
"> <font color='alarmType'>报警项:%s</font> \n" +
"> <font color='alarmValue'>报警阈值 / 当前值:%s</font> \n" +
"> <font color='alarmValue'>报警阈值 / 当前值:%s</font> \n";

public static final String WECHAT_ALARM_COMMON_TEMPLATE =
"> <font color='comment'>%s</font> \n";

public static final String WECHAT_ALARM_TEMPLATE_SUFFIX =
"> <font color='comment'>上次报警时间:%s</font> \n" +
"> <font color='comment'>报警时间:%s</font> \n" +
"> <font color='comment'>接收人:%s</font> \n" +
"> <font color='comment'>trace 信息:%s</font> \n" +
"> <font color='info'>报警间隔:%ss</font> \n" +
"> <font color='comment'>扩展信息:%s</font> \n";

/**
* receivers only supports userid, view more, see <a href="https://developer.work.weixin.qq.com/document/path/91770">more</a>.
*/
public static final String WECHAT_ALARM_TEMPLATE =
WECHAT_ALARM_TEMPLATE_PREFIX +
"> <font color='corePoolSize'>核心线程数:%s</font> \n" +
"> <font color='maximumPoolSize'>最大线程数:%s</font> \n" +
"> <font color='poolSize'>当前线程数:%s</font> \n" +
Expand All @@ -64,12 +78,7 @@ private WechatNotifyConst() { }
"> <font color='rejectCount'>总拒绝任务数量:%s</font> \n" +
"> <font color='runTimeoutCount'>总执行超时任务数量:%s</font> \n" +
"> <font color='queueTimeoutCount'>总等待超时任务数量:%s</font> \n" +
"> <font color='comment'>上次报警时间:%s</font> \n" +
"> <font color='comment'>报警时间:%s</font> \n" +
"> <font color='comment'>接收人:%s</font> \n" +
"> <font color='comment'>trace 信息:%s</font> \n" +
"> <font color='info'>报警间隔:%ss</font> \n" +
"> <font color='comment'>扩展信息:%s</font> \n";
WECHAT_ALARM_TEMPLATE_SUFFIX;

public static final String WECHAT_CHANGE_NOTICE_TEMPLATE =
"<font color='info'>【通知】</font> 动态线程池参数变更 \n" +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,12 @@ public enum NotifyItemEnum {
/**
* Task queue wait timeout alarm.
*/
QUEUE_TIMEOUT("queue_timeout", "");
QUEUE_TIMEOUT("queue_timeout", ""),

/**
* Pin timeout alarm.
*/
PIN_TIMEOUT("pin_timeout", "");

private final String value;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


/**
* ExecutorStats related
Expand Down Expand Up @@ -74,7 +77,12 @@ public class ExecutorStats extends Metrics {
/**
* 是否为虚拟线程执行器
*/
private boolean isVirtualExecutor;
private boolean isVirtualThreadExecutor;

/**
* 拓展字段
*/
private final Map<String, Double> extMap = new ConcurrentHashMap<>(2);

/**
* 空闲时间 (ms)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public static List<NotifyItem> mergeAllNotifyItems(List<NotifyItem> source) {
val defaultItems = getAllNotifyItems().stream()
.filter(t -> !StringUtil.containsIgnoreCase(t.getType(), configuredTypes))
.collect(Collectors.toList());
List<NotifyItem> notifyItems = new ArrayList<>(6);
List<NotifyItem> notifyItems = new ArrayList<>(7);
notifyItems.addAll(defaultItems);
notifyItems.addAll(source);
return notifyItems;
Expand All @@ -102,11 +102,16 @@ public static List<NotifyItem> getAllNotifyItems() {
queueTimeoutNotify.setType(NotifyItemEnum.QUEUE_TIMEOUT.getValue());
queueTimeoutNotify.setThreshold(10);

List<NotifyItem> notifyItems = new ArrayList<>(6);
NotifyItem pinTimeoutNotify = new NotifyItem();
pinTimeoutNotify.setType(NotifyItemEnum.PIN_TIMEOUT.getValue());
pinTimeoutNotify.setThreshold(10);

List<NotifyItem> notifyItems = new ArrayList<>(7);
notifyItems.addAll(getSimpleNotifyItems());
notifyItems.add(rejectNotify);
notifyItems.add(runTimeoutNotify);
notifyItems.add(queueTimeoutNotify);
notifyItems.add(pinTimeoutNotify);

return notifyItems;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ private static void tryPrintError(Runnable r, Throwable t) {
if (r instanceof FutureTask) {
try {
FutureTask<?> future = (FutureTask<?>) r;
if (future.isDone()) {
if (future.isDone() && !future.isCancelled()) {
future.get();
}
} catch (InterruptedException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@

package org.dromara.dynamictp.common.util;

import jdk.jfr.consumer.RecordedFrame;
import jdk.jfr.consumer.RecordedStackTrace;
import org.apache.commons.collections4.CollectionUtils;

import java.util.Collection;
import java.util.stream.Collectors;

/**
* StringUtil related
Expand Down Expand Up @@ -64,4 +67,22 @@ public static boolean containsIgnoreCase(CharSequence str, CharSequence testStr)
}
return str.toString().toLowerCase().contains(testStr.toString().toLowerCase());
}

public static String formatJfrStackTrace(RecordedStackTrace stackTrace, int maxDepth) {
if (stackTrace == null) {
return "\t<not available>";
}
String formatted = "\t" + stackTrace.getFrames().stream()
.limit(maxDepth)
.map(StringUtil::formatStackTraceFrame)
.collect(Collectors.joining("\n\t"));
if (maxDepth < stackTrace.getFrames().size()) {
return formatted + "\n\t(...)";
}
return formatted;
}

private static String formatStackTraceFrame(RecordedFrame frame) {
return frame.getMethod().getType().getName() + "#" + frame.getMethod().getName() + ": " + frame.getLineNumber();
}
}
Loading