Migrate reactor-netty CONNECT instrumentation to Instrumenter API
MODIFY
instrumentation/netty/netty-4-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/common/client/NettyClientInstrumenterFactory.java
instrumentation/netty/netty-4-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/common/client/NettyClientInstrumenterFactory.java
@@ -8,7 +8,6 @@ package io.opentelemetry.javaagent.instrumentation.netty.common.client;
import io.netty.channel.Channel;
import io.netty.handler.codec.http.HttpResponse;
import io.opentelemetry.api.GlobalOpenTelemetry;
-import io.opentelemetry.instrumentation.api.config.Config;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.api.instrumenter.PeerServiceAttributesExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor;
@@ -19,13 +18,13 @@ import io.opentelemetry.javaagent.instrumentation.netty.common.HttpRequestAndCha
public final class NettyClientInstrumenterFactory {
- private static final boolean alwaysCreateConnectSpan =
- Config.get().getBoolean("otel.instrumentation.netty.always-create-connect-span", false);
-
private final String instrumentationName;
+ private final boolean alwaysCreateConnectSpan;
- public NettyClientInstrumenterFactory(String instrumentationName) {
+ public NettyClientInstrumenterFactory(
+ String instrumentationName, boolean alwaysCreateConnectSpan) {
this.instrumentationName = instrumentationName;
+ this.alwaysCreateConnectSpan = alwaysCreateConnectSpan;
}
public Instrumenter<HttpRequestAndChannel, HttpResponse> createHttpInstrumenter() {

MODIFY
instrumentation/netty/netty-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v4_0/client/NettyClientSingletons.java
instrumentation/netty/netty-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v4_0/client/NettyClientSingletons.java
package io.opentelemetry.javaagent.instrumentation.netty.v4_0.client;
import io.netty.handler.codec.http.HttpResponse;
+import io.opentelemetry.instrumentation.api.config.Config;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.javaagent.instrumentation.netty.common.HttpRequestAndChannel;
import io.opentelemetry.javaagent.instrumentation.netty.common.client.NettyClientInstrumenterFactory;
@@ -13,12 +14,15 @@ import io.opentelemetry.javaagent.instrumentation.netty.common.client.NettyConne
public final class NettyClientSingletons {
+ private static final boolean alwaysCreateConnectSpan =
+ Config.get().getBoolean("otel.instrumentation.netty.always-create-connect-span", false);
+
private static final Instrumenter<HttpRequestAndChannel, HttpResponse> INSTRUMENTER;
private static final NettyConnectInstrumenter CONNECT_INSTRUMENTER;
static {
NettyClientInstrumenterFactory factory =
- new NettyClientInstrumenterFactory("io.opentelemetry.netty-4.0");
+ new NettyClientInstrumenterFactory("io.opentelemetry.netty-4.0", alwaysCreateConnectSpan);
INSTRUMENTER = factory.createHttpInstrumenter();
CONNECT_INSTRUMENTER = factory.createConnectInstrumenter();
}

MODIFY
instrumentation/netty/netty-4.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v4_1/client/NettyClientSingletons.java
instrumentation/netty/netty-4.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v4_1/client/NettyClientSingletons.java
@@ -7,6 +7,7 @@ package io.opentelemetry.javaagent.instrumentation.netty.v4_1.client;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.util.AttributeKey;
+import io.opentelemetry.instrumentation.api.config.Config;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.javaagent.instrumentation.netty.common.HttpRequestAndChannel;
import io.opentelemetry.javaagent.instrumentation.netty.common.client.NettyClientInstrumenterFactory;
@@ -19,12 +20,15 @@ public final class NettyClientSingletons {
static final AttributeKey<HttpResponse> HTTP_RESPONSE =
AttributeKey.valueOf(NettyClientSingletons.class, "http-client-response");
+ private static final boolean alwaysCreateConnectSpan =
+ Config.get().getBoolean("otel.instrumentation.netty.always-create-connect-span", false);
+
private static final Instrumenter<HttpRequestAndChannel, HttpResponse> INSTRUMENTER;
private static final NettyConnectInstrumenter CONNECT_INSTRUMENTER;
static {
NettyClientInstrumenterFactory factory =
- new NettyClientInstrumenterFactory("io.opentelemetry.netty-4.1");
+ new NettyClientInstrumenterFactory("io.opentelemetry.netty-4.1", alwaysCreateConnectSpan);
INSTRUMENTER = factory.createHttpInstrumenter();
CONNECT_INSTRUMENTER = factory.createConnectInstrumenter();
}

MODIFY
instrumentation/reactor-netty/reactor-netty-1.0/javaagent/build.gradle.kts
instrumentation/reactor-netty/reactor-netty-1.0/javaagent/build.gradle.kts
@@ -18,6 +18,7 @@ muzzle {
dependencies {
implementation(project(":instrumentation:netty:netty-4.1:library"))
+ implementation(project(":instrumentation:netty:netty-4-common:javaagent"))
library("io.projectreactor.netty:reactor-netty-http:1.0.0")
testInstrumentation(project(":instrumentation:reactor-netty:reactor-netty-0.9:javaagent"))

MODIFY
instrumentation/reactor-netty/reactor-netty-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v1_0/ConnectionWrapper.java
instrumentation/reactor-netty/reactor-netty-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v1_0/ConnectionWrapper.java
package io.opentelemetry.javaagent.instrumentation.reactornetty.v1_0;
-import static io.opentelemetry.javaagent.instrumentation.reactornetty.v1_0.ReactorNettyTracer.tracer;
+import static io.opentelemetry.javaagent.instrumentation.reactornetty.v1_0.ReactorNettySingletons.connectInstrumenter;
import io.netty.channel.Channel;
import io.opentelemetry.context.Context;
-import java.net.SocketAddress;
+import io.opentelemetry.javaagent.instrumentation.netty.common.client.NettyConnectRequest;
import reactor.core.publisher.Mono;
public class ConnectionWrapper {
public static Mono<Channel> wrap(
- Context context, Context parentContext, SocketAddress remoteAddress, Mono<Channel> mono) {
- return mono.doOnError(
- throwable -> {
- tracer().endConnectionSpan(context, parentContext, remoteAddress, null, throwable);
- })
- .doOnSuccess(
- channel -> {
- if (context != null) {
- tracer().endConnectionSpan(context, parentContext, remoteAddress, channel, null);
- }
- });
+ Context context, NettyConnectRequest request, Mono<Channel> mono) {
+ return mono.doOnError(error -> connectInstrumenter().end(context, request, null, error))
+ .doOnSuccess(channel -> connectInstrumenter().end(context, request, channel, null));
}
}

ADD
instrumentation/reactor-netty/reactor-netty-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v1_0/ReactorNettySingletons.java
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.instrumentation.reactornetty.v1_0;
+
+import io.opentelemetry.instrumentation.api.config.Config;
+import io.opentelemetry.javaagent.instrumentation.netty.common.client.NettyClientInstrumenterFactory;
+import io.opentelemetry.javaagent.instrumentation.netty.common.client.NettyConnectInstrumenter;
+
+public final class ReactorNettySingletons {
+
+ private static final boolean alwaysCreateConnectSpan =
+ Config.get()
+ .getBoolean("otel.instrumentation.reactor-netty.always-create-connect-span", false);
+
+ private static final NettyConnectInstrumenter CONNECT_INSTRUMENTER;
+
+ static {
+ NettyClientInstrumenterFactory instrumenterFactory =
+ new NettyClientInstrumenterFactory(
+ "io.opentelemetry.reactor-netty-1.0", alwaysCreateConnectSpan);
+ CONNECT_INSTRUMENTER = instrumenterFactory.createConnectInstrumenter();
+ }
+
+ public static NettyConnectInstrumenter connectInstrumenter() {
+ return CONNECT_INSTRUMENTER;
+ }
+
+ private ReactorNettySingletons() {}
+}

DELETE
instrumentation/reactor-netty/reactor-netty-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v1_0/ReactorNettyTracer.java
-/*
- * Copyright The OpenTelemetry Authors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package io.opentelemetry.javaagent.instrumentation.reactornetty.v1_0;
-
-import static io.opentelemetry.api.trace.SpanKind.CLIENT;
-import static io.opentelemetry.api.trace.SpanKind.INTERNAL;
-import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.NetTransportValues.IP_TCP;
-import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.NetTransportValues.IP_UDP;
-
-import io.netty.channel.Channel;
-import io.netty.channel.socket.DatagramChannel;
-import io.opentelemetry.api.GlobalOpenTelemetry;
-import io.opentelemetry.api.trace.Span;
-import io.opentelemetry.api.trace.SpanBuilder;
-import io.opentelemetry.context.Context;
-import io.opentelemetry.instrumentation.api.config.Config;
-import io.opentelemetry.instrumentation.api.tracer.BaseTracer;
-import io.opentelemetry.instrumentation.api.tracer.net.NetPeerAttributes;
-import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
-import java.net.InetSocketAddress;
-import java.net.SocketAddress;
-
-public class ReactorNettyTracer extends BaseTracer {
- private static final ReactorNettyTracer TRACER = new ReactorNettyTracer();
-
- private static final boolean alwaysCreateConnectSpan =
- Config.get()
- .getBoolean("otel.instrumentation.reactor-netty.always-create-connect-span", false);
-
- protected ReactorNettyTracer() {
- super(GlobalOpenTelemetry.get());
- }
-
- public static ReactorNettyTracer tracer() {
- return TRACER;
- }
-
- public Context startConnectionSpan(Context parentContext, SocketAddress remoteAddress) {
- if (!alwaysCreateConnectSpan) {
- return null;
- }
-
- SpanBuilder spanBuilder = spanBuilder(parentContext, "CONNECT", INTERNAL);
- NetPeerAttributes.INSTANCE.setNetPeer(spanBuilder, (InetSocketAddress) remoteAddress);
-
- return parentContext.with(spanBuilder.startSpan());
- }
-
- public void endConnectionSpan(
- Context context,
- Context parentContext,
- SocketAddress remoteAddress,
- Channel channel,
- Throwable throwable) {
- if (alwaysCreateConnectSpan) {
- if (context != null) {
- // if context is present we started span in startConnectionSpan
- endConnectionSpan(context, channel, throwable);
- }
- } else if (throwable != null && shouldStartSpan(parentContext, CLIENT)) {
- // if we didn't start span in startConnectionSpan create a span only when the request fails
- // and when not inside a client span
- connectionFailure(parentContext, remoteAddress, channel, throwable);
- }
- }
-
- private void endConnectionSpan(Context context, Channel channel, Throwable throwable) {
- if (channel != null) {
- Span span = Span.fromContext(context);
- span.setAttribute(
- SemanticAttributes.NET_TRANSPORT, channel instanceof DatagramChannel ? IP_UDP : IP_TCP);
- NetPeerAttributes.INSTANCE.setNetPeer(span, (InetSocketAddress) channel.remoteAddress());
- }
- if (throwable != null) {
- endExceptionally(context, throwable);
- } else {
- end(context);
- }
- }
-
- private void connectionFailure(
- Context parentContext, SocketAddress remoteAddress, Channel channel, Throwable throwable) {
- SpanBuilder spanBuilder = spanBuilder(parentContext, "CONNECT", CLIENT);
- if (channel != null) {
- spanBuilder.setAttribute(
- SemanticAttributes.NET_TRANSPORT, channel instanceof DatagramChannel ? IP_UDP : IP_TCP);
- NetPeerAttributes.INSTANCE.setNetPeer(
- spanBuilder, (InetSocketAddress) channel.remoteAddress());
- } else if (remoteAddress != null) {
- NetPeerAttributes.INSTANCE.setNetPeer(spanBuilder, (InetSocketAddress) remoteAddress);
- }
-
- Context context = withClientSpan(parentContext, spanBuilder.startSpan());
- endExceptionally(context, throwable);
- }
-
- @Override
- protected String getInstrumentationName() {
- return "io.opentelemetry.reactor-netty-1.0";
- }
-}

MODIFY
instrumentation/reactor-netty/reactor-netty-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v1_0/TransportConnectorInstrumentation.java
instrumentation/reactor-netty/reactor-netty-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v1_0/TransportConnectorInstrumentation.java
package io.opentelemetry.javaagent.instrumentation.reactornetty.v1_0;
-import static io.opentelemetry.javaagent.instrumentation.reactornetty.v1_0.ReactorNettyTracer.tracer;
+import static io.opentelemetry.javaagent.instrumentation.reactornetty.v1_0.ReactorNettySingletons.connectInstrumenter;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
@@ -15,6 +15,7 @@ import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
+import io.opentelemetry.javaagent.instrumentation.netty.common.client.NettyConnectRequest;
import java.net.SocketAddress;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
@@ -40,31 +41,35 @@ public class TransportConnectorInstrumentation implements TypeInstrumentation {
public static void startConnect(
@Advice.Argument(1) SocketAddress remoteAddress,
@Advice.Local("otelContext") Context context,
- @Advice.Local("otelParentContext") Context parentContext,
+ @Advice.Local("otelRequest") NettyConnectRequest request,
@Advice.Local("otelScope") Scope scope) {
- parentContext = Java8BytecodeBridge.currentContext();
- context = tracer().startConnectionSpan(parentContext, remoteAddress);
- if (context != null) {
- scope = context.makeCurrent();
+
+ Context parentContext = Java8BytecodeBridge.currentContext();
+ request = NettyConnectRequest.create(remoteAddress);
+ if (!connectInstrumenter().shouldStart(parentContext, request)) {
+ return;
}
+
+ context = connectInstrumenter().start(parentContext, request);
+ scope = context.makeCurrent();
}
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void endConnect(
@Advice.Thrown Throwable throwable,
- @Advice.Argument(1) SocketAddress remoteAddress,
@Advice.Return(readOnly = false) Mono<Channel> mono,
@Advice.Local("otelContext") Context context,
- @Advice.Local("otelParentContext") Context parentContext,
+ @Advice.Local("otelRequest") NettyConnectRequest request,
@Advice.Local("otelScope") Scope scope) {
+
if (scope != null) {
scope.close();
}
if (throwable != null) {
- tracer().endConnectionSpan(context, parentContext, remoteAddress, null, throwable);
+ connectInstrumenter().end(context, request, null, throwable);
} else {
- mono = ConnectionWrapper.wrap(context, parentContext, remoteAddress, mono);
+ mono = ConnectionWrapper.wrap(context, request, mono);
}
}
}

MODIFY
instrumentation/reactor-netty/reactor-netty-1.0/javaagent/src/test/groovy/io/opentelemetry/javaagent/instrumentation/reactornetty/v1_0/ReactorNettyConnectionSpanTest.groovy
instrumentation/reactor-netty/reactor-netty-1.0/javaagent/src/test/groovy/io/opentelemetry/javaagent/instrumentation/reactornetty/v1_0/ReactorNettyConnectionSpanTest.groovy
@@ -115,6 +115,7 @@ class ReactorNettyConnectionSpanTest extends InstrumentationSpecification implem
status ERROR
errorEvent(connectException.class, connectException.message)
attributes {
+ "${SemanticAttributes.NET_TRANSPORT.key}" IP_TCP
"${SemanticAttributes.NET_PEER_NAME.key}" "localhost"
"${SemanticAttributes.NET_PEER_PORT.key}" PortUtils.UNUSABLE_PORT
"${SemanticAttributes.NET_PEER_IP.key}" { it == null || it == "127.0.0.1" }

Migrate reactor-netty CONNECT instrumentation to Instrumenter API (#4493)