新增:mdc工具封装
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
package com.sdm.common.common;
|
||||
|
||||
/*spdm 常量字符串定义类 */
|
||||
public class SpdmCommonConstant {
|
||||
|
||||
/**
|
||||
* MDC 中存储 traceId 的 key(需与日志格式中的 %X{traceId} 对应)
|
||||
*/
|
||||
public static final String TRACE_ID_KEY = "traceId";
|
||||
|
||||
/**
|
||||
* 响应头中返回 traceId 的 key(前端可通过此 key 获取)
|
||||
*/
|
||||
public static final String TRACE_ID_HEADER = "X-Trace-Id";
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.sdm.common.filter;
|
||||
|
||||
import com.sdm.common.common.SpdmCommonConstant;
|
||||
import jakarta.servlet.*;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
@@ -13,15 +14,7 @@ import java.util.UUID;
|
||||
// 拦截所有 HTTP 请求
|
||||
public class TraceIdFilter implements Filter {
|
||||
|
||||
/**
|
||||
* MDC 中存储 traceId 的 key(需与日志格式中的 %X{traceId} 对应)
|
||||
*/
|
||||
public static final String TRACE_ID_KEY = "traceId";
|
||||
|
||||
/**
|
||||
* 响应头中返回 traceId 的 key(前端可通过此 key 获取)
|
||||
*/
|
||||
public static final String TRACE_ID_HEADER = "X-Trace-Id";
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
|
||||
@@ -32,14 +25,14 @@ public class TraceIdFilter implements Filter {
|
||||
|
||||
try {
|
||||
// 1. 生成或获取 traceId(优先从请求头获取,支持前端传递,便于联调)
|
||||
String traceId = request.getHeader(TRACE_ID_HEADER);
|
||||
String traceId = request.getHeader(SpdmCommonConstant.TRACE_ID_HEADER);
|
||||
if (traceId == null || traceId.trim().isEmpty()) {
|
||||
// 生成 UUID 并去除横杠(32位,简洁易读)
|
||||
traceId = UUID.randomUUID().toString().replace("-", "");
|
||||
}
|
||||
|
||||
// 2. 存入 MDC(供日志打印使用,所有日志框架可通过 %X{traceId} 获取)
|
||||
MDC.put(TRACE_ID_KEY, traceId);
|
||||
MDC.put(SpdmCommonConstant.TRACE_ID_KEY, traceId);
|
||||
|
||||
// 3. 写入响应头(返回给前端,便于前端排查问题时匹配日志)
|
||||
// response.setHeader(TRACE_ID_HEADER, traceId);
|
||||
@@ -49,7 +42,7 @@ public class TraceIdFilter implements Filter {
|
||||
|
||||
} finally {
|
||||
// 5. 清除 MDC 中的 traceId(关键!避免线程池复用导致的 traceId 污染)
|
||||
MDC.remove(TRACE_ID_KEY);
|
||||
MDC.remove(SpdmCommonConstant.TRACE_ID_KEY);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
56
common/src/main/java/com/sdm/common/utils/MdcUtil.java
Normal file
56
common/src/main/java/com/sdm/common/utils/MdcUtil.java
Normal file
@@ -0,0 +1,56 @@
|
||||
package com.sdm.common.utils;
|
||||
|
||||
import com.sdm.common.common.SpdmCommonConstant;
|
||||
import org.slf4j.MDC;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class MdcUtil {
|
||||
|
||||
/**
|
||||
* 私有构造方法,禁止实例化工具类
|
||||
*/
|
||||
private MdcUtil() {
|
||||
throw new UnsupportedOperationException("工具类禁止实例化");
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成并存入 traceId 到 MDC
|
||||
* @return 生成的 traceId 字符串(无横线的UUID)
|
||||
*/
|
||||
public static String generateAndPutTraceId() {
|
||||
// 生成无横线的UUID作为traceId
|
||||
String traceId = UUID.randomUUID().toString().replace("-", "");
|
||||
// 存入MDC,供日志框架通过 %X{traceId} 获取
|
||||
MDC.put(SpdmCommonConstant.TRACE_ID_KEY, traceId);
|
||||
return traceId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 MDC 中移除 traceId(销毁)
|
||||
*/
|
||||
public static void removeTraceId() {
|
||||
MDC.remove(SpdmCommonConstant.TRACE_ID_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前 MDC 中的 traceId
|
||||
* @return 当前traceId,若不存在则返回null
|
||||
*/
|
||||
public static String getTraceId() {
|
||||
return MDC.get(SpdmCommonConstant.TRACE_ID_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 手动存入指定的 traceId 到 MDC(适用于需要复用traceId的场景,如跨服务调用)
|
||||
* @param traceId 自定义的traceId
|
||||
*/
|
||||
public static void putTraceId(String traceId) {
|
||||
if (traceId == null || traceId.trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("traceId 不能为空");
|
||||
}
|
||||
MDC.put(SpdmCommonConstant.TRACE_ID_KEY, traceId);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.sdm.common.common.SdmResponse;
|
||||
import com.sdm.common.common.ThreadLocalContext;
|
||||
import com.sdm.common.utils.MdcUtil;
|
||||
import com.sdm.project.service.ILyricInternalService;
|
||||
import com.xxl.job.core.context.XxlJobHelper;
|
||||
import com.xxl.job.core.handler.annotation.XxlJob;
|
||||
@@ -23,21 +24,26 @@ public class LyricTodoListSchedule {
|
||||
// xxljob平台配置定时任务
|
||||
@XxlJob("lyricTodoListHandler")
|
||||
public void hpcJobStatusHandler() throws Exception {
|
||||
// 初始化traceId
|
||||
String traceId = MdcUtil.generateAndPutTraceId();
|
||||
String param = XxlJobHelper.getJobParam();
|
||||
if(StringUtils.isBlank(param)){
|
||||
log.warn("lyricTodoListHandler param null");
|
||||
log.warn("{} lyricTodoListHandler param null",traceId);
|
||||
return;
|
||||
}
|
||||
XxlJobHelper.log("XXL-JOB:拉起lyric代办任务开始,param:{}", param);
|
||||
XxlJobHelper.log("{} XXL-JOB:拉起lyric代办任务开始,param:{}", traceId,param);
|
||||
JSONObject paramJson = JSONObject.parseObject(param);
|
||||
ThreadLocalContext.setTenantId(paramJson.getLong("tenantId"));
|
||||
ThreadLocalContext.setUserId(paramJson.getLong("userId"));
|
||||
long startTime = System.currentTimeMillis();
|
||||
SdmResponse response = lyricInternalService.getTodoList();
|
||||
long endTime = System.currentTimeMillis();
|
||||
log.info("lyricTodoListHandler cost [{}] s", (endTime - startTime)/1000);
|
||||
log.info("lyricTodoListHandler result :{}", JSON.toJSONString(response));
|
||||
XxlJobHelper.log("XXL-JOB:拉起lyric代办任务结束:{}", JSON.toJSONString(response));
|
||||
long second = (endTime - startTime) / 1000;
|
||||
log.info("{} lyricTodoListHandler cost [{}] s", traceId,second);
|
||||
log.info("{} lyricTodoListHandler result :{}", traceId,JSON.toJSONString(response));
|
||||
XxlJobHelper.log("{} XXL-JOB:拉起lyric代办任务结束:{},耗时:{} s", traceId,JSON.toJSONString(response),second);
|
||||
// 销毁
|
||||
MdcUtil.removeTraceId();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,44 +1,61 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<!-- 彩色日志 -->
|
||||
<!-- 彩色日志依赖的渲染类 -->
|
||||
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
|
||||
<conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
|
||||
<conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
|
||||
|
||||
<!-- 彩色日志格式 -->
|
||||
<property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr([%X{traceId}] %d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr([%15.15t]){faint} %clr(%logger){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}" />
|
||||
<!-- 普通日志格式(无颜色) -->
|
||||
<property name="FILE_LOG_PATTERN" value="[%X{traceId}] %d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${PID:- } [%15.15t] %logger : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}" />
|
||||
|
||||
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
|
||||
<!-- 日志文件存储地址 -->
|
||||
<property name="LOG_HOME" value="/home/app/project/logs" />
|
||||
<!-- 控制台输出 -->
|
||||
|
||||
<!-- 1. 控制台输出(默认输出DEBUG及以上级别) -->
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
||||
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
|
||||
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
|
||||
<charset>UTF-8</charset>
|
||||
</encoder>
|
||||
</appender>
|
||||
<!-- 按照每天生成日志文件 -->
|
||||
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!--日志文件输出的文件名-->
|
||||
<FileNamePattern>${LOG_HOME}/console.log.%d{yyyy-MM-dd}.log</FileNamePattern>
|
||||
<!--日志文件保留天数-->
|
||||
|
||||
<!-- 2. INFO级别日志输出到running.log(仅包含INFO及以上,不包含DEBUG) -->
|
||||
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_HOME}/running.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<FileNamePattern>${LOG_HOME}/running.log.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
|
||||
<MaxHistory>30</MaxHistory>
|
||||
<TotalSizeCap>500MB</TotalSizeCap>
|
||||
<cleanHistoryOnStart>true</cleanHistoryOnStart>
|
||||
<maxFileSize>10MB</maxFileSize>
|
||||
</rollingPolicy>
|
||||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
||||
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
|
||||
<pattern>${FILE_LOG_PATTERN}</pattern>
|
||||
<charset>UTF-8</charset>
|
||||
</encoder>
|
||||
<!--日志文件最大的大小-->
|
||||
<!-- <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">-->
|
||||
<!-- <MaxFileSize>10MB</MaxFileSize>-->
|
||||
<!-- </triggeringPolicy>-->
|
||||
<!-- 过滤:只接受INFO及以上级别(INFO, WARN, ERROR),排除DEBUG -->
|
||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||
<level>INFO</level>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<!-- 3. DEBUG级别日志输出到running_debug.log(仅包含DEBUG级别) -->
|
||||
<appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_HOME}/running_debug.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<FileNamePattern>${LOG_HOME}/running_debug.log.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
|
||||
<MaxHistory>30</MaxHistory>
|
||||
<TotalSizeCap>500MB</TotalSizeCap>
|
||||
<maxFileSize>10MB</maxFileSize>
|
||||
</rollingPolicy>
|
||||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
||||
<pattern>${FILE_LOG_PATTERN}</pattern>
|
||||
</encoder>
|
||||
<!-- 过滤:只接受DEBUG级别 -->
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<level>DEBUG</level>
|
||||
<onMatch>ACCEPT</onMatch> <!-- 匹配DEBUG级别则接受 -->
|
||||
<onMismatch>DENY</onMismatch> <!-- 不匹配则拒绝 -->
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<!-- 4. core.log 专用输出器(保留 callerInfo 格式) -->
|
||||
@@ -59,15 +76,17 @@
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<!-- 日志输出级别 -->
|
||||
<!-- 全局日志级别设置为DEBUG(确保DEBUG日志能被捕获) -->
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT" />
|
||||
<appender-ref ref="FILE" />
|
||||
<appender-ref ref="STDOUT" /> <!-- 控制台输出DEBUG及以上 -->
|
||||
<appender-ref ref="INFO_FILE" /> <!-- INFO及以上输出到running.log -->
|
||||
<appender-ref ref="DEBUG_FILE" /> <!-- 仅DEBUG输出到running_debug.log -->
|
||||
</root>
|
||||
|
||||
|
||||
<!-- 绑定 FeignClient → 输出到日志文件 -->
|
||||
<logger name="FeignClient" level="INFO" additivity="false">
|
||||
<appender-ref ref="FILE" />
|
||||
<appender-ref ref="INFO_FILE" />
|
||||
<appender-ref ref="STDOUT" />
|
||||
</logger>
|
||||
|
||||
@@ -111,6 +130,7 @@
|
||||
<logger name="java.sql.ResultSet" level="DEBUG"/>
|
||||
|
||||
<logger name="com.sdm.project" level="INFO"/>
|
||||
<logger name="com.sdm.project.dao" level="DEBUG"/>
|
||||
<!-- 新增:com.sdm.outbridge 包日志级别配置 -->
|
||||
<logger name="com.sdm.outbridge" level="INFO"/>
|
||||
<logger name="com.sdm.project.dao" level="DEBUG"/>
|
||||
|
||||
Reference in New Issue
Block a user