feat: OpenFeign请求增加来源服务标记
- FeignChainInterceptor新增X-Source-Service和X-Request-Time请求头 - ContextInterceptor提取并记录请求来源服务、计算链路耗时 - 日志格式: [Trace] sourceService -> targetService | traceId=xxx | chainTime=xxxms | path=xxx
This commit is contained in:
parent
a8450d181f
commit
61c6e573df
@ -5,6 +5,7 @@ import com.fundplatform.common.context.TraceContextHolder;
|
||||
import com.fundplatform.common.context.UserContextHolder;
|
||||
import feign.RequestInterceptor;
|
||||
import feign.RequestTemplate;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
@ -12,6 +13,8 @@ import org.springframework.stereotype.Component;
|
||||
*
|
||||
* <p>职责:在通过 OpenFeign 发起下游 HTTP 请求时,统一透传:
|
||||
* <ul>
|
||||
* <li>X-Source-Service:请求来源服务名称(调用方标识);</li>
|
||||
* <li>X-Request-Time:请求发起时间戳(毫秒);</li>
|
||||
* <li>X-Tenant-Id:租户ID;</li>
|
||||
* <li>X-Uid:当前用户ID;</li>
|
||||
* <li>X-Uname:当前用户名;</li>
|
||||
@ -21,20 +24,34 @@ import org.springframework.stereotype.Component;
|
||||
@Component
|
||||
public class FeignChainInterceptor implements RequestInterceptor {
|
||||
|
||||
public static final String HEADER_SOURCE_SERVICE = "X-Source-Service";
|
||||
public static final String HEADER_REQUEST_TIME = "X-Request-Time";
|
||||
public static final String HEADER_TENANT_ID = "X-Tenant-Id";
|
||||
public static final String HEADER_UID = "X-Uid";
|
||||
public static final String HEADER_UNAME = "X-Uname";
|
||||
public static final String HEADER_TRACE_ID = "X-Trace-Id";
|
||||
|
||||
/**
|
||||
* 当前服务名称(请求来源标识)
|
||||
*/
|
||||
@Value("${spring.application.name:unknown}")
|
||||
private String serviceName;
|
||||
|
||||
@Override
|
||||
public void apply(RequestTemplate template) {
|
||||
// 多租户透传
|
||||
// 1. 请求来源服务标识(调用方)
|
||||
template.header(HEADER_SOURCE_SERVICE, serviceName);
|
||||
|
||||
// 2. 请求发起时间戳(用于计算链路耗时)
|
||||
template.header(HEADER_REQUEST_TIME, String.valueOf(System.currentTimeMillis()));
|
||||
|
||||
// 3. 多租户透传
|
||||
Long tenantId = TenantContextHolder.getTenantId();
|
||||
if (tenantId != null) {
|
||||
template.header(HEADER_TENANT_ID, String.valueOf(tenantId));
|
||||
}
|
||||
|
||||
// 用户信息透传
|
||||
// 4. 用户信息透传
|
||||
Long uid = UserContextHolder.getUserId();
|
||||
if (uid != null) {
|
||||
template.header(HEADER_UID, String.valueOf(uid));
|
||||
@ -44,7 +61,7 @@ public class FeignChainInterceptor implements RequestInterceptor {
|
||||
template.header(HEADER_UNAME, uname);
|
||||
}
|
||||
|
||||
// TraceId 透传(如不存在则生成)
|
||||
// 5. TraceId 透传(如不存在则生成)
|
||||
String traceId = TraceContextHolder.getOrCreateTraceId();
|
||||
template.header(HEADER_TRACE_ID, traceId);
|
||||
}
|
||||
|
||||
@ -5,22 +5,59 @@ import com.fundplatform.common.context.TraceContextHolder;
|
||||
import com.fundplatform.common.context.UserContextHolder;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
/**
|
||||
* 租户和用户上下文拦截器
|
||||
* 从HTTP Header中提取租户ID和用户ID,设置到ThreadLocal中
|
||||
* 从HTTP Header中提取租户ID、用户ID、请求来源等信息,设置到ThreadLocal中
|
||||
* 同时记录请求来源和链路耗时信息
|
||||
*/
|
||||
@Component
|
||||
public class ContextInterceptor implements HandlerInterceptor {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ContextInterceptor.class);
|
||||
|
||||
public static final String HEADER_SOURCE_SERVICE = "X-Source-Service";
|
||||
public static final String HEADER_REQUEST_TIME = "X-Request-Time";
|
||||
public static final String HEADER_TENANT_ID = "X-Tenant-Id";
|
||||
public static final String HEADER_USER_ID = "X-User-Id";
|
||||
public static final String HEADER_TRACE_ID = "X-Trace-Id";
|
||||
|
||||
/**
|
||||
* 请求开始时间属性Key
|
||||
*/
|
||||
private static final String ATTR_START_TIME = "requestStartTime";
|
||||
|
||||
/**
|
||||
* 当前服务名称
|
||||
*/
|
||||
@Value("${spring.application.name:unknown}")
|
||||
private String serviceName;
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
|
||||
// 记录请求开始时间
|
||||
request.setAttribute(ATTR_START_TIME, System.currentTimeMillis());
|
||||
|
||||
// 提取请求来源服务
|
||||
String sourceService = request.getHeader(HEADER_SOURCE_SERVICE);
|
||||
String requestTimeStr = request.getHeader(HEADER_REQUEST_TIME);
|
||||
|
||||
// 计算链路耗时(如果有请求发起时间)
|
||||
Long chainDuration = null;
|
||||
if (requestTimeStr != null && !requestTimeStr.isEmpty()) {
|
||||
try {
|
||||
long requestTime = Long.parseLong(requestTimeStr);
|
||||
chainDuration = System.currentTimeMillis() - requestTime;
|
||||
} catch (NumberFormatException e) {
|
||||
// 忽略无效的时间戳
|
||||
}
|
||||
}
|
||||
|
||||
// 提取租户ID
|
||||
String tenantIdStr = request.getHeader(HEADER_TENANT_ID);
|
||||
if (tenantIdStr != null && !tenantIdStr.isEmpty()) {
|
||||
@ -49,11 +86,36 @@ public class ContextInterceptor implements HandlerInterceptor {
|
||||
TraceContextHolder.setTraceId(traceId);
|
||||
}
|
||||
|
||||
// 记录请求追踪日志
|
||||
if (sourceService != null && chainDuration != null) {
|
||||
logger.info("[Trace] {} -> {} | traceId={} | chainTime={}ms | path={}",
|
||||
sourceService, serviceName, traceId, chainDuration, request.getRequestURI());
|
||||
} else if (sourceService != null) {
|
||||
logger.info("[Trace] {} -> {} | traceId={} | path={}",
|
||||
sourceService, serviceName, traceId, request.getRequestURI());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
|
||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
|
||||
Object handler, Exception ex) {
|
||||
// 计算当前服务处理耗时
|
||||
Long startTime = (Long) request.getAttribute(ATTR_START_TIME);
|
||||
if (startTime != null) {
|
||||
long duration = System.currentTimeMillis() - startTime;
|
||||
String traceId = request.getHeader(HEADER_TRACE_ID);
|
||||
String sourceService = request.getHeader(HEADER_SOURCE_SERVICE);
|
||||
|
||||
logger.debug("[Trace] {} -> {} | traceId={} | processTime={}ms | status={}",
|
||||
sourceService != null ? sourceService : "external",
|
||||
serviceName,
|
||||
traceId,
|
||||
duration,
|
||||
response.getStatus());
|
||||
}
|
||||
|
||||
// 清理 ThreadLocal,防止内存泄漏
|
||||
TenantContextHolder.clear();
|
||||
UserContextHolder.clear();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user