1+ <?xml version =" 1.0" encoding =" utf-8" ?>
2+ <feed xmlns =" http://www.w3.org/2005/Atom" >
3+ <id >https://sruby.github.io</id >
4+ <title >Coder</title >
5+ <updated >2023-02-21T11:35:07.166Z</updated >
6+ <generator >https://github.com/jpmonette/feed</generator >
7+ <link rel =" alternate" href =" https://sruby.github.io" />
8+ <link rel =" self" href =" https://sruby.github.io/atom.xml" />
9+ <subtitle >Try again,fail again,fail better</subtitle >
10+ <logo >https://sruby.github.io/images/avatar.png</logo >
11+ <icon >https://sruby.github.io/favicon.ico</icon >
12+ <rights >All rights reserved 2023, Coder</rights >
13+ <entry >
14+ <title type =" html" ><![CDATA[ Spring Cloud Gateway日志无法记录SkyWalking的TID]]> </title >
15+ <id >https://sruby.github.io/post/spring-cloud-gateway-ri-zhi-wu-fa-ji-lu-skywalking-de-tid/</id >
16+ <link href =" https://sruby.github.io/post/spring-cloud-gateway-ri-zhi-wu-fa-ji-lu-skywalking-de-tid/" >
17+ </link >
18+ <updated >2023-02-20T05:58:10.000Z</updated >
19+ <content type =" html" ><![CDATA[ <h1 id="问题">问题</h1>
20+ <p>在继承了SkyWalking日志工具的情况下,Spring Cloud Gateway的日志中TID为N/A,其他服务的日志均能够正常记录TID。<br>
21+ SkyWalking UI可以正常记录包括Spring Cloud Gateway在内的各个服务的TID。</p>
22+ <h1 id="原因">原因</h1>
23+ <p>SkyWalking agent plugin只保证将TID传递给OAP,而不保证一定把TID输出到日志。<br>
24+ 如果需要支持,则需要使用方增加此特性。</p>
25+ <h1 id="agent-plugin源码分析">Agent plugin源码分析</h1>
26+ <p>Spring Cloud Gateway对应的plugin源码如下:<br>
27+ Agent plugin:spring-webflux-5.x-plugin<br>
28+ 类:DispatcherHandlerHandleMethodInterceptor</p>
29+ <pre><code class="language-java">@Override
30+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
31+ MethodInterceptResult result) throws Throwable {
32+ EnhancedInstance instance = getInstance(allArguments[0]);
33+
34+ ServerWebExchange exchange = (ServerWebExchange) allArguments[0];
35+
36+ ContextCarrier carrier = new ContextCarrier();
37+ CarrierItem next = carrier.items();
38+ HttpHeaders headers = exchange.getRequest().getHeaders();
39+ while (next.hasNext()) {
40+ next = next.next();
41+ List<String> header = headers.get(next.getHeadKey());
42+ if (header != null && header.size() > 0) {
43+ next.setHeadValue(header.get(0));
44+ }
45+ }
46+
47+ AbstractSpan span = ContextManager.createEntrySpan(exchange.getRequest().getURI().getPath(), carrier);
48+
49+ if (instance != null && instance.getSkyWalkingDynamicField() != null) {
50+ ContextManager.continued((ContextSnapshot) instance.getSkyWalkingDynamicField());
51+ }
52+ span.setComponent(ComponentsDefine.SPRING_WEBFLUX);
53+ SpanLayer.asHttp(span);
54+ Tags.URL.set(span, exchange.getRequest().getURI().toString());
55+ HTTP.METHOD.set(span, exchange.getRequest().getMethodValue());
56+ instance.setSkyWalkingDynamicField(ContextManager.capture());
57+ span.prepareForAsync();
58+ ContextManager.stopSpan(span);
59+ //SKYWALING_SPAN保存到exchange
60+ exchange.getAttributes().put("SKYWALING_SPAN", span);
61+ }
62+ </code></pre>
63+ <h1 id="solution">Solution</h1>
64+ <h1 id="solution-1">Solution 1</h1>
65+ <ul>
66+ <li>只需要在filter中记录TID,便于排查问题,而不保存到日志框架的MDC种。</li>
67+ <li>根据源码分析部分可以得知plugin会把SKYWALING_SPAN保存到exchange<br>
68+ 中,所以我们可以在exchange中获取SKYWALING_SPAN。</li>
69+ <li>从exchange中获取到Span对象后,需要通过反射的方式一层层获取到traceid,因为无法直接依赖包含这些类的agent-core包,会跟agent本身发生冲突。</li>
70+ </ul>
71+ <pre><code class="language-java">String traceId = "N/A";
72+ Object skywalingSpanObject = exchange.getAttributes().get("SKYWALING_SPAN");
73+ if (ObjectUtils.isNotEmpty(skywalingSpanObject)) {
74+ try {
75+ Field owner = FieldUtils.getField(skywalingSpanObject.getClass(), "owner", true);
76+ Object tracingContext = owner.get(skywalingSpanObject);
77+ Field segmentField = FieldUtils.getField(tracingContext.getClass(), "segment", true);
78+ Object segment = segmentField.get(tracingContext);
79+ Field relatedGlobalTraceIdField = FieldUtils.getField(segment.getClass(), "relatedGlobalTraceId", true);
80+ Object relatedGlobalTraceId = relatedGlobalTraceIdField.get(segment);
81+ String traceIdObject = relatedGlobalTraceId.toString();
82+ traceId = Stringutils.substrΩingBetween(traceIdObject, "=", ")");
83+ } catch (Exception e) {
84+ log.warn("get TID failed", e);
85+ }
86+ </code></pre>
87+ <h1 id="reference">Reference</h1>
88+ <blockquote>
89+ <p><a href="https://github.com/apache/skywalking/discussions/9232">SpringCloudGateway3.1.3, With apm-log4j2-2.x:8.10.0, does not display the real traceId, always display 'TID: N/A' · Discussion #9232 · apache/skywalking (github.com)</a><br>
90+ <a href="https://github.com/apache/skywalking/issues/5268">My log can't get traceId when I use Spring Cloud Gateway in my project ,all traceId in my log is "[traceId:TID:N/A]" · Issue #5268 · apache/skywalking (github.com)</a><br>
91+ <a href="https://www.jianshu.com/p/40727a0b9604">SpringCloudGateway使用Skywalking时日志打印traceId - 简书 (jianshu.com)</a></p>
92+ </blockquote>
93+ <p>#SkyWalking<br>
94+ #SpringCloudGateway<br>
95+ #MDC<br>
96+ #TracdID</p>
97+ ]]> </content >
98+ </entry >
99+ </feed >
0 commit comments