From f887fb870d71ee71396cc8483a8fa3f07df85531 Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Thu, 9 Feb 2023 08:46:39 +0200 Subject: [PATCH] Dubbo: don't create spans for calls inside the same jvm (#7761) Resolves https://github.com/open-telemetry/opentelemetry-java-instrumentation/issues/7520 Invoking a dubbo service, like in https://github.com/zewade/opentelemetry-dubbo-demo/blob/d7e2417ae787808dbfb43747d586b91a1b29ecec/demo-business-provider/src/main/java/cn/zewade/business/controller/BusinessController.java#L20, creates a client span (and a server span on the receiving end). If the caller and service are on the jvm this call doesn't go through remoting and will be handled with regular java calls. Now when the initially called service calls another service, like in https://github.com/zewade/opentelemetry-dubbo-demo/blob/main/demo-business-provider/src/main/java/cn/zewade/business/dubbo/BusinessDubboServiceImpl.java#L25, that second call will also attempt to create a client span. This second client span will be suppressed which will also suppress context propagation. --- .../apachedubbo/v2_7/TracingFilter.java | 2 +- .../v2_7/AbstractDubboTraceChainTest.groovy | 93 +++++++++++++++++++ 2 files changed, 94 insertions(+), 1 deletion(-) diff --git a/instrumentation/apache-dubbo-2.7/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachedubbo/v2_7/TracingFilter.java b/instrumentation/apache-dubbo-2.7/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachedubbo/v2_7/TracingFilter.java index a0b0b1665c..a19e8ef6d5 100644 --- a/instrumentation/apache-dubbo-2.7/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachedubbo/v2_7/TracingFilter.java +++ b/instrumentation/apache-dubbo-2.7/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachedubbo/v2_7/TracingFilter.java @@ -35,7 +35,7 @@ final class TracingFilter implements Filter { } RpcContext rpcContext = RpcContext.getContext(); - if (rpcContext.getUrl() == null) { + if (rpcContext.getUrl() == null || "injvm".equals(rpcContext.getUrl().getProtocol())) { return invoker.invoke(invocation); } diff --git a/instrumentation/apache-dubbo-2.7/testing/src/main/groovy/io/opentelemetry/instrumentation/apachedubbo/v2_7/AbstractDubboTraceChainTest.groovy b/instrumentation/apache-dubbo-2.7/testing/src/main/groovy/io/opentelemetry/instrumentation/apachedubbo/v2_7/AbstractDubboTraceChainTest.groovy index 5428389dfe..8295373562 100644 --- a/instrumentation/apache-dubbo-2.7/testing/src/main/groovy/io/opentelemetry/instrumentation/apachedubbo/v2_7/AbstractDubboTraceChainTest.groovy +++ b/instrumentation/apache-dubbo-2.7/testing/src/main/groovy/io/opentelemetry/instrumentation/apachedubbo/v2_7/AbstractDubboTraceChainTest.groovy @@ -43,6 +43,14 @@ abstract class AbstractDubboTraceChainTest extends InstrumentationSpecification return reference } + ReferenceConfig configureLocalClient(int port) { + ReferenceConfig reference = new ReferenceConfig<>() + reference.setInterface(HelloService) + reference.setGeneric("true") + reference.setUrl("injvm://localhost:" + port + "/?timeout=30000") + return reference + } + ReferenceConfig configureMiddleClient(int port) { ReferenceConfig reference = new ReferenceConfig<>() reference.setInterface(MiddleService) @@ -183,4 +191,89 @@ abstract class AbstractDubboTraceChainTest extends InstrumentationSpecification middleBootstrap.destroy() consumerBootstrap.destroy() } + + def "test ignore injvm calls"() { + setup: + def port = PortUtils.findOpenPorts(2) + def middlePort = port + 1 + def protocolConfig = new ProtocolConfig() + protocolConfig.setPort(port) + + def frameworkModel = newFrameworkModel() + DubboBootstrap bootstrap = newDubboBootstrap(frameworkModel) + bootstrap.application(new ApplicationConfig("dubbo-test-provider")) + .service(configureServer()) + .protocol(protocolConfig) + .start() + + def middleProtocolConfig = new ProtocolConfig() + middleProtocolConfig.setPort(middlePort) + + def reference = configureLocalClient(port) + DubboBootstrap middleBootstrap = newDubboBootstrap(frameworkModel) + middleBootstrap.application(new ApplicationConfig("dubbo-demo-middle")) + .reference(reference) + .service(configureMiddleServer(reference)) + .protocol(middleProtocolConfig) + .start() + + + def consumerProtocolConfig = new ProtocolConfig() + consumerProtocolConfig.setRegister(false) + + def middleReference = configureMiddleClient(middlePort) + DubboBootstrap consumerBootstrap = newDubboBootstrap(frameworkModel) + consumerBootstrap.application(new ApplicationConfig("dubbo-demo-api-consumer")) + .reference(middleReference) + .protocol(consumerProtocolConfig) + .start() + + when: + GenericService genericService = middleReference.get() + def response = runWithSpan("parent") { + genericService.$invoke("hello", [String.getName()] as String[], ["hello"] as Object[]) + } + + then: + response == "hello" + assertTraces(1) { + trace(0, 3) { + span(0) { + name "parent" + kind SpanKind.INTERNAL + hasNoParent() + } + span(1) { + name "org.apache.dubbo.rpc.service.GenericService/\$invoke" + kind CLIENT + childOf span(0) + attributes { + "$SemanticAttributes.RPC_SYSTEM" "apache_dubbo" + "$SemanticAttributes.RPC_SERVICE" "org.apache.dubbo.rpc.service.GenericService" + "$SemanticAttributes.RPC_METHOD" "\$invoke" + "$SemanticAttributes.NET_PEER_NAME" "localhost" + "$SemanticAttributes.NET_PEER_PORT" Long + } + } + span(2) { + name "io.opentelemetry.instrumentation.apachedubbo.v2_7.api.MiddleService/hello" + kind SERVER + childOf span(1) + attributes { + "$SemanticAttributes.RPC_SYSTEM" "apache_dubbo" + "$SemanticAttributes.RPC_SERVICE" "io.opentelemetry.instrumentation.apachedubbo.v2_7.api.MiddleService" + "$SemanticAttributes.RPC_METHOD" "hello" + "$SemanticAttributes.NET_SOCK_PEER_ADDR" String + "$SemanticAttributes.NET_SOCK_PEER_PORT" Long + "$SemanticAttributes.NET_SOCK_FAMILY" { it == SemanticAttributes.NetSockFamilyValues.INET6 || it == null } + } + } + } + } + + cleanup: + bootstrap.destroy() + middleBootstrap.destroy() + consumerBootstrap.destroy() + } }