diff --git a/instrumentation/apache-dubbo-2.7/javaagent/src/test/groovy/io/opentelemetry/instrumentation/apachedubbo/v2_7/DubboTraceChainTest.groovy b/instrumentation/apache-dubbo-2.7/javaagent/src/test/groovy/io/opentelemetry/instrumentation/apachedubbo/v2_7/DubboTraceChainTest.groovy new file mode 100644 index 000000000000..432be0305633 --- /dev/null +++ b/instrumentation/apache-dubbo-2.7/javaagent/src/test/groovy/io/opentelemetry/instrumentation/apachedubbo/v2_7/DubboTraceChainTest.groovy @@ -0,0 +1,11 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.apachedubbo.v2_7 + +import io.opentelemetry.instrumentation.test.AgentTestTrait + +class DubboTraceChainTest extends AbstractDubboTraceChainTest implements AgentTestTrait { +} diff --git a/instrumentation/apache-dubbo-2.7/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachedubbo/v2_7/DubboHeadersSetter.java b/instrumentation/apache-dubbo-2.7/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachedubbo/v2_7/DubboHeadersSetter.java index d220d877c35d..8dc502c051eb 100644 --- a/instrumentation/apache-dubbo-2.7/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachedubbo/v2_7/DubboHeadersSetter.java +++ b/instrumentation/apache-dubbo-2.7/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachedubbo/v2_7/DubboHeadersSetter.java @@ -13,5 +13,6 @@ enum DubboHeadersSetter implements TextMapSetter { @Override public void set(DubboRequest request, String key, String value) { request.context().setAttachment(key, value); + request.invocation().setAttachment(key, value); } } 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 af0dffe1c4b5..a0b0b1665c25 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,6 +35,10 @@ public Result invoke(Invoker invoker, Invocation invocation) { } RpcContext rpcContext = RpcContext.getContext(); + if (rpcContext.getUrl() == null) { + return invoker.invoke(invocation); + } + boolean isServer = rpcContext.isProviderSide(); Instrumenter instrumenter = isServer ? serverInstrumenter : clientInstrumenter; diff --git a/instrumentation/apache-dubbo-2.7/library-autoconfigure/src/test/groovy/io/opentelemetry/instrumentation/apachedubbo/v2_7/DubboTraceChainTest.groovy b/instrumentation/apache-dubbo-2.7/library-autoconfigure/src/test/groovy/io/opentelemetry/instrumentation/apachedubbo/v2_7/DubboTraceChainTest.groovy new file mode 100644 index 000000000000..ee0b1040dec5 --- /dev/null +++ b/instrumentation/apache-dubbo-2.7/library-autoconfigure/src/test/groovy/io/opentelemetry/instrumentation/apachedubbo/v2_7/DubboTraceChainTest.groovy @@ -0,0 +1,11 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.apachedubbo.v2_7 + +import io.opentelemetry.instrumentation.test.LibraryTestTrait + +class DubboTraceChainTest extends AbstractDubboTraceChainTest implements LibraryTestTrait { +} 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 new file mode 100644 index 000000000000..708b6c1fd39c --- /dev/null +++ b/instrumentation/apache-dubbo-2.7/testing/src/main/groovy/io/opentelemetry/instrumentation/apachedubbo/v2_7/AbstractDubboTraceChainTest.groovy @@ -0,0 +1,180 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.apachedubbo.v2_7 + +import io.opentelemetry.api.trace.SpanKind +import io.opentelemetry.instrumentation.apachedubbo.v2_7.api.HelloService +import io.opentelemetry.instrumentation.apachedubbo.v2_7.api.MiddleService +import io.opentelemetry.instrumentation.apachedubbo.v2_7.impl.HelloServiceImpl +import io.opentelemetry.instrumentation.apachedubbo.v2_7.impl.MiddleServiceImpl +import io.opentelemetry.instrumentation.test.InstrumentationSpecification +import io.opentelemetry.instrumentation.test.utils.PortUtils +import io.opentelemetry.semconv.trace.attributes.SemanticAttributes +import org.apache.dubbo.common.utils.NetUtils +import org.apache.dubbo.config.ApplicationConfig +import org.apache.dubbo.config.ProtocolConfig +import org.apache.dubbo.config.ReferenceConfig +import org.apache.dubbo.config.RegistryConfig +import org.apache.dubbo.config.ServiceConfig +import org.apache.dubbo.config.bootstrap.DubboBootstrap +import org.apache.dubbo.rpc.service.GenericService +import spock.lang.Unroll + +import static io.opentelemetry.api.trace.SpanKind.CLIENT +import static io.opentelemetry.api.trace.SpanKind.SERVER + +@Unroll +abstract class AbstractDubboTraceChainTest extends InstrumentationSpecification { + + def setupSpec() { + NetUtils.LOCAL_ADDRESS = InetAddress.getLoopbackAddress() + } + + ReferenceConfig configureClient(int port) { + ReferenceConfig reference = new ReferenceConfig<>() + reference.setInterface(HelloService) + reference.setGeneric("true") + reference.setUrl("dubbo://localhost:" + port + "/?timeout=30000") + return reference + } + + ReferenceConfig configureMiddleClient(int port) { + ReferenceConfig reference = new ReferenceConfig<>() + reference.setInterface(MiddleService) + reference.setGeneric("true") + reference.setUrl("dubbo://localhost:" + port + "/?timeout=30000") + return reference + } + + ServiceConfig configureServer() { + def registerConfig = new RegistryConfig() + registerConfig.setAddress("N/A") + ServiceConfig service = new ServiceConfig<>() + service.setInterface(HelloService) + service.setRef(new HelloServiceImpl()) + service.setRegistry(registerConfig) + return service + } + + ServiceConfig configureMiddleServer(GenericService genericService) { + def registerConfig = new RegistryConfig() + registerConfig.setAddress("N/A") + ServiceConfig service = new ServiceConfig<>() + service.setInterface(MiddleService) + service.setRef(new MiddleServiceImpl(genericService)) + service.setRegistry(registerConfig) + return service + } + + def "test that context is propagated correctly in chained dubbo calls"() { + setup: + def port = PortUtils.findOpenPorts(2) + def middlePort = port + 1 + def protocolConfig = new ProtocolConfig() + protocolConfig.setPort(port) + + DubboBootstrap bootstrap = DubboBootstrap.newInstance() + bootstrap.application(new ApplicationConfig("dubbo-test-provider")) + .service(configureServer()) + .protocol(protocolConfig) + .start() + + def middleProtocolConfig = new ProtocolConfig() + middleProtocolConfig.setPort(middlePort) + + def reference = configureClient(port) + DubboBootstrap middleBootstrap = DubboBootstrap.newInstance() + middleBootstrap.application(new ApplicationConfig("dubbo-demo-middle")) + .reference(reference) + .service(configureMiddleServer(reference.get())) + .protocol(middleProtocolConfig) + .start() + + + def consumerProtocolConfig = new ProtocolConfig() + consumerProtocolConfig.setRegister(false) + + def middleReference = configureMiddleClient(middlePort) + DubboBootstrap consumerBootstrap = DubboBootstrap.newInstance() + 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, 5) { + 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" + "net.sock.peer.addr" String + "net.sock.peer.port" Long + "net.sock.family" { it == "inet6" || it == null } + } + } + span(3) { + name "org.apache.dubbo.rpc.service.GenericService/\$invoke" + kind CLIENT + childOf span(2) + 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(4) { + name "io.opentelemetry.instrumentation.apachedubbo.v2_7.api.HelloService/hello" + kind SERVER + childOf span(3) + attributes { + "$SemanticAttributes.RPC_SYSTEM" "apache_dubbo" + "$SemanticAttributes.RPC_SERVICE" "io.opentelemetry.instrumentation.apachedubbo.v2_7.api.HelloService" + "$SemanticAttributes.RPC_METHOD" "hello" + "net.sock.peer.addr" String + "net.sock.peer.port" Long + "net.sock.family" { it == "inet6" || it == null } + } + } + } + } + + cleanup: + bootstrap.destroy() + middleBootstrap.destroy() + consumerBootstrap.destroy() + } +} diff --git a/instrumentation/apache-dubbo-2.7/testing/src/main/java/io/opentelemetry/instrumentation/apachedubbo/v2_7/api/MiddleService.java b/instrumentation/apache-dubbo-2.7/testing/src/main/java/io/opentelemetry/instrumentation/apachedubbo/v2_7/api/MiddleService.java new file mode 100644 index 000000000000..e80f1cd00438 --- /dev/null +++ b/instrumentation/apache-dubbo-2.7/testing/src/main/java/io/opentelemetry/instrumentation/apachedubbo/v2_7/api/MiddleService.java @@ -0,0 +1,10 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.apachedubbo.v2_7.api; + +public interface MiddleService { + String hello(String hello); +} diff --git a/instrumentation/apache-dubbo-2.7/testing/src/main/java/io/opentelemetry/instrumentation/apachedubbo/v2_7/impl/MiddleServiceImpl.java b/instrumentation/apache-dubbo-2.7/testing/src/main/java/io/opentelemetry/instrumentation/apachedubbo/v2_7/impl/MiddleServiceImpl.java new file mode 100644 index 000000000000..bdc1b689828d --- /dev/null +++ b/instrumentation/apache-dubbo-2.7/testing/src/main/java/io/opentelemetry/instrumentation/apachedubbo/v2_7/impl/MiddleServiceImpl.java @@ -0,0 +1,25 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.apachedubbo.v2_7.impl; + +import io.opentelemetry.instrumentation.apachedubbo.v2_7.api.MiddleService; +import org.apache.dubbo.rpc.service.GenericService; + +public class MiddleServiceImpl implements MiddleService { + + private final GenericService genericService; + + public MiddleServiceImpl(GenericService genericService) { + this.genericService = genericService; + } + + @Override + public String hello(String hello) { + return genericService + .$invoke("hello", new String[] {String.class.getName()}, new Object[] {hello}) + .toString(); + } +}