com.ideaaedi.commonds.monitor.WatchTimeUtil Maven / Gradle / Ivy
package com.ideaaedi.commonds.monitor;
import com.alibaba.fastjson2.JSON;
import org.apache.commons.lang3.StringUtils;
import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
/**
* 耗时统计工具
*
* @author JustryDeng
* @since 2100.10.7.LTS17
*/
public final class WatchTimeUtil {
/** 初始化标识 */
private static final ThreadLocal initThreadLocal = ThreadLocal.withInitial(() -> false);
/** 存放执行中任务的ThreadLocal */
private static final ThreadLocal> runningTaskThreadLocal = new ThreadLocal<>();
/** 存放已结束任务的ThreadLocal */
private static final ThreadLocal> endTaskThreadLocal = new ThreadLocal<>();
/** 存放最大序号的ThreadLocal */
private static final ThreadLocal maxTaskNoThreadLocal = new ThreadLocal<>();
/**
* 开始统计
*
* 若计时器尚未初始化,则会静默忽略当前操作
*
*
* @param taskName 任务名
*/
public static void start(String taskName) {
if (!initThreadLocal.get()) {
return;
}
TaskInfo taskInfo = new TaskInfo();
String no = Manager.nextNo();
taskInfo.setTaskNo(no);
taskInfo.setTaskName(taskName);
taskInfo.setStartTime(System.nanoTime());
runningTaskThreadLocal.get().addFirst(taskInfo);
maxTaskNoThreadLocal.set(no);
}
/**
* 结束统计
*
* 若计时器尚未初始化,则会静默忽略当前操作
*
*/
public static void stop() {
if (!initThreadLocal.get()) {
return;
}
LinkedList runningTaskDeque = runningTaskThreadLocal.get();
if (runningTaskDeque.size() == 0) {
return;
}
TaskInfo taskInfo = runningTaskDeque.pollFirst();
taskInfo.setEndTime(System.nanoTime());
endTaskThreadLocal.get().addLast(taskInfo);
}
/**
* 执行
*
* @param taskName 任务名
* @param function 业务逻辑块
* @param param 参数
*
* @return 逻辑执行结果
*/
public static R watch(@Nonnull String taskName, Function
function, P param) {
try {
start(taskName);
return function.apply(param);
} finally {
stop();
}
}
/**
* 执行
*
* @param taskName 任务名
* @param function 业务逻辑块
*
* @return 执行结果
*/
public static R watch(@Nonnull String taskName, InnerNoArgFunction function) {
try {
start(taskName);
return function.apply();
} finally {
stop();
}
}
/**
* 执行
*
* @param taskName 任务名
* @param consumer 业务逻辑块
* @param param 参数
*/
public static void voidWatch(@Nonnull String taskName, Consumer
consumer, P param) {
try {
start(taskName);
consumer.accept(param);
} finally {
stop();
}
}
/**
* 执行
*
* @param taskName 任务名
* @param consumer 业务逻辑块
*/
public static void voidWatch(@Nonnull String taskName, InnerNoArgConsumer consumer) {
try {
start(taskName);
consumer.accept();
} finally {
stop();
}
}
/**
* 耗时信息
*/
public static String prettyResult() {
if (!initThreadLocal.get()) {
throw new IllegalStateException("Not initialized yet. You could do it by 'TimeWatchUtil.Manager.init()', "
+ "and don't forget to clear him last by 'TimeWatchUtil.Manager.clear()'");
}
if (!Manager.currIsEnd()) {
throw new IllegalStateException("There are also running tasks. " + Manager.getIngTaskList());
}
List endTaskList = Manager.getEndTaskList();
return Manager.prettyResult(endTaskList);
}
/**
* 耗时信息
*/
public static String result() {
if (!initThreadLocal.get()) {
throw new IllegalStateException("Not initialized yet. You could do it by 'TimeWatchUtil.Manager.init()', "
+ "and don't forget to clear him last by 'TimeWatchUtil.Manager.clear()'");
}
if (!Manager.currIsEnd()) {
throw new IllegalStateException("There are also running tasks. " + Manager.getIngTaskList());
}
List endTaskList = Manager.getEndTaskList();
return Manager.result(endTaskList);
}
/**
* 管理器
*/
public static class Manager {
/**
* 初始化
*/
public static void init() {
if (initThreadLocal.get()) {
throw new IllegalStateException("It has already been initialized, please do not initialize it repeatedly.");
}
initThreadLocal.set(true);
runningTaskThreadLocal.set(new LinkedList<>());
endTaskThreadLocal.set(new LinkedList<>());
}
/**
* 初始化
*/
public static void initSilence() {
if (initThreadLocal.get()) {
return;
}
initThreadLocal.set(true);
runningTaskThreadLocal.set(new LinkedList<>());
endTaskThreadLocal.set(new LinkedList<>());
}
/**
* 所有耗时统计任务当前是否都已结束
*/
public static boolean currIsEnd() {
LinkedList list = runningTaskThreadLocal.get();
return list == null || list.size() == 0;
}
/**
* 获取已完成的任务集合
*/
public static List getEndTaskList() {
return new ArrayList<>(endTaskThreadLocal.get());
}
/**
* 获取进行中的任务集合
*/
public static List getIngTaskList() {
return new ArrayList<>(runningTaskThreadLocal.get());
}
/**
* 清空
*/
public static void clear() {
runningTaskThreadLocal.remove();
endTaskThreadLocal.remove();
maxTaskNoThreadLocal.remove();
initThreadLocal.remove();
}
/**
* 获取下一个执行序号
*/
public static String nextNo() {
TaskInfo taskInfo = runningTaskThreadLocal.get().peekFirst();
String maxNo = maxTaskNoThreadLocal.get();
String nextNo;
if (taskInfo == null) {
if (maxNo == null) {
nextNo = "1";
} else {
nextNo = String.valueOf(Long.parseLong(maxNo.split("\\.")[0]) + 1);
}
} else {
Objects.requireNonNull(maxNo, "maxNo should not be null.");
String parentNo = taskInfo.getTaskNo();
String[] parentNoArr = parentNo.split("\\.");
String[] maxNoArr = maxNo.split("\\.");
long subNo;
if (maxNoArr.length > parentNoArr.length) {
subNo = Long.parseLong(maxNoArr[parentNoArr.length]) + 1;
} else {
subNo = 1;
}
nextNo = parentNo + "." + subNo;
}
return nextNo;
}
/**
* 按照任务序号排序
*/
public static void sortByTaskNo(List taskInfoList) {
if (taskInfoList == null) {
return;
}
taskInfoList.sort(
(x, y) -> {
String xNo = x.getTaskNo();
String yNo = y.getTaskNo();
String[] xNoArr = xNo.split("\\.");
String[] yNoArr = yNo.split("\\.");
int minLength = Math.min(xNoArr.length, yNoArr.length);
for (int i = 0; i < minLength; i++) {
long xVal = Long.parseLong(xNoArr[i]);
long yVal = Long.parseLong(yNoArr[i]);
if (xVal < yVal) {
return -1;
}
if (xVal > yVal) {
return 1;
}
}
return Integer.compare(xNoArr.length, yNoArr.length);
}
);
}
/**
* 耗时信息
*/
public static String prettyResult(@Nonnull List endTaskList) {
StringBuilder sb = new StringBuilder();
int size = endTaskList.size();
if (size == 0) {
sb.append("no tasks time info.");
return sb.toString();
}
if (size == 1) {
WatchTimeUtil.TaskInfo taskInfo = endTaskList.get(0);
long consumeMilli = (taskInfo.getEndTime() - taskInfo.getStartTime()) / 1000000;
return consumeMilli + "ms @ " + taskInfo.getTaskName();
}
WatchTimeUtil.Manager.sortByTaskNo(endTaskList);
WatchTimeUtil.TaskInfo preTask = null;
for (WatchTimeUtil.TaskInfo taskInfo : endTaskList) {
String taskNo = taskInfo.getTaskNo();
long startTime = taskInfo.getStartTime();
long endTime = taskInfo.getEndTime();
String[] noArr = taskNo.split("\\.");
sb.append("\n");
sb.append(StringUtils.rightPad("|--".repeat(Math.max(0, noArr.length - 1)) + taskNo, 34, "."));
long consumeMilli = (endTime - startTime) / 1000000;
// 计算和前一个任务的间隔
Long intervalMilli = null;
if (preTask != null) {
String preTaskNo = preTask.getTaskNo();
long preStartTime = preTask.getStartTime();
long preEndTime = preTask.getEndTime();
if (preTaskNo.length() > taskNo.length()) {
// 前一任务是当前任务的子任务
intervalMilli = (endTime - preEndTime) / 1000000;
} else if (taskNo.startsWith(preTaskNo)) {
// 前一任务是当前任务的父任务
intervalMilli = (startTime - preStartTime) / 1000000;
} else {
// 同级任务
intervalMilli = (startTime - preEndTime) / 1000000;
}
}
sb.append(StringUtils.leftPad(consumeMilli + "", 6, "."))
.append("ms");
// 两个任务之间的间隔时间
if (intervalMilli != null) {
sb.append("(").append(StringUtils.leftPad(intervalMilli + "ms) @ ", 11, " "));
} else {
sb.append(StringUtils.leftPad(" @ ", 12, " "));
}
sb.append(taskInfo.getTaskName());
preTask = taskInfo;
}
return sb.toString();
}
/**
* 耗时信息
*/
public static String result(@Nonnull List endTaskList) {
int size = endTaskList.size();
if (size == 0) {
return "no tasks time info.";
}
if (size == 1) {
TaskInfo taskInfo = endTaskList.get(0);
long consumeMilli = (taskInfo.getEndTime() - taskInfo.getStartTime()) / 1000000;
return consumeMilli + "ms @ " + taskInfo.getTaskName();
}
Manager.sortByTaskNo(endTaskList);
List list = new ArrayList<>();
WatchTimeUtil.TaskInfo preTask = null;
for (TaskInfo taskInfo : endTaskList) {
StringBuilder sb = new StringBuilder();
String taskNo = taskInfo.getTaskNo();
long startTime = taskInfo.getStartTime();
long endTime = taskInfo.getEndTime();
sb.append("taskNo: ");
sb.append(taskNo);
sb.append(", ");
long consumeMilli = (taskInfo.getEndTime() - taskInfo.getStartTime()) / 1000000;
// 计算和前一个任务的间隔
Long intervalMilli = null;
if (preTask != null) {
String preTaskNo = preTask.getTaskNo();
long preStartTime = preTask.getStartTime();
long preEndTime = preTask.getEndTime();
if (preTaskNo.length() > taskNo.length()) {
// 前一任务是当前任务的子任务
intervalMilli = (endTime - preEndTime) / 1000000;
} else if (taskNo.startsWith(preTaskNo)) {
// 前一任务是当前任务的父任务
intervalMilli = (startTime - preStartTime) / 1000000;
} else {
// 同级任务
intervalMilli = (startTime - preEndTime) / 1000000;
}
}
sb.append("consumeTime: ");
sb.append(consumeMilli).append("ms, ");
if (intervalMilli != null) {
sb.append("intervalTime: ").append(intervalMilli).append("ms, ");
}
sb.append("taskName: ")
.append(taskInfo.getTaskName());
list.add(sb.toString());
preTask = taskInfo;
}
return JSON.toJSONString(list);
}
}
/**
* 任务信息
*/
public static class TaskInfo {
/** 执行序号(格式形如:xxx.xxx.xxx) */
private String taskNo;
/** 任务名 */
private String taskName;
/** 开始时间(纳秒) */
private long startTime;
/** 结束时间(纳秒) */
private long endTime;
public String getTaskNo() {
return taskNo;
}
public void setTaskNo(String taskNo) {
this.taskNo = taskNo;
}
public String getTaskName() {
return taskName;
}
public void setTaskName(String taskName) {
this.taskName = taskName;
}
public long getStartTime() {
return startTime;
}
public void setStartTime(long startTime) {
this.startTime = startTime;
}
public long getEndTime() {
return endTime;
}
public void setEndTime(long endTime) {
this.endTime = endTime;
}
@Override
public String toString() {
return "TaskInfo{" +
"taskNo='" + taskNo + '\'' +
", taskName='" + taskName + '\'' +
", startTime=" + startTime +
", endTime=" + endTime +
'}';
}
}
/**
* (non-javadoc)
*/
@FunctionalInterface
public interface InnerNoArgFunction {
R apply();
}
/**
* (non-javadoc)
*/
@FunctionalInterface
public interface InnerNoArgConsumer {
void accept();
}
}