初始化仓库
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
package xtools.boot.log;
|
||||
|
||||
import org.springframework.context.annotation.Import;
|
||||
import xtools.boot.core.utils.ModuleLoadUtils;
|
||||
import xtools.boot.log.selector.BootLogImportSelector;
|
||||
|
||||
/**
|
||||
* <p>Title : BootLogConfiguration</p>
|
||||
* <p>Description : BootLogConfiguration</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 5.0.0
|
||||
* @date : 2026/01/01 09:30
|
||||
*/
|
||||
@Import(BootLogImportSelector.class)
|
||||
public class BootLogConfiguration {
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
*/
|
||||
public BootLogConfiguration() {
|
||||
ModuleLoadUtils.loadSuccess(BootLogConfiguration.class);
|
||||
}
|
||||
|
||||
}
|
||||
380
xtools-boot-log/src/main/java/xtools/boot/log/LogBus.java
Normal file
380
xtools-boot-log/src/main/java/xtools/boot/log/LogBus.java
Normal file
@@ -0,0 +1,380 @@
|
||||
package xtools.boot.log;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.alibaba.fastjson2.JSONWriter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import xtools.base.config.BaseParams;
|
||||
import xtools.base.exception.CommonException;
|
||||
import xtools.base.exception.ExceptionUtils;
|
||||
import xtools.boot.api.enums.ThreadType;
|
||||
import xtools.boot.api.model.dto.log.LogTrack;
|
||||
import xtools.boot.core.utils.SpringContextUtils;
|
||||
import xtools.boot.log.config.LogBusConfig;
|
||||
import xtools.boot.log.config.RunInfoConfig;
|
||||
import xtools.boot.log.holder.LogTrackHolder;
|
||||
import xtools.boot.log.interfaces.LogBusInterface;
|
||||
import xtools.boot.log.interfaces.LogBusType;
|
||||
import xtools.boot.log.model.dto.LogBody;
|
||||
import xtools.boot.log.model.dto.RunInfo;
|
||||
import xtools.core.ArrUtils;
|
||||
import xtools.core.CollectionUtils;
|
||||
import xtools.core.StringUtils;
|
||||
import xtools.core.enums.LogLevel;
|
||||
import xtools.core.enums.TimePattern;
|
||||
import xtools.core.sys.SysBaseInfoUtils;
|
||||
import xtools.core.time.InstantUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
/**
|
||||
* <p>Title : LogBus</p>
|
||||
* <p>Description : LogBus</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 5.0.0
|
||||
* @date : 2026/2/3 09:33
|
||||
*/
|
||||
@Slf4j
|
||||
public class LogBus implements BaseParams {
|
||||
|
||||
/**
|
||||
* 运行信息
|
||||
*/
|
||||
private static RunInfo runInfo;
|
||||
|
||||
/**
|
||||
* 日志体
|
||||
*/
|
||||
private final LogBody logBody;
|
||||
|
||||
/**
|
||||
* 异常信息
|
||||
*/
|
||||
private Throwable throwable;
|
||||
|
||||
/**
|
||||
* 是否在控制台打印
|
||||
*/
|
||||
private Boolean print;
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
*
|
||||
* @param level 日志级别
|
||||
* @param type 日志类型
|
||||
* @param logTrack 日志信息
|
||||
*/
|
||||
private LogBus(LogLevel level, LogBusType type, LogTrack logTrack) {
|
||||
// 参数处理
|
||||
if (Objects.isNull(level)) {
|
||||
level = LogLevel.INFO;
|
||||
}
|
||||
if (Objects.isNull(logTrack)) {
|
||||
logTrack = LogTrackHolder.get();
|
||||
}
|
||||
// 构建日志信息
|
||||
logBody = new LogBody();
|
||||
logBody.setLevel(level);
|
||||
logBody.setType(type.desc());
|
||||
logBody.setLogTrack(logTrack);
|
||||
logBody.setRunInfo(getRunInfo());
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*
|
||||
* @param type 日志类型
|
||||
* @return 当前对象
|
||||
*/
|
||||
public static LogBus init(LogBusType type) {
|
||||
return new LogBus(null, type, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*
|
||||
* @param level 日志级别
|
||||
* @param type 日志类型
|
||||
* @return 当前对象
|
||||
*/
|
||||
public static LogBus init(LogLevel level, LogBusType type) {
|
||||
return new LogBus(level, type, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*
|
||||
* @param level 日志级别
|
||||
* @param type 日志类型
|
||||
* @param logTrack 日志信息
|
||||
* @return 当前对象
|
||||
*/
|
||||
public static LogBus init(LogLevel level, LogBusType type, LogTrack logTrack) {
|
||||
return new LogBus(level, type, logTrack);
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化日志
|
||||
*
|
||||
* @param logBody 日志信息
|
||||
* @return 日志信息
|
||||
*/
|
||||
private static StringBuilder fmtLog(LogBody logBody) {
|
||||
// 日志标题
|
||||
String title = logBody.getTitle();
|
||||
if (StringUtils.isBlank(title)) {
|
||||
title = "日志信息";
|
||||
}
|
||||
LogTrack logTrack = logBody.getLogTrack();
|
||||
// 日志时间
|
||||
String time = InstantUtils.format(InstantUtils.from(logTrack.time()), TimePattern.ALL);
|
||||
// 线程类型
|
||||
ThreadType threadType = logTrack.type();
|
||||
// 堆栈信息
|
||||
JSONArray stackTraceInfo = logBody.getStackTrace();
|
||||
// 日志数据
|
||||
JSONObject data = logBody.getLogData();
|
||||
// 构建打印日志
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(CP_NEWLINE);
|
||||
sb.append("┏━━━ ").append(title).append(" Start ━━━").append(CP_NEWLINE);
|
||||
sb.append("┠ ").append("日志ID: ").append(logTrack.id()).append(CP_NEWLINE);
|
||||
sb.append("┠ ").append("日志时间: ").append(time).append(CP_NEWLINE);
|
||||
sb.append("┠ ").append("追踪ID: ").append(logTrack.traceId()).append(CP_NEWLINE);
|
||||
sb.append("┠ ").append("线程类型: ").append(threadType.desc()).append(CP_NEWLINE);
|
||||
if (!ThreadType.MAIN.equals(threadType)) {
|
||||
sb.append("┠ ").append("父线程ID: ").append(logTrack.parentId()).append(CP_NEWLINE);
|
||||
}
|
||||
sb.append("┠ ").append("日志级别: ").append(logBody.getLevel().level()).append(CP_NEWLINE);
|
||||
sb.append("┠ ").append("日志类型: ").append(logBody.getType()).append(CP_NEWLINE);
|
||||
sb.append("┠ ").append("运行环境: ").append(CP_NEWLINE).append(JSONObject.toJSONString(logBody.getRunInfo(), JSONWriter.Feature.PrettyFormat)).append(CP_NEWLINE);
|
||||
if (CollectionUtils.isNotEmpty(stackTraceInfo)) {
|
||||
sb.append("┠ ").append("堆栈信息: ").append(CP_NEWLINE).append(stackTraceInfo.toJSONString(JSONWriter.Feature.PrettyFormat)).append(CP_NEWLINE);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(data)) {
|
||||
sb.append("┠ ").append("日志数据: ").append(CP_NEWLINE).append(data.toJSONString(JSONWriter.Feature.PrettyFormat)).append(CP_NEWLINE);
|
||||
}
|
||||
sb.append("┗━━━ ").append(title).append(" End ━━━").append(CP_NEWLINE);
|
||||
return sb;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化堆栈信息
|
||||
*
|
||||
* @param stackTraceInfo 堆栈信息
|
||||
* @param includeStackTrace 包含的堆栈信息(开始的包名)
|
||||
* @return 堆栈信息
|
||||
*/
|
||||
private static JSONArray fmtStackTrace(StackTraceElement[] stackTraceInfo, List<String> includeStackTrace) {
|
||||
// 获取当前线程的调用栈
|
||||
if (ArrUtils.isEmpty(stackTraceInfo)) {
|
||||
return null;
|
||||
}
|
||||
JSONArray result = new JSONArray();
|
||||
if (CollectionUtils.isEmpty(includeStackTrace)) {
|
||||
// 获取所有堆栈数据
|
||||
Arrays.stream(stackTraceInfo).toList().forEach((item) -> result.add(item.toString()));
|
||||
return result;
|
||||
}
|
||||
|
||||
// 获取关于本工程堆栈信息
|
||||
for (StackTraceElement item : stackTraceInfo) {
|
||||
String className = item.getClassName();
|
||||
|
||||
boolean flag = false;
|
||||
for (String include : includeStackTrace) {
|
||||
if (className.startsWith(include)) {
|
||||
flag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (flag) {
|
||||
result.add(item.toString());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 日志标题
|
||||
*
|
||||
* @param title 标题
|
||||
* @return 当前对象
|
||||
*/
|
||||
public LogBus title(String title) {
|
||||
if (StringUtils.isNotBlank(title)) {
|
||||
logBody.setTitle(title);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否打印
|
||||
*
|
||||
* @param print 是否打印
|
||||
* @return 当前对象
|
||||
*/
|
||||
public LogBus print(boolean print) {
|
||||
this.print = print;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置日志信息
|
||||
*
|
||||
* @param log 日志信息
|
||||
* @return 当前对象
|
||||
*/
|
||||
public LogBus data(final Object log) {
|
||||
if (Objects.isNull(log)) {
|
||||
return this;
|
||||
}
|
||||
if (log instanceof JSONObject jsonLog) {
|
||||
logBody.setLogData(jsonLog);
|
||||
} else {
|
||||
logBody.setLogData(JSONObject.from(log));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置异常信息
|
||||
*
|
||||
* @param throwable 异常信息
|
||||
* @return 当前对象
|
||||
*/
|
||||
public LogBus error(Throwable throwable) {
|
||||
this.throwable = throwable;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存日志
|
||||
*/
|
||||
public void save() {
|
||||
// 获取堆栈信息
|
||||
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
|
||||
ExecutorService service = Executors.newVirtualThreadPerTaskExecutor();
|
||||
try {
|
||||
// 创建子线程,并异步提交
|
||||
CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
doSave(logBody, throwable, stackTrace);
|
||||
} catch (Exception e) {
|
||||
log.error("保存日志异常", e);
|
||||
}
|
||||
}, service);
|
||||
} finally {
|
||||
// 关闭线程池
|
||||
service.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取运行信息
|
||||
*
|
||||
* @return 运行信息
|
||||
*/
|
||||
private RunInfo getRunInfo() {
|
||||
if (runInfo != null) {
|
||||
return runInfo;
|
||||
}
|
||||
RunInfoConfig sysRunInfo = SpringContextUtils.getBean(RunInfoConfig.class);
|
||||
RunInfo info = new RunInfo();
|
||||
info.setLocalIp(SysBaseInfoUtils.getLocalIp());
|
||||
info.setAppName(sysRunInfo.getName());
|
||||
info.setPort(sysRunInfo.getPort());
|
||||
runInfo = info;
|
||||
return runInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行日志发送
|
||||
*
|
||||
* @param logBody 日志内容
|
||||
* @param throwable 异常
|
||||
* @param stackTrace 堆栈信息
|
||||
*/
|
||||
private void doSave(LogBody logBody, Throwable throwable, StackTraceElement[] stackTrace) {
|
||||
// 获取配置文件
|
||||
LogBusConfig config = SpringContextUtils.getBean(LogBusConfig.class);
|
||||
|
||||
// 计算日志级
|
||||
boolean geWarn = logBody.getLevel().code() > LogLevel.INFO.code();
|
||||
// 处理堆栈信息
|
||||
logBody.setStackTrace(fmtStackTrace(stackTrace, geWarn ? null : config.getIncludeStackTrace()));
|
||||
|
||||
// 是否打印日志
|
||||
if (geWarn || (Objects.nonNull(print) ? print : config.getPrint().booleanValue())) {
|
||||
printLog(logBody);
|
||||
}
|
||||
// 异常日志不做忽略
|
||||
if (!geWarn) {
|
||||
// 不保存日志
|
||||
if (!logBody.getLogTrack().save()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// 处理日志内容超长
|
||||
JSONObject data = logBody.getLogData();
|
||||
if (CollectionUtils.isNotEmpty(data)) {
|
||||
Integer logDataItemMax = config.getLogDataMaxLength();
|
||||
if (!Objects.equals(logDataItemMax, CP_NEGATIVE1)) {
|
||||
String dataStr = data.toString();
|
||||
if (dataStr.length() > logDataItemMax) {
|
||||
JSONObject newLogData = JSONObject.of(
|
||||
"msg", "日志内容超长",
|
||||
"log", dataStr.substring(CP_NUM0, logDataItemMax) + "..."
|
||||
);
|
||||
logBody.setLogData(newLogData);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 处理异常信息
|
||||
if (Objects.nonNull(throwable)) {
|
||||
if (throwable instanceof CommonException commonException) {
|
||||
String message = commonException.getMessage();
|
||||
Throwable cause = commonException.getCause();
|
||||
String errMsg = ExceptionUtils.getErrMsg(Objects.nonNull(cause) ? cause : throwable);
|
||||
logBody.setErr(message + CP_NEWLINE + errMsg);
|
||||
} else {
|
||||
logBody.setErr(ExceptionUtils.getErrMsg(throwable));
|
||||
}
|
||||
}
|
||||
|
||||
// 保存日志信息
|
||||
Collection<LogBusInterface> beanList = SpringContextUtils.getBeanList(LogBusInterface.class);
|
||||
if (CollectionUtils.isNotEmpty(beanList)) {
|
||||
beanList.forEach(item -> item.save(logBody));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印日志信息
|
||||
*
|
||||
* @param logBody 日志信息
|
||||
*/
|
||||
private void printLog(LogBody logBody) {
|
||||
// 格式化日志
|
||||
StringBuilder logContext = fmtLog(logBody);
|
||||
// 异常数据
|
||||
if (Objects.isNull(throwable)) {
|
||||
logContext.append(CP_NEWLINE);
|
||||
log.info(logContext.toString());
|
||||
} else {
|
||||
logContext.append("━━━━ ↓↓↓ exception ↓↓↓ ━━━━").append(CP_NEWLINE);
|
||||
log.error(logContext.toString(), throwable);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package xtools.boot.log.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>Title : LogBusConfig</p>
|
||||
* <p>Description : LogBusConfig</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 5.0.0
|
||||
* @date : 2026/2/3 15:07
|
||||
*/
|
||||
@Data
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "sys.log.bus")
|
||||
public class LogBusConfig {
|
||||
|
||||
/**
|
||||
* 是否打印日志
|
||||
*/
|
||||
private Boolean print = false;
|
||||
|
||||
/**
|
||||
* 包含的堆栈信息(开始的包名)
|
||||
*/
|
||||
private List<String> includeStackTrace = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 日志项最大长度
|
||||
*/
|
||||
private Integer logDataMaxLength = -1;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package xtools.boot.log.config;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* <p>Title : RunInfoConfig</p>
|
||||
* <p>Description : RunInfoConfig</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 5.0.0
|
||||
* @date : 2026/2/3 14:17
|
||||
*/
|
||||
@Getter
|
||||
@Component
|
||||
public class RunInfoConfig {
|
||||
|
||||
/**
|
||||
* 应用名称
|
||||
*/
|
||||
@Value("${spring.application.name:xtools-boot}")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 应用端口
|
||||
*/
|
||||
@Value("${server.port:8080}")
|
||||
private int port;
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package xtools.boot.log.enums;
|
||||
|
||||
import xtools.boot.api.enums.BaseEnum;
|
||||
import xtools.boot.log.interfaces.LogBusType;
|
||||
|
||||
/**
|
||||
* <p>Title : LogBusBaseType</p>
|
||||
* <p>Description : LogBusBaseType</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 5.0.0
|
||||
* @date : 2026/2/3 11:26
|
||||
*/
|
||||
public enum LogBusBaseType implements LogBusType {
|
||||
|
||||
// 其他
|
||||
OTHER(0, "其他"),
|
||||
// THREAD
|
||||
VIRTUAL_THREAD(1, "虚拟线程"),
|
||||
// Redis
|
||||
REDIS(10, "Redis"),
|
||||
// MyBatis
|
||||
MYBATIS(20, "MyBatis"),
|
||||
// MQ
|
||||
MQ(30, "MQ"),
|
||||
// Elasticsearch
|
||||
ELASTICSEARCH(40, "Elasticsearch"),
|
||||
// Sentinel
|
||||
SENTINEL(50, "Sentinel"),
|
||||
// Http
|
||||
HTTP(80, "Http工具"),
|
||||
HTTP_REQUEST(81, "Http请求"),
|
||||
HTTP_RESPONSE(82, "Http响应"),
|
||||
// Cloud
|
||||
CLOUD_REQUEST(85, "Cloud请求"),
|
||||
CLOUD_RESPONSE(86, "Cloud响应"),
|
||||
// Controller
|
||||
CONTROLLER(90, "Controller"),
|
||||
// Task
|
||||
TASK(91, "Task"),
|
||||
// Job
|
||||
JOB(92, "Job"),
|
||||
// Risk
|
||||
RISK(93, "Risk"),
|
||||
;
|
||||
|
||||
/**
|
||||
* 编码
|
||||
**/
|
||||
private final int code;
|
||||
|
||||
/**
|
||||
* 说明
|
||||
**/
|
||||
private final String desc;
|
||||
|
||||
/**
|
||||
* 初始化方法
|
||||
*
|
||||
* @param code Code
|
||||
* @param desc 说明
|
||||
*/
|
||||
LogBusBaseType(int code, String desc) {
|
||||
this.code = code;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有枚举
|
||||
*
|
||||
* @return 所有枚举
|
||||
*/
|
||||
@Override
|
||||
public BaseEnum[] all() {
|
||||
return values();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取枚举编码
|
||||
*
|
||||
* @return 枚举编码
|
||||
*/
|
||||
@Override
|
||||
public int code() {
|
||||
return code;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取枚举说明
|
||||
*
|
||||
* @return 枚举说明
|
||||
*/
|
||||
@Override
|
||||
public String desc() {
|
||||
return desc;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
package xtools.boot.log.holder;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.alibaba.fastjson2.JSONWriter;
|
||||
import xtools.base.exception.CommonException;
|
||||
import xtools.boot.api.enums.BootError;
|
||||
import xtools.boot.api.enums.ThreadType;
|
||||
import xtools.boot.api.model.dto.log.HolderLogTrack;
|
||||
import xtools.boot.api.model.dto.log.LogTrack;
|
||||
import xtools.core.UuidUtils;
|
||||
import xtools.core.encrypt.Base64Utils;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Instant;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* <p>Title : LogTrackHolder</p>
|
||||
* <p>Description : LogTrackHolder</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 5.0.0
|
||||
* @date : 2026/1/6 16:36
|
||||
*/
|
||||
public class LogTrackHolder {
|
||||
|
||||
/**
|
||||
* 日志追踪信息
|
||||
*/
|
||||
private static final ScopedValue<HolderLogTrack> LOG_TRACK_INFO = ScopedValue.newInstance();
|
||||
|
||||
/**
|
||||
* 获取日志追踪保持信息
|
||||
*
|
||||
* @return 日志追踪保持信息
|
||||
*/
|
||||
public static ScopedValue<HolderLogTrack> getScoped() {
|
||||
return LOG_TRACK_INFO;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 新建主线程日志追踪信息
|
||||
*
|
||||
* @return 日志追踪信息
|
||||
*/
|
||||
public static HolderLogTrack newMain() {
|
||||
ThreadType main = ThreadType.MAIN;
|
||||
return new HolderLogTrack(UuidUtils.get(), main.name(), main);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新建线程日志追踪信息
|
||||
*
|
||||
* @param mainLogTrack 主线程日志追踪信息
|
||||
* @return 日志追踪信息
|
||||
*/
|
||||
public static HolderLogTrack newThread(LogTrack mainLogTrack) {
|
||||
HolderLogTrack holderLogTrack = new HolderLogTrack(mainLogTrack.traceId(), mainLogTrack.id(), ThreadType.THREAD);
|
||||
holderLogTrack.setSave(mainLogTrack.save());
|
||||
return holderLogTrack;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新建 Holder 日志追踪信息
|
||||
*
|
||||
* @param logTrack 日志追踪信息
|
||||
* @return 日志追踪信息
|
||||
*/
|
||||
public static HolderLogTrack newHolderLogTrack(LogTrack logTrack) {
|
||||
HolderLogTrack holderLogTrack = new HolderLogTrack(logTrack.traceId(), logTrack.parentId(), logTrack.type(), logTrack.index());
|
||||
holderLogTrack.setSave(logTrack.save());
|
||||
return holderLogTrack;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新建 Holder 日志追踪信息
|
||||
*
|
||||
* @param base64 日志追踪信息
|
||||
* @return 日志追踪信息
|
||||
*/
|
||||
public static HolderLogTrack newByBase64(String base64) {
|
||||
String log = Base64Utils.decodeToStr(base64.getBytes(StandardCharsets.UTF_8));
|
||||
LogTrack logTrack = JSONObject.parseObject(log, LogTrack.class);
|
||||
return newThread(logTrack);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取日志追踪信息
|
||||
*
|
||||
* @return 日志追踪信息
|
||||
*/
|
||||
public static LogTrack get() {
|
||||
Instant now = Instant.now();
|
||||
HolderLogTrack holder = getHolder();
|
||||
holder.getCount().getAndIncrement();
|
||||
return new LogTrack(
|
||||
UuidUtils.get(),
|
||||
now.toEpochMilli(),
|
||||
holder.getTraceId(),
|
||||
holder.getParentId(),
|
||||
holder.getType(),
|
||||
holder.getCount().get(),
|
||||
holder.isSave()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取日志追踪信息
|
||||
*
|
||||
* @return 日志追踪信息
|
||||
*/
|
||||
public static LogTrack getDefNull() {
|
||||
Instant now = Instant.now();
|
||||
HolderLogTrack holder = getHolderDefNull();
|
||||
if (Objects.isNull(holder)) {
|
||||
return null;
|
||||
}
|
||||
holder.getCount().getAndIncrement();
|
||||
return new LogTrack(
|
||||
UuidUtils.get(),
|
||||
now.toEpochMilli(),
|
||||
holder.getTraceId(),
|
||||
holder.getParentId(),
|
||||
holder.getType(),
|
||||
holder.getCount().get(),
|
||||
holder.isSave()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取日志追踪信息
|
||||
*
|
||||
* @return 日志追踪信息
|
||||
*/
|
||||
public static String getBase64() {
|
||||
LogTrack logTrack = getDefNull();
|
||||
return getBase64(logTrack);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取日志追踪信息
|
||||
*
|
||||
* @param logTrack 日志追踪信息
|
||||
* @return 日志追踪信息
|
||||
*/
|
||||
public static String getBase64(LogTrack logTrack) {
|
||||
if (Objects.isNull(logTrack)) {
|
||||
return null;
|
||||
}
|
||||
String logTxt = JSONObject.toJSONString(logTrack, JSONWriter.Feature.IgnoreEmpty);
|
||||
return Base64Utils.encodeToStr(logTxt.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否保存日志
|
||||
*
|
||||
* @param save true 保存日志, false 不保存日志
|
||||
*/
|
||||
public static void saveLog(boolean save) {
|
||||
getHolder().setSave(save);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 Holder 日志追踪信息
|
||||
*
|
||||
* @return Holder 日志追踪信息
|
||||
*/
|
||||
private static HolderLogTrack getHolder() {
|
||||
if (!LOG_TRACK_INFO.isBound()) {
|
||||
throw CommonException.create(BootError.LOG_HOLDER);
|
||||
}
|
||||
return LOG_TRACK_INFO.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 Holder 日志追踪信息
|
||||
*
|
||||
* @return Holder 日志追踪信息
|
||||
*/
|
||||
private static HolderLogTrack getHolderDefNull() {
|
||||
if (!LOG_TRACK_INFO.isBound()) {
|
||||
return null;
|
||||
}
|
||||
return LOG_TRACK_INFO.get();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package xtools.boot.log.interfaces;
|
||||
|
||||
import xtools.boot.log.model.dto.LogBody;
|
||||
|
||||
/**
|
||||
* <p>Title : LogBusInterface</p>
|
||||
* <p>Description : LogBusInterface</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 5.0.0
|
||||
* @date : 2026/2/3 16:56
|
||||
*/
|
||||
public interface LogBusInterface {
|
||||
|
||||
/**
|
||||
* 保存日志
|
||||
*
|
||||
* @param logBody 日志
|
||||
*/
|
||||
void save(LogBody logBody);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package xtools.boot.log.interfaces;
|
||||
|
||||
import xtools.boot.api.enums.BaseEnum;
|
||||
|
||||
/**
|
||||
* <p>Title : LogBusType</p>
|
||||
* <p>Description : LogBusType</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 5.0.0
|
||||
* @date : 2026/2/3 10:31
|
||||
*/
|
||||
public interface LogBusType extends BaseEnum {
|
||||
|
||||
/**
|
||||
* 基础编码
|
||||
*/
|
||||
int BASE_CODE = 100;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package xtools.boot.log.model.dto;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import lombok.Data;
|
||||
import xtools.boot.api.model.dto.log.LogTrack;
|
||||
import xtools.core.enums.LogLevel;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* <p>Title : LogBody</p>
|
||||
* <p>Description : LogBody</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 5.0.0
|
||||
* @date : 2026/2/3 09:37
|
||||
*/
|
||||
@Data
|
||||
public class LogBody implements Serializable {
|
||||
|
||||
/**
|
||||
* 日志主题
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 日志级别
|
||||
*/
|
||||
private LogLevel level;
|
||||
|
||||
/**
|
||||
* 日志类型
|
||||
*/
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 日志链信息
|
||||
*/
|
||||
private LogTrack logTrack;
|
||||
|
||||
/**
|
||||
* 运行环境信息
|
||||
*/
|
||||
private RunInfo runInfo;
|
||||
|
||||
/**
|
||||
* 堆栈信息
|
||||
*/
|
||||
private JSONArray stackTrace;
|
||||
|
||||
/**
|
||||
* 日志数据
|
||||
*/
|
||||
private JSONObject logData;
|
||||
|
||||
/**
|
||||
* 异常信息(文本)
|
||||
*/
|
||||
private String err;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package xtools.boot.log.model.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* <p>Title : RunEvInfo</p>
|
||||
* <p>Description : RunEvInfo</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 5.0.0
|
||||
* @date : 2026/2/3 09:38
|
||||
*/
|
||||
@Data
|
||||
public class RunInfo implements Serializable {
|
||||
|
||||
/**
|
||||
* 服务名称
|
||||
*/
|
||||
private String appName;
|
||||
|
||||
/**
|
||||
* 本机IP
|
||||
*/
|
||||
private String localIp;
|
||||
|
||||
/**
|
||||
* 运行端口
|
||||
*/
|
||||
private int port;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package xtools.boot.log.selector;
|
||||
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
|
||||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
|
||||
/**
|
||||
* <p>Title : BootLogImportSelector</p>
|
||||
* <p>Description : BootLogImportSelector</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 5.0.0
|
||||
* @date : 2026/01/01 09:30
|
||||
*/
|
||||
public class BootLogImportSelector implements ImportBeanDefinitionRegistrar {
|
||||
|
||||
/**
|
||||
* 根据给定的注释元数据,根据需要注册bean
|
||||
*
|
||||
* @param importingClassMetadata AnnotationMetadata
|
||||
* @param registry BeanDefinitionRegistry
|
||||
*/
|
||||
@Override
|
||||
public void registerBeanDefinitions(@NonNull AnnotationMetadata importingClassMetadata, @NonNull BeanDefinitionRegistry registry) {
|
||||
// 构建扫描对象
|
||||
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry, true);
|
||||
// 扫描包下路径
|
||||
scanner.scan("xtools.boot.log");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
xtools.boot.log.BootLogConfiguration
|
||||
Reference in New Issue
Block a user