SpringCloudGateway使用Skywalking時日志打印traceId解析
環(huán)境信息
- SpringCloudGateway 3.1.3
- Skywalking Agent 8.10.0
環(huán)境配置
Agent
由于SpringCloudGateway是基于WebFlux來實現(xiàn)的,需要進到skywalking的agent目錄,將optional-plugins目錄底下的以下兩個jar包復制到plugins目錄
- apm-spring-webflux-5.x-plugin-8.10.0.jar
- apm-spring-cloud-gateway-3.x-plugin-8.10.0.jar
Maven依賴配置
<dependency> <groupId>org.apache.skywalking</groupId> <artifactId>apm-toolkit-log4j-2.x</artifactId> <version>${skywalking.version}</version> </dependency> <dependency> <groupId>org.apache.skywalking</groupId> <artifactId>apm-toolkit-trace</artifactId> <version>${skywalking.version}</version> </dependency>
日志pattern配置
[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%traceId] [%logger{36}] [%thread] [%-5level] %msg%n
啟動參數
新增啟動參數
-javaagent:D:\work\skywalking-agent\skywalking-agent.jar=agent.service_name=xxx -Dskywalking.collector.backend_service=xxx:11800
啟動程序后,嘗試通過網關進行接口調用,可以在Skywalking-ui上看到鏈路已經串起來了
調用鏈路
但是有個問題,日志里記錄的日志始終不顯示正確的TID
[2022-06-15 14:53:19.958] [TID: N/A]
問題處理過程
查看agent是怎么串聯(lián)鏈路的
查看Skywalking-agent的源碼,可以看到,在apm-spring-webflux-5.x-plugin-8.10.0.jar插件里,攔截了org.springframework.web.reactive.DispatcherHandler的handle方法
攔截器里往reactor的調用鏈路里,放入 < SKYWALKING_CONTEXT_SNAPSHOT - ContextSnapshot >
image.png
所以traceId可以從reactor的context里獲取到
怎么讓日志獲取到traceId
網上找了下資料,在這里[https://github.com/reactor/reactor-core/blob/main/docs/asciidoc/faq.adoc#context.api]發(fā)現(xiàn)了相關信息
public static <T> Consumer<Signal<T>> logOnNext(Consumer<T> logStatement) { return signal -> { if (!signal.isOnNext()) return; (1) Optional<String> toPutInMdc = signal.getContext().getOrEmpty("CONTEXT_KEY"); (2) toPutInMdc.ifPresentOrElse(tpim -> { try (MDC.MDCCloseable cMdc = MDC.putCloseable("MDC_KEY", tpim)) { (3) logStatement.accept(signal.get()); (4) } }, () -> logStatement.accept(signal.get())); (5) }; } @GetMapping("/byPrice") public Flux<Restaurant> byPrice(@RequestParam Double maxPrice, @RequestHeader(required = false, name = "X-UserId") String userId) { String apiId = userId == null ? "" : userId; (1) return restaurantService.byPrice(maxPrice)) .doOnEach(logOnNext(r -> LOG.debug("found restaurant {} for ${}", (2) r.getName(), r.getPricePerPerson()))) .contextWrite(Context.of("CONTEXT_KEY", apiId)); (3) }
獲取不到traceId的時候,怎么顯示默認值
https://logging.apache.org/log4j/2.x/manual/layouts.html#PatternLayout
equals{pattern}{test}{substitution} equalsIgnoreCase{pattern}{test}{substitution}
完整例子
- pattern改為 [%d{yyyy-MM-dd HH:mm:ss.SSS}] [TID: %equals{%X{traceId}}{}{N/A}] [%logger{36}] [%thread] [%-5level] %msg%n
- 注冊onEachOperator的Hooks
@Component public class LogHooks { private static final String KEY = "logMdc"; @PostConstruct @SuppressWarnings("unchecked") public void setHook() { reactor.core.publisher.Hooks.onEachOperator(KEY, Operators.lift((scannable, coreSubscriber) -> new MdcSubscriber(coreSubscriber))); } @PreDestroy public void resetHook() { reactor.core.publisher.Hooks.resetOnEachOperator(KEY); } }
public class MdcSubscriber implements CoreSubscriber { private static final String TRACE_ID = "traceId"; private static final String SKYWALKING_CTX_SNAPSHOT = "SKYWALKING_CONTEXT_SNAPSHOT"; private final CoreSubscriber<Object> actual; public MdcSubscriber(CoreSubscriber<Object> actual) { this.actual = actual; } @Override public void onSubscribe(Subscription s) { actual.onSubscribe(s); } @Override public void onNext(Object o) { Context c = actual.currentContext(); Optional<String> traceIdOptional = Optional.empty(); if (!c.isEmpty() && c.hasKey(SKYWALKING_CTX_SNAPSHOT)) { traceIdOptional = Optional.of(c.get(SKYWALKING_CTX_SNAPSHOT)).map(BeanUtil::beanToMap) .map(t -> t.get(TRACE_ID)).map(BeanUtil::beanToMap).map(t -> t.get("id")).map(Object::toString); } try (MDC.MDCCloseable cMdc = MDC.putCloseable(TRACE_ID, traceIdOptional.orElse("N/A"))) { actual.onNext(o); } } @Override public void onError(Throwable throwable) { actual.onError(throwable); } @Override public void onComplete() { actual.onComplete(); } @Override public Context currentContext() { return actual.currentContext(); } }
以上就是SpringCloudGateway使用Skywalking時日志打印traceId解析的詳細內容,更多關于SpringCloudGateway Skywalking的資料請關注腳本之家其它相關文章!
相關文章
Java maven三種倉庫,本地倉庫,私服,中央倉庫的配置
今天給大家簡單介紹Maven三種倉庫的配置,文中有非常詳細的解釋,對Java初學者很有幫助喲,需要的朋友可以參考下,希望能夠給你帶來幫助2021-09-09解讀httpclient的validateAfterInactivity連接池狀態(tài)檢測
這篇文章主要為大家介紹了httpclient的validateAfterInactivity連接池狀態(tài)檢測解讀*,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-11-11SpringBoot中使用Servlet三大組件的方法(Servlet、Filter、Listener)
這篇文章主要介紹了SpringBoot中使用Servlet三大組件的方法(Servlet、Filter、Listener),本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-01-01java DataInputStream和DataOutputStream詳解及實例代碼
這篇文章主要介紹了java DataInputStream和DataOutputStream詳解及實例代碼的相關資料,需要的朋友可以參考下2017-01-01