Migrate Netty 4.x CONNECT instrumentation to Instrumenter API
DELETE
instrumentation/netty/netty-4-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/common/client/AbstractNettyHttpClientTracer.java
-/*
- * Copyright The OpenTelemetry Authors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package io.opentelemetry.javaagent.instrumentation.netty.common.client;
-
-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.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 abstract class AbstractNettyHttpClientTracer extends BaseTracer {
-
- private static final boolean alwaysCreateConnectSpan =
- Config.get().getBoolean("otel.instrumentation.netty.always-create-connect-span", false);
-
- 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);
- }
-}

MODIFY
instrumentation/netty/netty-4-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/common/client/ConnectionCompleteListener.java
instrumentation/netty/netty-4-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/common/client/ConnectionCompleteListener.java
@@ -12,25 +12,23 @@ import io.netty.util.concurrent.GenericFutureListener;
import io.opentelemetry.context.Context;
public class ConnectionCompleteListener implements GenericFutureListener<Future<Void>> {
+ private final NettyConnectInstrumenter instrumenter;
private final Context context;
- private final Context parentContext;
+ private final NettyConnectRequest request;
- public ConnectionCompleteListener(Context context, Context parentContext) {
+ public ConnectionCompleteListener(
+ NettyConnectInstrumenter instrumenter, Context context, NettyConnectRequest request) {
+ this.instrumenter = instrumenter;
this.context = context;
- this.parentContext = parentContext;
+ this.request = request;
}
@Override
public void operationComplete(Future<Void> future) {
- AbstractNettyHttpClientTracer tracer = NettyHttpClientTracerAccess.getTracer();
- if (tracer == null) {
- return;
- }
-
Channel channel = null;
if (future instanceof ChannelFuture) {
channel = ((ChannelFuture) future).channel();
}
- tracer.endConnectionSpan(context, parentContext, null, channel, future.cause());
+ instrumenter.end(context, request, channel, future.cause());
}
}

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
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;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
@@ -16,6 +19,9 @@ 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;
public NettyClientInstrumenterFactory(String instrumentationName) {
@@ -39,4 +45,25 @@ public final class NettyClientInstrumenterFactory {
.addRequestMetrics(HttpClientMetrics.get())
.newClientInstrumenter(new HttpRequestHeadersSetter());
}
+
+ public NettyConnectInstrumenter createConnectInstrumenter() {
+ NettyConnectNetAttributesExtractor netAttributesExtractor =
+ new NettyConnectNetAttributesExtractor();
+ Instrumenter<NettyConnectRequest, Channel> instrumenter =
+ Instrumenter.<NettyConnectRequest, Channel>builder(
+ GlobalOpenTelemetry.get(), instrumentationName, rq -> "CONNECT")
+ .addAttributesExtractor(netAttributesExtractor)
+ .addAttributesExtractor(PeerServiceAttributesExtractor.create(netAttributesExtractor))
+ .setTimeExtractors(
+ request -> request.timer().startTime(),
+ (request, channel, error) -> request.timer().now())
+ .newInstrumenter(
+ alwaysCreateConnectSpan
+ ? SpanKindExtractor.alwaysInternal()
+ : SpanKindExtractor.alwaysClient());
+
+ return alwaysCreateConnectSpan
+ ? new NettyConnectInstrumenterImpl(instrumenter)
+ : new NettyErrorOnlyConnectInstrumenter(instrumenter);
+ }
}

ADD
instrumentation/netty/netty-4-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/common/client/NettyConnectInstrumenter.java
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.instrumentation.netty.common.client;
+
+import io.netty.channel.Channel;
+import io.opentelemetry.context.Context;
+import javax.annotation.Nullable;
+
+public interface NettyConnectInstrumenter {
+
+ boolean shouldStart(Context parentContext, NettyConnectRequest request);
+
+ Context start(Context parentContext, NettyConnectRequest request);
+
+ void end(
+ Context context, NettyConnectRequest request, Channel channel, @Nullable Throwable error);
+}

ADD
instrumentation/netty/netty-4-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/common/client/NettyConnectInstrumenterImpl.java
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.instrumentation.netty.common.client;
+
+import io.netty.channel.Channel;
+import io.opentelemetry.context.Context;
+import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
+import javax.annotation.Nullable;
+
+final class NettyConnectInstrumenterImpl implements NettyConnectInstrumenter {
+
+ private final Instrumenter<NettyConnectRequest, Channel> instrumenter;
+
+ NettyConnectInstrumenterImpl(Instrumenter<NettyConnectRequest, Channel> instrumenter) {
+ this.instrumenter = instrumenter;
+ }
+
+ @Override
+ public boolean shouldStart(Context parentContext, NettyConnectRequest request) {
+ return instrumenter.shouldStart(parentContext, request);
+ }
+
+ @Override
+ public Context start(Context parentContext, NettyConnectRequest request) {
+ return instrumenter.start(parentContext, request);
+ }
+
+ @Override
+ public void end(
+ Context context, NettyConnectRequest request, Channel channel, @Nullable Throwable error) {
+ instrumenter.end(context, request, channel, error);
+ }
+}

ADD
instrumentation/netty/netty-4-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/common/client/NettyConnectNetAttributesExtractor.java
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.instrumentation.netty.common.client;
+
+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.instrumentation.api.instrumenter.net.InetSocketAddressNetClientAttributesExtractor;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import javax.annotation.Nullable;
+
+final class NettyConnectNetAttributesExtractor
+ extends InetSocketAddressNetClientAttributesExtractor<NettyConnectRequest, Channel> {
+
+ @Nullable
+ @Override
+ public InetSocketAddress getAddress(NettyConnectRequest request, @Nullable Channel channel) {
+ SocketAddress remoteAddress = null;
+ if (channel != null) {
+ remoteAddress = channel.remoteAddress();
+ }
+ // remote address on end() may be null when connection hasn't been established
+ if (remoteAddress == null) {
+ remoteAddress = request.remoteAddressOnStart();
+ }
+ if (remoteAddress instanceof InetSocketAddress) {
+ return (InetSocketAddress) remoteAddress;
+ }
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public String transport(NettyConnectRequest request, @Nullable Channel channel) {
+ return channel instanceof DatagramChannel ? IP_UDP : IP_TCP;
+ }
+}

ADD
instrumentation/netty/netty-4-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/common/client/NettyConnectRequest.java
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.instrumentation.netty.common.client;
+
+import com.google.auto.value.AutoValue;
+import java.net.SocketAddress;
+import javax.annotation.Nullable;
+
+@AutoValue
+public abstract class NettyConnectRequest {
+
+ public static NettyConnectRequest create(SocketAddress remoteAddress) {
+ return new AutoValue_NettyConnectRequest(Timer.start(), remoteAddress);
+ }
+
+ abstract Timer timer();
+
+ @Nullable
+ abstract SocketAddress remoteAddressOnStart();
+}

ADD
instrumentation/netty/netty-4-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/common/client/NettyErrorOnlyConnectInstrumenter.java
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.instrumentation.netty.common.client;
+
+import io.netty.channel.Channel;
+import io.opentelemetry.context.Context;
+import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
+import javax.annotation.Nullable;
+
+final class NettyErrorOnlyConnectInstrumenter implements NettyConnectInstrumenter {
+
+ private final Instrumenter<NettyConnectRequest, Channel> instrumenter;
+
+ NettyErrorOnlyConnectInstrumenter(Instrumenter<NettyConnectRequest, Channel> instrumenter) {
+ this.instrumenter = instrumenter;
+ }
+
+ @Override
+ public boolean shouldStart(Context parentContext, NettyConnectRequest request) {
+ // the "real" check is done on end() anyway
+ return true;
+ }
+
+ @Override
+ public Context start(Context parentContext, NettyConnectRequest request) {
+ return parentContext;
+ }
+
+ @Override
+ public void end(
+ Context context, NettyConnectRequest request, Channel channel, @Nullable Throwable error) {
+ if (error != null && instrumenter.shouldStart(context, request)) {
+ Context connectContext = instrumenter.start(context, request);
+ instrumenter.end(connectContext, request, channel, error);
+ }
+ }
+}

DELETE
instrumentation/netty/netty-4-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/common/client/NettyHttpClientTracerAccess.java
-/*
- * Copyright The OpenTelemetry Authors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package io.opentelemetry.javaagent.instrumentation.netty.common.client;
-
-import java.util.concurrent.atomic.AtomicReference;
-
-public class NettyHttpClientTracerAccess {
- private static final AtomicReference<AbstractNettyHttpClientTracer>
- nettyHttpClientTracerReference = new AtomicReference<>();
-
- public static AbstractNettyHttpClientTracer getTracer() {
- return nettyHttpClientTracerReference.get();
- }
-
- public static void setTracer(AbstractNettyHttpClientTracer tracer) {
- nettyHttpClientTracerReference.compareAndSet(null, tracer);
- }
-}

ADD
instrumentation/netty/netty-4-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/common/client/Timer.java
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.instrumentation.netty.common.client;
+
+import java.time.Instant;
+
+final class Timer {
+
+ static Timer start() {
+ return new Timer(Instant.now(), System.nanoTime());
+ }
+
+ private final Instant startTime;
+ private final long startNanoTime;
+
+ private Timer(Instant startTime, long startNanoTime) {
+ this.startTime = startTime;
+ this.startNanoTime = startNanoTime;
+ }
+
+ Instant startTime() {
+ return startTime;
+ }
+
+ Instant now() {
+ long durationNanos = System.nanoTime() - startNanoTime;
+ return startTime().plusNanos(durationNanos);
+ }
+}

MODIFY
instrumentation/netty/netty-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v4_0/BootstrapInstrumentation.java
instrumentation/netty/netty-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v4_0/BootstrapInstrumentation.java
package io.opentelemetry.javaagent.instrumentation.netty.v4_0;
-import static io.opentelemetry.javaagent.instrumentation.netty.v4_0.client.NettyHttpClientTracer.tracer;
-import static net.bytebuddy.matcher.ElementMatchers.isConstructor;
+import static io.opentelemetry.javaagent.instrumentation.netty.v4_0.client.NettyClientSingletons.connectInstrumenter;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
@@ -17,6 +16,7 @@ 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.ConnectionCompleteListener;
+import io.opentelemetry.javaagent.instrumentation.netty.common.client.NettyConnectRequest;
import java.net.SocketAddress;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
@@ -30,54 +30,48 @@ public class BootstrapInstrumentation implements TypeInstrumentation {
@Override
public void transform(TypeTransformer transformer) {
- transformer.applyAdviceToMethod(
- isConstructor(), BootstrapInstrumentation.class.getName() + "$InitAdvice");
transformer.applyAdviceToMethod(
named("doConnect").and(takesArgument(0, SocketAddress.class)),
BootstrapInstrumentation.class.getName() + "$ConnectAdvice");
}
- @SuppressWarnings("unused")
- public static class InitAdvice {
- @Advice.OnMethodEnter
- public static void enter() {
- // Ensure that tracer is initialized. Connection failure handling is initialized in the static
- // initializer of tracer which needs to be run before an attempt is made to establish
- // connection.
- tracer();
- }
- }
-
public static class ConnectAdvice {
@Advice.OnMethodEnter
public static void startConnect(
@Advice.Argument(0) 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(0) SocketAddress remoteAddress,
@Advice.Return ChannelFuture channelFuture,
@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 (scope == null) {
+ return;
}
+ scope.close();
if (throwable != null) {
- tracer().endConnectionSpan(context, parentContext, remoteAddress, null, throwable);
+ connectInstrumenter().end(context, request, null, throwable);
} else {
- channelFuture.addListener(new ConnectionCompleteListener(context, parentContext));
+ channelFuture.addListener(
+ new ConnectionCompleteListener(connectInstrumenter(), context, request));
}
}
}

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
@@ -9,20 +9,27 @@ import io.netty.handler.codec.http.HttpResponse;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.javaagent.instrumentation.netty.common.HttpRequestAndChannel;
import io.opentelemetry.javaagent.instrumentation.netty.common.client.NettyClientInstrumenterFactory;
+import io.opentelemetry.javaagent.instrumentation.netty.common.client.NettyConnectInstrumenter;
public final class NettyClientSingletons {
private static final Instrumenter<HttpRequestAndChannel, HttpResponse> INSTRUMENTER;
+ private static final NettyConnectInstrumenter CONNECT_INSTRUMENTER;
static {
NettyClientInstrumenterFactory factory =
new NettyClientInstrumenterFactory("io.opentelemetry.netty-4.0");
INSTRUMENTER = factory.createHttpInstrumenter();
+ CONNECT_INSTRUMENTER = factory.createConnectInstrumenter();
}
public static Instrumenter<HttpRequestAndChannel, HttpResponse> instrumenter() {
return INSTRUMENTER;
}
+ public static NettyConnectInstrumenter connectInstrumenter() {
+ return CONNECT_INSTRUMENTER;
+ }
+
private NettyClientSingletons() {}
}

DELETE
instrumentation/netty/netty-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v4_0/client/NettyHttpClientTracer.java
-/*
- * Copyright The OpenTelemetry Authors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package io.opentelemetry.javaagent.instrumentation.netty.v4_0.client;
-
-import io.opentelemetry.javaagent.instrumentation.netty.common.client.AbstractNettyHttpClientTracer;
-import io.opentelemetry.javaagent.instrumentation.netty.common.client.NettyHttpClientTracerAccess;
-
-public class NettyHttpClientTracer extends AbstractNettyHttpClientTracer {
- private static final NettyHttpClientTracer TRACER = new NettyHttpClientTracer();
-
- static {
- NettyHttpClientTracerAccess.setTracer(TRACER);
- }
-
- private NettyHttpClientTracer() {}
-
- public static NettyHttpClientTracer tracer() {
- return TRACER;
- }
-
- @Override
- protected String getInstrumentationName() {
- return "io.opentelemetry.netty-4.0";
- }
-}

MODIFY
instrumentation/netty/netty-4.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v4_1/BootstrapInstrumentation.java
instrumentation/netty/netty-4.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v4_1/BootstrapInstrumentation.java
package io.opentelemetry.javaagent.instrumentation.netty.v4_1;
-import static io.opentelemetry.javaagent.instrumentation.netty.v4_1.client.NettyHttpClientTracer.tracer;
-import static net.bytebuddy.matcher.ElementMatchers.isConstructor;
+import static io.opentelemetry.javaagent.instrumentation.netty.v4_1.client.NettyClientSingletons.connectInstrumenter;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
@@ -17,6 +16,7 @@ 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.ConnectionCompleteListener;
+import io.opentelemetry.javaagent.instrumentation.netty.common.client.NettyConnectRequest;
import java.net.SocketAddress;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
@@ -30,54 +30,48 @@ public class BootstrapInstrumentation implements TypeInstrumentation {
@Override
public void transform(TypeTransformer transformer) {
- transformer.applyAdviceToMethod(
- isConstructor(), BootstrapInstrumentation.class.getName() + "$InitAdvice");
transformer.applyAdviceToMethod(
named("doResolveAndConnect").and(takesArgument(0, SocketAddress.class)),
BootstrapInstrumentation.class.getName() + "$ConnectAdvice");
}
- @SuppressWarnings("unused")
- public static class InitAdvice {
- @Advice.OnMethodEnter
- public static void enter() {
- // Ensure that tracer is initialized. Connection failure handling is initialized in the static
- // initializer of tracer which needs to be run before an attempt is made to establish
- // connection.
- tracer();
- }
- }
-
public static class ConnectAdvice {
@Advice.OnMethodEnter
public static void startConnect(
@Advice.Argument(0) 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(0) SocketAddress remoteAddress,
@Advice.Return ChannelFuture channelFuture,
@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 (scope == null) {
+ return;
}
+ scope.close();
if (throwable != null) {
- tracer().endConnectionSpan(context, parentContext, remoteAddress, null, throwable);
+ connectInstrumenter().end(context, request, null, throwable);
} else {
- channelFuture.addListener(new ConnectionCompleteListener(context, parentContext));
+ channelFuture.addListener(
+ new ConnectionCompleteListener(connectInstrumenter(), context, request));
}
}
}

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
@@ -10,6 +10,7 @@ import io.netty.util.AttributeKey;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.javaagent.instrumentation.netty.common.HttpRequestAndChannel;
import io.opentelemetry.javaagent.instrumentation.netty.common.client.NettyClientInstrumenterFactory;
+import io.opentelemetry.javaagent.instrumentation.netty.common.client.NettyConnectInstrumenter;
public final class NettyClientSingletons {
@@ -19,16 +20,22 @@ public final class NettyClientSingletons {
AttributeKey.valueOf(NettyClientSingletons.class, "http-client-response");
private static final Instrumenter<HttpRequestAndChannel, HttpResponse> INSTRUMENTER;
+ private static final NettyConnectInstrumenter CONNECT_INSTRUMENTER;
static {
NettyClientInstrumenterFactory factory =
new NettyClientInstrumenterFactory("io.opentelemetry.netty-4.1");
INSTRUMENTER = factory.createHttpInstrumenter();
+ CONNECT_INSTRUMENTER = factory.createConnectInstrumenter();
}
public static Instrumenter<HttpRequestAndChannel, HttpResponse> instrumenter() {
return INSTRUMENTER;
}
+ public static NettyConnectInstrumenter connectInstrumenter() {
+ return CONNECT_INSTRUMENTER;
+ }
+
private NettyClientSingletons() {}
}

DELETE
instrumentation/netty/netty-4.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v4_1/client/NettyHttpClientTracer.java
-/*
- * Copyright The OpenTelemetry Authors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package io.opentelemetry.javaagent.instrumentation.netty.v4_1.client;
-
-import io.opentelemetry.javaagent.instrumentation.netty.common.client.AbstractNettyHttpClientTracer;
-import io.opentelemetry.javaagent.instrumentation.netty.common.client.NettyHttpClientTracerAccess;
-
-public class NettyHttpClientTracer extends AbstractNettyHttpClientTracer {
- private static final NettyHttpClientTracer TRACER = new NettyHttpClientTracer();
-
- static {
- NettyHttpClientTracerAccess.setTracer(TRACER);
- }
-
- private NettyHttpClientTracer() {}
-
- public static NettyHttpClientTracer tracer() {
- return TRACER;
- }
-
- @Override
- protected String getInstrumentationName() {
- return "io.opentelemetry.netty-4.1";
- }
-}

Migrate Netty 4.x CONNECT instrumentation to Instrumenter API (#4461)