Fix a bug in Spring Cloud Gateway if HttpClientFinalizer#send does not invoke, the span created at NettyRoutingFilterInterceptor can not stop. (#672)
This commit is contained in:
parent
4adb343091
commit
f227543fc3
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -74,6 +74,10 @@ public class NettyRoutingFilterInterceptor implements InstanceMethodsAroundInter
|
|||
@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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,13 +21,23 @@ package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v21x;
|
|||
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;
|
||||
|
|
@ -47,6 +57,103 @@ import reactor.core.publisher.Mono;
|
|||
|
||||
@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();
|
||||
|
|
@ -151,12 +258,48 @@ public class NettyRoutingFilterInterceptorTest {
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,6 +81,10 @@ public class NettyRoutingFilterInterceptor implements InstanceMethodsAroundInter
|
|||
@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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -170,7 +170,8 @@ public class NettyRoutingFilterInterceptorTest {
|
|||
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));
|
||||
|
|
@ -187,7 +188,8 @@ public class NettyRoutingFilterInterceptorTest {
|
|||
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);
|
||||
|
|
@ -207,9 +209,10 @@ public class NettyRoutingFilterInterceptorTest {
|
|||
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);
|
||||
|
|
|
|||
|
|
@ -81,6 +81,10 @@ public class NettyRoutingFilterInterceptor implements InstanceMethodsAroundInter
|
|||
@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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -170,7 +170,8 @@ public class NettyRoutingFilterInterceptorTest {
|
|||
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));
|
||||
|
|
@ -187,7 +188,8 @@ public class NettyRoutingFilterInterceptorTest {
|
|||
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);
|
||||
|
|
@ -207,9 +209,10 @@ public class NettyRoutingFilterInterceptorTest {
|
|||
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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue