Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix duplicate traceId when use forward scheme in spring.cloud.gateway.routes.uri properties #672

Merged
merged 2 commits into from
Mar 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Release Notes.
* Rename system env name from `sw_plugin_kafka_producer_config` to `SW_PLUGIN_KAFKA_PRODUCER_CONFIG`.
* Support for ActiveMQ-Artemis messaging tracing.
* Archive the expired plugins `impala-jdbc-2.6.x-plugin`.
* Fix a bug in Spring Cloud Gateway if HttpClientFinalizer#send does not invoke, the span created at NettyRoutingFilterInterceptor can not stop.

#### Documentation
* Update docs to describe `expired-plugins`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ public static EnhancedInstance getInstance(Object o) {
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
Object ret) throws Throwable {
if (ContextManager.isActive()) {
// if HttpClientFinalizerSendInterceptor does not invoke, we will stop the span there to avoid context leak.
ContextManager.stopSpan();
}
return ret;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,23 @@
import java.security.Principal;
import java.time.Instant;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan;
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.test.helper.SegmentHelper;
import org.apache.skywalking.apm.agent.test.tools.AgentServiceRule;
import org.apache.skywalking.apm.agent.test.tools.SegmentStorage;
import org.apache.skywalking.apm.agent.test.tools.SegmentStoragePoint;
import org.apache.skywalking.apm.agent.test.tools.SpanAssert;
import org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner;
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
Expand All @@ -47,6 +57,103 @@

@RunWith(TracingSegmentRunner.class)
public class NettyRoutingFilterInterceptorTest {

private static class ServerWebExchangeEnhancedInstance implements ServerWebExchange, EnhancedInstance {
private ContextSnapshot snapshot;
Map<String, Object> attributes = new HashMap<>();

@Override
public Object getSkyWalkingDynamicField() {
return snapshot;
}

@Override
public void setSkyWalkingDynamicField(Object value) {
this.snapshot = (ContextSnapshot) value;
}

@Override
public ServerHttpRequest getRequest() {
return null;
}

@Override
public ServerHttpResponse getResponse() {
return null;
}

@Override
public Map<String, Object> getAttributes() {
return attributes;
}

@Override
public Mono<WebSession> getSession() {
return null;
}

@Override
public <T extends Principal> Mono<T> getPrincipal() {
return null;
}

@Override
public Mono<MultiValueMap<String, String>> getFormData() {
return null;
}

@Override
public Mono<MultiValueMap<String, Part>> getMultipartData() {
return null;
}

@Override
public LocaleContext getLocaleContext() {
return null;
}

@Override
public ApplicationContext getApplicationContext() {
return null;
}

@Override
public boolean isNotModified() {
return false;
}

@Override
public boolean checkNotModified(Instant instant) {
return false;
}

@Override
public boolean checkNotModified(String s) {
return false;
}

@Override
public boolean checkNotModified(String s, Instant instant) {
return false;
}

@Override
public String transformUrl(String s) {
return null;
}

@Override
public void addUrlTransformer(Function<String, String> function) {

}

@Override
public String getLogPrefix() {
return null;
}
}

private final ServerWebExchangeEnhancedInstance enhancedInstance = new ServerWebExchangeEnhancedInstance();
private final NettyRoutingFilterInterceptor interceptor = new NettyRoutingFilterInterceptor();
@Rule
public AgentServiceRule serviceRule = new AgentServiceRule();
Expand Down Expand Up @@ -151,12 +258,48 @@ public void testIsTraced() throws Throwable {
interceptor.beforeMethod(null, null, new Object[]{exchange}, null, null);
interceptor.afterMethod(null, null, null, null, null);
Assert.assertEquals(exchange.getAttributes().get(NETTY_ROUTING_FILTER_TRACED_ATTR), true);
Assert.assertNotNull(ContextManager.activeSpan());
Assert.assertFalse(ContextManager.isActive());

ContextManager.stopSpan();
// no more need this, span was stopped at interceptor#afterMethod
// ContextManager.stopSpan();

interceptor.beforeMethod(null, null, new Object[]{exchange}, null, null);
interceptor.afterMethod(null, null, null, null, null);
Assert.assertEquals(exchange.getAttributes().get(NETTY_ROUTING_FILTER_TRACED_ATTR), true);
}

@Test
public void testWithNullDynamicField() throws Throwable {
interceptor.beforeMethod(null, null, new Object[]{enhancedInstance}, null, null);
interceptor.afterMethod(null, null, null, null, null);
// no more need this, span was stopped at interceptor#afterMethod
// ContextManager.stopSpan();
final List<TraceSegment> traceSegments = segmentStorage.getTraceSegments();
Assert.assertEquals(traceSegments.size(), 1);
final List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegments.get(0));
Assert.assertNotNull(spans);
Assert.assertEquals(spans.size(), 1);
SpanAssert.assertComponent(spans.get(0), ComponentsDefine.SPRING_CLOUD_GATEWAY);
}

@Test
public void testWithContextSnapshot() throws Throwable {
final AbstractSpan entrySpan = ContextManager.createEntrySpan("/get", null);
SpanLayer.asHttp(entrySpan);
entrySpan.setComponent(ComponentsDefine.SPRING_WEBFLUX);
enhancedInstance.setSkyWalkingDynamicField(ContextManager.capture());
interceptor.beforeMethod(null, null, new Object[]{enhancedInstance}, null, null);
interceptor.afterMethod(null, null, null, null, null);
// no more need this, span was stopped at interceptor#afterMethod
// ContextManager.stopSpan();
ContextManager.stopSpan(entrySpan);
final List<TraceSegment> traceSegments = segmentStorage.getTraceSegments();
Assert.assertEquals(traceSegments.size(), 1);
final List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegments.get(0));
Assert.assertNotNull(spans);
Assert.assertEquals(spans.size(), 2);
SpanAssert.assertComponent(spans.get(0), ComponentsDefine.SPRING_CLOUD_GATEWAY);
SpanAssert.assertComponent(spans.get(1), ComponentsDefine.SPRING_WEBFLUX);
SpanAssert.assertLayer(spans.get(1), SpanLayer.HTTP);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ private EnhancedInstance getInstance(Object o) {
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
Object ret) throws Throwable {
if (ContextManager.isActive()) {
// if HttpClientFinalizerSendInterceptor does not invoke, we will stop the span there to avoid context leak.
ContextManager.stopSpan();
}
return ret;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,8 @@ public void setUp() throws Exception {
public void testWithNullDynamicField() throws Throwable {
interceptor.beforeMethod(null, null, new Object[]{enhancedInstance}, null, null);
interceptor.afterMethod(null, null, null, null, null);
ContextManager.stopSpan();
// no more need this, span was stopped at interceptor#afterMethod
// ContextManager.stopSpan();
final List<TraceSegment> traceSegments = segmentStorage.getTraceSegments();
Assert.assertEquals(traceSegments.size(), 1);
final List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegments.get(0));
Expand All @@ -187,7 +188,8 @@ public void testWithContextSnapshot() throws Throwable {
enhancedInstance.setSkyWalkingDynamicField(ContextManager.capture());
interceptor.beforeMethod(null, null, new Object[]{enhancedInstance}, null, null);
interceptor.afterMethod(null, null, null, null, null);
ContextManager.stopSpan();
// no more need this, span was stopped at interceptor#afterMethod
// ContextManager.stopSpan();
ContextManager.stopSpan(entrySpan);
final List<TraceSegment> traceSegments = segmentStorage.getTraceSegments();
Assert.assertEquals(traceSegments.size(), 1);
Expand All @@ -207,9 +209,10 @@ public void testIsTraced() throws Throwable {
interceptor.beforeMethod(null, null, new Object[]{enhancedInstance}, null, null);
interceptor.afterMethod(null, null, null, null, null);
Assert.assertEquals(enhancedInstance.getAttributes().get(NETTY_ROUTING_FILTER_TRACED_ATTR), true);
Assert.assertNotNull(ContextManager.activeSpan());
Assert.assertFalse(ContextManager.isActive());

ContextManager.stopSpan();
// no more need this, span was stopped at interceptor#afterMethod
// ContextManager.stopSpan();

interceptor.beforeMethod(null, null, new Object[]{enhancedInstance}, null, null);
interceptor.afterMethod(null, null, null, null, null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ private EnhancedInstance getInstance(Object o) {
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
Object ret) throws Throwable {
if (ContextManager.isActive()) {
// if HttpClientFinalizerSendInterceptor does not invoke, we will stop the span there to avoid context leak.
ContextManager.stopSpan();
}
return ret;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,8 @@ public void setUp() throws Exception {
public void testWithNullDynamicField() throws Throwable {
interceptor.beforeMethod(null, null, new Object[]{enhancedInstance}, null, null);
interceptor.afterMethod(null, null, null, null, null);
ContextManager.stopSpan();
// no more need this, span was stopped at interceptor#afterMethod
// ContextManager.stopSpan();
final List<TraceSegment> traceSegments = segmentStorage.getTraceSegments();
Assert.assertEquals(traceSegments.size(), 1);
final List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegments.get(0));
Expand All @@ -187,7 +188,8 @@ public void testWithContextSnapshot() throws Throwable {
enhancedInstance.setSkyWalkingDynamicField(ContextManager.capture());
interceptor.beforeMethod(null, null, new Object[]{enhancedInstance}, null, null);
interceptor.afterMethod(null, null, null, null, null);
ContextManager.stopSpan();
// no more need this, span was stopped at interceptor#afterMethod
// ContextManager.stopSpan();
ContextManager.stopSpan(entrySpan);
final List<TraceSegment> traceSegments = segmentStorage.getTraceSegments();
Assert.assertEquals(traceSegments.size(), 1);
Expand All @@ -207,9 +209,10 @@ public void testIsTraced() throws Throwable {
interceptor.beforeMethod(null, null, new Object[]{enhancedInstance}, null, null);
interceptor.afterMethod(null, null, null, null, null);
Assert.assertEquals(enhancedInstance.getAttributes().get(NETTY_ROUTING_FILTER_TRACED_ATTR), true);
Assert.assertNotNull(ContextManager.activeSpan());
Assert.assertFalse(ContextManager.isActive());

ContextManager.stopSpan();
// no more need this, span was stopped at interceptor#afterMethod
// ContextManager.stopSpan();

interceptor.beforeMethod(null, null, new Object[]{enhancedInstance}, null, null);
interceptor.afterMethod(null, null, null, null, null);
Expand Down
Loading