全局調用鏈路traceId網關到業務層、feign調用統一問題記錄
項目里面使用的traceId是基于skywalking進行打印的,但是實際使用的過程中發現網關處的traceId為空,而且feign調用其他服務時候的traceId 都不一樣。 顯示如下:
網關traceId為空:
基于此,想要把項目里面的以及feign調用的traceId統一成一樣的,且在網關顯示一樣。
首先是需要在日志設置打印traceId的格式:以logback-spring.xml為例
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"> <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout"> <pattern>%date{yyyy-MM-dd HH:mm:ss.SSS} %tid [%-5level] [%thread] [%logger{15}:%line] %X{traceId} --- %msg%n</pattern> </layout> </encoder> </appender>
%X{traceId} 即為顯示的traceId
其次是在網關出需要優先把traceId進行打印顯示:
String traceId = StringUtils.isEmpty(exchange.getRequest().getHeaders().getFirst(TraceUtils.TRACE_ID))?TraceUtils.createTraceId(): exchange.getRequest().getHeaders().getFirst(TraceUtils.TRACE_ID); logger.info("當前request traceId:" + traceId);
public class TraceUtils { public static final String TRACE_ID = "traceId"; public static synchronized String createTraceId() { String traceId = UUID.randomUUID().toString().replaceAll("-", "").toLowerCase(); MDC.put(TRACE_ID, traceId); return traceId; } public static void destroyTraceId() { MDC.remove(TRACE_ID); MDC.clear(); } }
注意的是:如果在網關處有其他的業務日志,需要優先把traceId創建出來。否則使用的是默認的16位traceId.我自己在開發和測試環境測試發現,如果把traceId寫在業務日志后面,顯示的是16位的且和我本地不同的traceId.
feign時候需要通過request.getHeader("traceId")獲取,且需要在網關處把生成的traceId放入header里面。大概的代碼如下:
ServerHttpRequest request = exchange.getRequest().mutate() .header(Constant.H_KEY_DEVICE_ID, deviceId) .header(Constant.H_KEY_APP_ID, appId) .header(Constant.H_KEY_BRAND, sourceApp) .header(Constant.H_KEY_BRAND, sourceApp) .header(Constant.H_KEY_IP, ip) .header(Constant.H_URL, exchange.getRequest().getURI().toString()) .header(Constant.H_KEY_REQ_FROM,"outside") .header(TraceUtils.TRACE_ID,traceId) .build();
/** * FeignClient調用服務時添加廣告主信息請求頭 * */ public class FeignAddHeadersRequestInterceptor implements RequestInterceptor { /** * 日志定義 */ private static final Logger LOG = LoggerFactory.getLogger(FeignAddHeadersRequestInterceptor.class); /** * 請求頭名稱 */ private static final String X_CLIENT_USER = "x-client-user"; private static final String AUTHORIZATION = "Authorization"; private static final String SOURCEAPP = "SourceApp"; private static final String SOURCEAPPEGNORE= "sourceApp"; private static final String TRACE_ID = "traceId"; private static final String SOURCE_APP_VER = "SourceAppVer"; private static final String SOURCE_APP_VER_IGNORE = "sourceappver"; @Override public void apply(RequestTemplate template) { LOG.info("feign add header begin"); ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); if (attributes == null) { return; } HttpServletRequest request = attributes.getRequest(); String header = request.getHeader(AUTHORIZATION); String traceId = request.getHeader(TRACE_ID); String sourceApp = request.getHeader(SOURCEAPP); String sourceAppVer = request.getHeader(SOURCE_APP_VER); if (header != null) { // 添加請求頭 template.header(AUTHORIZATION, header); LOG.info("feign add header done"); } if(Objects.nonNull(sourceApp)){ template.header(SOURCEAPP, sourceApp); LOG.info("feign souceApp done"); }else { String sourceAppIgnore = request.getHeader(SOURCEAPPEGNORE); if(Objects.nonNull(sourceAppIgnore)){ template.header(SOURCEAPPEGNORE,sourceAppIgnore); LOG.info("fein SOURCEAPPEGNORE done"); } } if(Objects.isNull(traceId)){ traceId = Optional.ofNullable(request.getAttribute(TRACE_ID)).map(t->t.toString()).orElse(null); LOG.info("current traceId:" + traceId); } if(Objects.nonNull(traceId)){ //添加traceId template.header(TRACE_ID,traceId); MDC.put(TRACE_ID,traceId); LOG.info("request traceId:" + traceId); } if(Objects.nonNull(sourceAppVer)){ template.header(BaseCommon.SOURCE_APP_VER,sourceAppVer); }else{ String sourceAppVerIgnore = request.getHeader(SOURCE_APP_VER_IGNORE); if(Objects.nonNull(sourceAppVerIgnore)){ template.header(BaseCommon.SOURCE_APP_VER,sourceAppVerIgnore); LOG.info("feign add sourceAppVerIgnore "); } } } }
通過實現RequestInterceptor接口的apply方法,把feign調用的traceId給打通。大概思路是這樣。這樣打通后,一個完整的請求的traceId即可打通。
網關:
業務層:feign調用顯示也和網關的都一樣的了

浙公網安備 33010602011771號