fix Dubbo3.x Context problem #8525 (#110)

This commit is contained in:
洪阿南 2022-02-25 12:08:57 +08:00 committed by GitHub
parent f0c22f32dd
commit 9efec16c1b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 200 additions and 120 deletions

View File

@ -8,6 +8,7 @@ Release Notes.
* Support Tomcat thread pool metric collect.
* Remove plugin for ServiceComb Java Chassis 0.x
* Add Guava EventBus plugin.
* Fix Dubbo 3.x plugin's tracing problem.
* Support Druid Connection pool metrics collecting.
* Support HikariCP Connection pool metrics collecting.
* Support Dbcp2 Connection pool metrics collecting.

View File

@ -33,11 +33,9 @@ import java.util.List;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.returns;
public class DubboInstrumentationBase extends ClassInstanceMethodsEnhancePluginDefine {
public class DubboInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
public static final String PROVIDER_ENHANCE_CLASS = "org.apache.dubbo.monitor.support.MonitorFilter";
public static final String CONSUMER_ENHANCE_CLASS = "org.apache.dubbo.monitor.support.MonitorClusterFilter";
public static final String ENHANCE_CLASS = "org.apache.dubbo.monitor.support.MonitorFilter";
public static final String INTERCEPT_POINT_METHOD = "invoke";
@ -49,15 +47,9 @@ public class DubboInstrumentationBase extends ClassInstanceMethodsEnhancePluginD
public static final String CONTEXT_ATTACHMENT_TYPE_NAME = "org.apache.dubbo.rpc.RpcContextAttachment";
private final String enhanceClassName;
public DubboInstrumentationBase(String enhanceClassName) {
this.enhanceClassName = enhanceClassName;
}
@Override
protected ClassMatch enhanceClass() {
return NameMatch.byName(enhanceClassName);
return NameMatch.byName(ENHANCE_CLASS);
}
@Override

View File

@ -18,15 +18,13 @@
package org.apache.skywalking.apm.plugin.asf.dubbo3;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.RpcContextAttachment;
import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.RpcServiceContext;
import org.apache.skywalking.apm.agent.core.context.CarrierItem;
import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
@ -65,15 +63,7 @@ public class DubboInterceptor implements InstanceMethodsAroundInterceptor {
Invoker invoker = (Invoker) allArguments[0];
Invocation invocation = (Invocation) allArguments[1];
RpcServiceContext serviceContext = RpcContext.getServiceContext();
boolean isConsumer;
URL url = serviceContext.getUrl();
if (url == null) {
url = serviceContext.getConsumerUrl();
isConsumer = url != null;
} else {
isConsumer = serviceContext.isConsumerSide();
}
boolean isConsumer = isConsumer(invocation);
RpcContextAttachment attachment = isConsumer ? RpcContext.getClientAttachment() : RpcContext.getServerAttachment();
URL requestURL = invoker.getUrl();
@ -125,12 +115,8 @@ public class DubboInterceptor implements InstanceMethodsAroundInterceptor {
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
Object ret) throws Throwable {
Result result = (Result) ret;
try {
if (result != null && result.getException() != null) {
dealException(result.getException());
}
} catch (RpcException e) {
dealException(e);
if (result != null && result.getException() != null) {
dealException(result.getException());
}
ContextManager.stopSpan();
@ -151,6 +137,19 @@ public class DubboInterceptor implements InstanceMethodsAroundInterceptor {
span.log(throwable);
}
/**
* To judge if current is in provider side.
*/
private static boolean isConsumer(Invocation invocation) {
Invoker<?> invoker = invocation.getInvoker();
// As RpcServiceContext may not been reset when it's role switched from provider
// to consumer in the same thread, but RpcInvocation is always correctly bounded
// to the current request or serve request, https://github.com/apache/skywalking-java/pull/110
return invoker.getUrl()
.getParameter("side", "provider")
.equals("consumer");
}
/**
* Format operation name. e.g. org.apache.skywalking.apm.plugin.test.Test.test(String)
*

View File

@ -14,5 +14,4 @@
# See the License for the specific language governing permissions and
# limitations under the License.
dubbo-3.x=org.apache.skywalking.apm.plugin.asf.dubbo3.DubboProviderInstrumentation
dubbo-3.x=org.apache.skywalking.apm.plugin.asf.dubbo3.DubboConsumerInstrumentation
dubbo-3.x=org.apache.skywalking.apm.plugin.asf.dubbo3.DubboInstrumentation

View File

@ -87,39 +87,52 @@ public class DubboInterceptorTest {
@Mock
private RpcContextAttachment contextAttachment;
@Mock
private Invoker invoker;
private Invoker consumerInvoker;
@Mock
private Invocation invocation;
private Invoker providerInvoker;
@Mock
private Invocation consumerInvocation;
@Mock
private Invocation providerInvocation;
@Mock
private MethodInterceptResult methodInterceptResult;
@Mock
private Result result;
private Object[] allArguments;
private Object[] consumerArguments;
private Object[] providerArguments;
private Class[] argumentTypes;
private static final URL CONSUMER_URL = URL.valueOf("dubbo://127.0.0.1:20880/org.apache.skywalking.apm.test.TestDubboService?side=consumer");
private static final URL PROVIDER_URL = URL.valueOf("dubbo://127.0.0.1:20880/org.apache.skywalking.apm.test.TestDubboService?side=provider");
@Before
public void setUp() throws Exception {
dubboInterceptor = new DubboInterceptor();
PowerMockito.mockStatic(RpcContext.class);
URL url = URL.valueOf("dubbo://127.0.0.1:20880/org.apache.skywalking.apm.test.TestDubboService");
when(invoker.getUrl()).thenReturn(url);
when(invocation.getMethodName()).thenReturn("test");
when(invocation.getParameterTypes()).thenReturn(new Class[] {String.class});
when(invocation.getArguments()).thenReturn(new Object[] {"abc"});
when(RpcContext.getServiceContext()).thenReturn(serviceContext);
when(serviceContext.getUrl()).thenReturn(null);
when(serviceContext.getConsumerUrl()).thenReturn(url);
when(consumerInvoker.getUrl()).thenReturn(CONSUMER_URL);
when(consumerInvocation.getMethodName()).thenReturn("test");
when(consumerInvocation.getParameterTypes()).thenReturn(new Class[] {String.class});
when(consumerInvocation.getArguments()).thenReturn(new Object[] {"abc"});
when(consumerInvocation.getInvoker()).thenReturn(consumerInvoker);
when(RpcContext.getClientAttachment()).thenReturn(contextAttachment);
consumerArguments = new Object[] {
consumerInvoker,
consumerInvocation
};
allArguments = new Object[] {
invoker,
invocation
when(providerInvoker.getUrl()).thenReturn(PROVIDER_URL);
when(providerInvocation.getMethodName()).thenReturn("test");
when(providerInvocation.getParameterTypes()).thenReturn(new Class[] {String.class});
when(providerInvocation.getArguments()).thenReturn(new Object[] {"abc"});
when(providerInvocation.getInvoker()).thenReturn(providerInvoker);
providerArguments = new Object[] {
providerInvoker,
providerInvocation
};
argumentTypes = new Class[] {
invoker.getClass(),
invocation.getClass()
consumerInvoker.getClass(),
consumerInvocation.getClass()
};
Config.Agent.SERVICE_NAME = "DubboTestCases-APP";
}
@ -140,8 +153,8 @@ public class DubboInterceptorTest {
@Test
public void testConsumerWithAttachment() throws Throwable {
dubboInterceptor.beforeMethod(enhancedInstance, null, allArguments, argumentTypes, methodInterceptResult);
dubboInterceptor.afterMethod(enhancedInstance, null, allArguments, argumentTypes, result);
dubboInterceptor.beforeMethod(enhancedInstance, null, consumerArguments, argumentTypes, methodInterceptResult);
dubboInterceptor.afterMethod(enhancedInstance, null, consumerArguments, argumentTypes, result);
assertThat(segmentStorage.getTraceSegments().size(), is(1));
TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
@ -152,10 +165,10 @@ public class DubboInterceptorTest {
@Test
public void testConsumerWithException() throws Throwable {
dubboInterceptor.beforeMethod(enhancedInstance, null, allArguments, argumentTypes, methodInterceptResult);
dubboInterceptor.beforeMethod(enhancedInstance, null, consumerArguments, argumentTypes, methodInterceptResult);
dubboInterceptor.handleMethodException(
enhancedInstance, null, allArguments, argumentTypes, new RuntimeException());
dubboInterceptor.afterMethod(enhancedInstance, null, allArguments, argumentTypes, result);
enhancedInstance, null, consumerArguments, argumentTypes, new RuntimeException());
dubboInterceptor.afterMethod(enhancedInstance, null, consumerArguments, argumentTypes, result);
assertThat(segmentStorage.getTraceSegments().size(), is(1));
TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
assertConsumerTraceSegmentInErrorCase(traceSegment);
@ -165,8 +178,8 @@ public class DubboInterceptorTest {
public void testConsumerWithResultHasException() throws Throwable {
when(result.getException()).thenReturn(new RuntimeException());
dubboInterceptor.beforeMethod(enhancedInstance, null, allArguments, argumentTypes, methodInterceptResult);
dubboInterceptor.afterMethod(enhancedInstance, null, allArguments, argumentTypes, result);
dubboInterceptor.beforeMethod(enhancedInstance, null, consumerArguments, argumentTypes, methodInterceptResult);
dubboInterceptor.afterMethod(enhancedInstance, null, consumerArguments, argumentTypes, result);
assertThat(segmentStorage.getTraceSegments().size(), is(1));
TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
@ -175,16 +188,14 @@ public class DubboInterceptorTest {
@Test
public void testProviderWithAttachment() throws Throwable {
when(serviceContext.getUrl()).thenReturn(
URL.valueOf("dubbo://127.0.0.1:20880/org.apache.skywalking.apm.test.TestDubboService"));
when(serviceContext.getConsumerUrl()).thenReturn(null);
when(providerInvoker.getUrl()).thenReturn(PROVIDER_URL);
when(RpcContext.getServerAttachment()).thenReturn(contextAttachment);
when(contextAttachment.getAttachment(
SW8CarrierItem.HEADER_NAME)).thenReturn(
"1-My40LjU=-MS4yLjM=-3-c2VydmljZQ==-aW5zdGFuY2U=-L2FwcA==-MTI3LjAuMC4xOjgwODA=");
dubboInterceptor.beforeMethod(enhancedInstance, null, allArguments, argumentTypes, methodInterceptResult);
dubboInterceptor.afterMethod(enhancedInstance, null, allArguments, argumentTypes, result);
dubboInterceptor.beforeMethod(enhancedInstance, null, providerArguments, argumentTypes, methodInterceptResult);
dubboInterceptor.afterMethod(enhancedInstance, null, providerArguments, argumentTypes, result);
assertProvider();
}

View File

@ -18,53 +18,97 @@ segmentItems:
- serviceName: dubbo-3.x-scenario
segmentSize: ge 3
segments:
- segmentId: not null
spans:
- operationName: org.apache.skywalking.apm.testcase.dubbo3.services.GreetService.doBusiness(String)
parentSpanId: -1
spanId: 0
spanLayer: RPCFramework
startTime: nq 0
endTime: nq 0
componentId: 3
isError: false
spanType: Entry
peer: not null
tags:
- {key: url, value: not null}
- {key: arguments, value: helloWorld}
refs:
- {parentEndpoint: GET:/dubbo-3.x-scenario/case/dubbo, networkAddress: not null,
refType: CrossProcess, parentSpanId: 1, parentTraceSegmentId: not null,
parentServiceInstance: not null, parentService: dubbo-3.x-scenario, traceId: not null}
skipAnalysis: 'false'
- segmentId: not null
spans:
- operationName: org.apache.skywalking.apm.testcase.dubbo3.services.GreetService.doBusiness(String)
parentSpanId: 0
spanId: 1
spanLayer: RPCFramework
startTime: nq 0
endTime: nq 0
componentId: 3
isError: false
spanType: Exit
peer: not null
tags:
- {key: url, value: not null}
- {key: arguments, value: helloWorld}
skipAnalysis: 'false'
- operationName: GET:/dubbo-3.x-scenario/case/dubbo
parentSpanId: -1
spanId: 0
spanLayer: Http
startTime: nq 0
endTime: nq 0
componentId: 1
isError: false
spanType: Entry
peer: ''
tags:
- {key: url, value: 'http://localhost:8080/dubbo-3.x-scenario/case/dubbo'}
- {key: http.method, value: GET}
skipAnalysis: 'false'
- segmentId: not null
spans:
- operationName: org.apache.skywalking.apm.testcase.dubbo3.services.ExceptionService.exceptionCall()
parentSpanId: -1
spanId: 0
spanLayer: RPCFramework
startTime: nq 0
endTime: nq 0
componentId: 3
isError: true
spanType: Entry
peer: not null
tags:
- { key: url, value: not null }
logs:
- logEvent:
- { key: event, value: error }
- { key: error.kind, value: java.lang.RuntimeException }
- { key: message, value: test exception! }
- { key: "stack", value: "not null" }
refs:
- { parentEndpoint: org.apache.skywalking.apm.testcase.dubbo3.services.GreetService.doBusiness(String), networkAddress: not null,
refType: CrossProcess, parentSpanId: 1, parentTraceSegmentId: not null, parentServiceInstance: not null,
parentService: dubbo-3.x-scenario, traceId: not null }
skipAnalysis: 'false'
- segmentId: not null
spans:
- operationName: org.apache.skywalking.apm.testcase.dubbo3.services.ExceptionService.exceptionCall()
parentSpanId: 0
spanId: 1
spanLayer: RPCFramework
startTime: nq 0
endTime: nq 0
componentId: 3
isError: true
spanType: Exit
peer: not null
tags:
- { key: url, value: not null }
logs:
- logEvent:
- { key: event, value: error }
- { key: error.kind, value: java.lang.RuntimeException }
- { key: message, value: test exception! }
- { key: "stack", value: "not null" }
skipAnalysis: 'false'
- operationName: org.apache.skywalking.apm.testcase.dubbo3.services.GreetService.doBusiness(String)
parentSpanId: -1
spanId: 0
spanLayer: RPCFramework
startTime: nq 0
endTime: nq 0
componentId: 3
isError: false
spanType: Entry
peer: not null
tags:
- {key: url, value: not null}
- {key: arguments, value: helloWorld}
refs:
- {parentEndpoint: GET:/dubbo-3.x-scenario/case/dubbo, networkAddress: not null,
refType: CrossProcess, parentSpanId: 1, parentTraceSegmentId: not null,
parentServiceInstance: not null, parentService: dubbo-3.x-scenario, traceId: not null}
skipAnalysis: 'false'
- segmentId: not null
spans:
- operationName: org.apache.skywalking.apm.testcase.dubbo3.services.GreetService.doBusiness(String)
parentSpanId: 0
spanId: 1
spanLayer: RPCFramework
startTime: nq 0
endTime: nq 0
componentId: 3
isError: false
spanType: Exit
peer: not null
tags:
- {key: url, value: not null}
- {key: arguments, value: helloWorld}
skipAnalysis: 'false'
- operationName: GET:/dubbo-3.x-scenario/case/dubbo
parentSpanId: -1
spanId: 0
spanLayer: Http
startTime: nq 0
endTime: nq 0
componentId: 1
isError: false
spanType: Entry
peer: ''
tags:
- {key: url, value: 'http://localhost:8080/dubbo-3.x-scenario/case/dubbo'}
- {key: http.method, value: GET}
skipAnalysis: 'false'

View File

@ -24,7 +24,9 @@ import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.ServiceConfig;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.skywalking.apm.testcase.dubbo3.services.ExceptionService;
import org.apache.skywalking.apm.testcase.dubbo3.services.GreetService;
import org.apache.skywalking.apm.testcase.dubbo3.services.impl.ExceptionServiceImpl;
import org.apache.skywalking.apm.testcase.dubbo3.services.impl.GreetServiceImpl;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@ -64,6 +66,19 @@ public class Application {
return serviceConfig;
}
@Bean(destroyMethod = "unexport")
public ServiceConfig<ExceptionService> service2() {
ServiceConfig<ExceptionService> serviceConfig = new ServiceConfig<>();
serviceConfig.setApplication(applicationConfig);
serviceConfig.setRegistry(registryConfig);
serviceConfig.setProtocol(protocolConfig);
serviceConfig.setInterface(ExceptionService.class);
serviceConfig.setRef(new ExceptionServiceImpl());
serviceConfig.setTimeout(500000);
serviceConfig.export();
return serviceConfig;
}
@Bean(destroyMethod = "destroy")
public ReferenceConfig<GreetService> reference() {
ReferenceConfig<GreetService> referenceConfig = new ReferenceConfig<>();

View File

@ -16,12 +16,9 @@
*
*/
package org.apache.skywalking.apm.plugin.asf.dubbo3;
package org.apache.skywalking.apm.testcase.dubbo3.services;
public class DubboConsumerInstrumentation extends DubboInstrumentationBase {
public DubboConsumerInstrumentation() {
super(CONSUMER_ENHANCE_CLASS);
}
public interface ExceptionService {
void exceptionCall();
}

View File

@ -16,12 +16,13 @@
*
*/
package org.apache.skywalking.apm.plugin.asf.dubbo3;
package org.apache.skywalking.apm.testcase.dubbo3.services.impl;
public class DubboProviderInstrumentation extends DubboInstrumentationBase {
import org.apache.skywalking.apm.testcase.dubbo3.services.ExceptionService;
public DubboProviderInstrumentation() {
super(PROVIDER_ENHANCE_CLASS);
public class ExceptionServiceImpl implements ExceptionService {
@Override
public void exceptionCall() {
throw new RuntimeException("test exception!");
}
}

View File

@ -18,12 +18,33 @@
package org.apache.skywalking.apm.testcase.dubbo3.services.impl;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.skywalking.apm.testcase.dubbo3.services.ExceptionService;
import org.apache.skywalking.apm.testcase.dubbo3.services.GreetService;
public class GreetServiceImpl implements GreetService {
private RegistryConfig registryConfig = new RegistryConfig("zookeeper://127.0.0.1:2181");
@Override
public String doBusiness(String s) {
try {
ReferenceConfig<ExceptionService> referenceConfig = new ReferenceConfig<>();
referenceConfig.setRegistry(registryConfig);
referenceConfig.setInterface(ExceptionService.class);
referenceConfig.setScope("remote");
referenceConfig.setInjvm(false);
referenceConfig.setTimeout(500000);
referenceConfig.setAsync(false);
referenceConfig.setCheck(false);
ExceptionService exceptionService = referenceConfig.get();
exceptionService.exceptionCall();
} catch (Exception e) {
// do nothing
e.printStackTrace();
}
return "{name:'" + s + "'}";
}
}