Trace DNS resolution in Netty 4.1 (#4587)

* Trace DNS resolution in Netty 4.1

* Fix reactor-netty 0.9 tests

* Update instrumentation/netty/netty-4.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v4_1/client/InstrumentedAddressResolverGroup.java

Co-authored-by: Trask Stalnaker <trask.stalnaker@gmail.com>

Co-authored-by: Trask Stalnaker <trask.stalnaker@gmail.com>
This commit is contained in:
Mateusz Rzeszutek 2021-11-05 19:37:54 +01:00 committed by GitHub
parent f3ec9a215b
commit 958f1c039c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 352 additions and 144 deletions

View File

@ -7,7 +7,7 @@ package io.opentelemetry.javaagent.instrumentation.netty.v3_8;
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed;
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface; import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface;
import static io.opentelemetry.javaagent.instrumentation.netty.v3_8.client.NettyClientSingletons.connectInstrumenter; import static io.opentelemetry.javaagent.instrumentation.netty.v3_8.client.NettyClientSingletons.connectionInstrumenter;
import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.returns; import static net.bytebuddy.matcher.ElementMatchers.returns;
@ -19,7 +19,7 @@ import io.opentelemetry.instrumentation.api.field.VirtualField;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge; import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
import io.opentelemetry.javaagent.instrumentation.netty.common.NettyConnectRequest; import io.opentelemetry.javaagent.instrumentation.netty.common.NettyConnectionRequest;
import io.opentelemetry.javaagent.instrumentation.netty.v3_8.client.ConnectionListener; import io.opentelemetry.javaagent.instrumentation.netty.v3_8.client.ConnectionListener;
import java.net.SocketAddress; import java.net.SocketAddress;
import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.Advice;
@ -58,7 +58,7 @@ public class NettyChannelInstrumentation implements TypeInstrumentation {
@Advice.This Channel channel, @Advice.This Channel channel,
@Advice.Argument(0) SocketAddress remoteAddress, @Advice.Argument(0) SocketAddress remoteAddress,
@Advice.Local("otelParentContext") Context parentContext, @Advice.Local("otelParentContext") Context parentContext,
@Advice.Local("otelRequest") NettyConnectRequest request) { @Advice.Local("otelRequest") NettyConnectionRequest request) {
parentContext = Java8BytecodeBridge.currentContext(); parentContext = Java8BytecodeBridge.currentContext();
Span span = Java8BytecodeBridge.spanFromContext(parentContext); Span span = Java8BytecodeBridge.spanFromContext(parentContext);
@ -73,7 +73,7 @@ public class NettyChannelInstrumentation implements TypeInstrumentation {
} }
virtualField.set(channel, new NettyConnectionContext(parentContext)); virtualField.set(channel, new NettyConnectionContext(parentContext));
request = NettyConnectRequest.create(remoteAddress); request = NettyConnectionRequest.connect(remoteAddress);
} }
@Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class) @Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class)
@ -81,16 +81,16 @@ public class NettyChannelInstrumentation implements TypeInstrumentation {
@Advice.Return ChannelFuture channelFuture, @Advice.Return ChannelFuture channelFuture,
@Advice.Thrown Throwable error, @Advice.Thrown Throwable error,
@Advice.Local("otelParentContext") Context parentContext, @Advice.Local("otelParentContext") Context parentContext,
@Advice.Local("otelRequest") NettyConnectRequest request) { @Advice.Local("otelRequest") NettyConnectionRequest request) {
if (request == null) { if (request == null) {
return; return;
} }
if (error != null) { if (error != null) {
if (connectInstrumenter().shouldStart(parentContext, request)) { if (connectionInstrumenter().shouldStart(parentContext, request)) {
Context context = connectInstrumenter().start(parentContext, request); Context context = connectionInstrumenter().start(parentContext, request);
connectInstrumenter().end(context, request, null, error); connectionInstrumenter().end(context, request, null, error);
} }
} else { } else {
channelFuture.addListener(new ConnectionListener(parentContext, request)); channelFuture.addListener(new ConnectionListener(parentContext, request));

View File

@ -5,19 +5,19 @@
package io.opentelemetry.javaagent.instrumentation.netty.v3_8.client; package io.opentelemetry.javaagent.instrumentation.netty.v3_8.client;
import static io.opentelemetry.javaagent.instrumentation.netty.v3_8.client.NettyClientSingletons.connectInstrumenter; import static io.opentelemetry.javaagent.instrumentation.netty.v3_8.client.NettyClientSingletons.connectionInstrumenter;
import io.opentelemetry.context.Context; import io.opentelemetry.context.Context;
import io.opentelemetry.javaagent.instrumentation.netty.common.NettyConnectRequest; import io.opentelemetry.javaagent.instrumentation.netty.common.NettyConnectionRequest;
import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelFutureListener;
public final class ConnectionListener implements ChannelFutureListener { public final class ConnectionListener implements ChannelFutureListener {
private final Context parentContext; private final Context parentContext;
private final NettyConnectRequest request; private final NettyConnectionRequest request;
public ConnectionListener(Context parentContext, NettyConnectRequest request) { public ConnectionListener(Context parentContext, NettyConnectionRequest request) {
this.parentContext = parentContext; this.parentContext = parentContext;
this.request = request; this.request = request;
} }
@ -25,9 +25,9 @@ public final class ConnectionListener implements ChannelFutureListener {
@Override @Override
public void operationComplete(ChannelFuture future) { public void operationComplete(ChannelFuture future) {
Throwable cause = future.getCause(); Throwable cause = future.getCause();
if (cause != null && connectInstrumenter().shouldStart(parentContext, request)) { if (cause != null && connectionInstrumenter().shouldStart(parentContext, request)) {
Context context = connectInstrumenter().start(parentContext, request); Context context = connectionInstrumenter().start(parentContext, request);
connectInstrumenter().end(context, request, future.getChannel(), cause); connectionInstrumenter().end(context, request, future.getChannel(), cause);
} }
} }
} }

View File

@ -12,7 +12,7 @@ import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
import io.opentelemetry.javaagent.instrumentation.netty.common.NettyConnectRequest; import io.opentelemetry.javaagent.instrumentation.netty.common.NettyConnectionRequest;
import io.opentelemetry.javaagent.instrumentation.netty.common.NettyErrorHolder; import io.opentelemetry.javaagent.instrumentation.netty.common.NettyErrorHolder;
import io.opentelemetry.javaagent.instrumentation.netty.v3_8.HttpRequestAndChannel; import io.opentelemetry.javaagent.instrumentation.netty.v3_8.HttpRequestAndChannel;
import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.Channel;
@ -23,7 +23,7 @@ public final class NettyClientSingletons {
private static final String INSTRUMENTATION_NAME = "io.opentelemetry.netty-3.8"; private static final String INSTRUMENTATION_NAME = "io.opentelemetry.netty-3.8";
private static final Instrumenter<HttpRequestAndChannel, HttpResponse> INSTRUMENTER; private static final Instrumenter<HttpRequestAndChannel, HttpResponse> INSTRUMENTER;
private static final Instrumenter<NettyConnectRequest, Channel> CONNECT_INSTRUMENTER; private static final Instrumenter<NettyConnectionRequest, Channel> CONNECTION_INSTRUMENTER;
static { static {
NettyHttpClientAttributesExtractor httpClientAttributesExtractor = NettyHttpClientAttributesExtractor httpClientAttributesExtractor =
@ -48,9 +48,9 @@ public final class NettyClientSingletons {
NettyConnectNetAttributesExtractor nettyConnectAttributesExtractor = NettyConnectNetAttributesExtractor nettyConnectAttributesExtractor =
new NettyConnectNetAttributesExtractor(); new NettyConnectNetAttributesExtractor();
CONNECT_INSTRUMENTER = CONNECTION_INSTRUMENTER =
Instrumenter.<NettyConnectRequest, Channel>builder( Instrumenter.<NettyConnectionRequest, Channel>builder(
GlobalOpenTelemetry.get(), INSTRUMENTATION_NAME, rq -> "CONNECT") GlobalOpenTelemetry.get(), INSTRUMENTATION_NAME, NettyConnectionRequest::spanName)
.addAttributesExtractor(nettyConnectAttributesExtractor) .addAttributesExtractor(nettyConnectAttributesExtractor)
.addAttributesExtractor( .addAttributesExtractor(
PeerServiceAttributesExtractor.create(nettyConnectAttributesExtractor)) PeerServiceAttributesExtractor.create(nettyConnectAttributesExtractor))
@ -64,8 +64,8 @@ public final class NettyClientSingletons {
return INSTRUMENTER; return INSTRUMENTER;
} }
public static Instrumenter<NettyConnectRequest, Channel> connectInstrumenter() { public static Instrumenter<NettyConnectionRequest, Channel> connectionInstrumenter() {
return CONNECT_INSTRUMENTER; return CONNECTION_INSTRUMENTER;
} }
private NettyClientSingletons() {} private NettyClientSingletons() {}

View File

@ -9,7 +9,7 @@ import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.NetTr
import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.NetTransportValues.IP_UDP; import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.NetTransportValues.IP_UDP;
import io.opentelemetry.instrumentation.api.instrumenter.net.InetSocketAddressNetClientAttributesExtractor; import io.opentelemetry.instrumentation.api.instrumenter.net.InetSocketAddressNetClientAttributesExtractor;
import io.opentelemetry.javaagent.instrumentation.netty.common.NettyConnectRequest; import io.opentelemetry.javaagent.instrumentation.netty.common.NettyConnectionRequest;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.SocketAddress; import java.net.SocketAddress;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -17,11 +17,11 @@ import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.socket.DatagramChannel; import org.jboss.netty.channel.socket.DatagramChannel;
final class NettyConnectNetAttributesExtractor final class NettyConnectNetAttributesExtractor
extends InetSocketAddressNetClientAttributesExtractor<NettyConnectRequest, Channel> { extends InetSocketAddressNetClientAttributesExtractor<NettyConnectionRequest, Channel> {
@Nullable @Nullable
@Override @Override
public InetSocketAddress getAddress(NettyConnectRequest request, @Nullable Channel channel) { public InetSocketAddress getAddress(NettyConnectionRequest request, @Nullable Channel channel) {
SocketAddress remoteAddress = null; SocketAddress remoteAddress = null;
if (channel != null) { if (channel != null) {
remoteAddress = channel.getRemoteAddress(); remoteAddress = channel.getRemoteAddress();
@ -37,7 +37,7 @@ final class NettyConnectNetAttributesExtractor
} }
@Override @Override
public String transport(NettyConnectRequest request, @Nullable Channel channel) { public String transport(NettyConnectionRequest request, @Nullable Channel channel) {
return channel instanceof DatagramChannel ? IP_UDP : IP_TCP; return channel instanceof DatagramChannel ? IP_UDP : IP_TCP;
} }
} }

View File

@ -10,15 +10,15 @@ import io.netty.channel.ChannelFuture;
import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener; import io.netty.util.concurrent.GenericFutureListener;
import io.opentelemetry.context.Context; import io.opentelemetry.context.Context;
import io.opentelemetry.javaagent.instrumentation.netty.common.NettyConnectRequest; import io.opentelemetry.javaagent.instrumentation.netty.common.NettyConnectionRequest;
public class ConnectionCompleteListener implements GenericFutureListener<Future<Void>> { public class ConnectionCompleteListener implements GenericFutureListener<Future<Void>> {
private final NettyConnectInstrumenter instrumenter; private final NettyConnectionInstrumenter instrumenter;
private final Context context; private final Context context;
private final NettyConnectRequest request; private final NettyConnectionRequest request;
public ConnectionCompleteListener( public ConnectionCompleteListener(
NettyConnectInstrumenter instrumenter, Context context, NettyConnectRequest request) { NettyConnectionInstrumenter instrumenter, Context context, NettyConnectionRequest request) {
this.instrumenter = instrumenter; this.instrumenter = instrumenter;
this.context = context; this.context = context;
this.request = request; this.request = request;

View File

@ -15,7 +15,7 @@ import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
import io.opentelemetry.javaagent.instrumentation.netty.common.HttpRequestAndChannel; import io.opentelemetry.javaagent.instrumentation.netty.common.HttpRequestAndChannel;
import io.opentelemetry.javaagent.instrumentation.netty.common.NettyConnectRequest; import io.opentelemetry.javaagent.instrumentation.netty.common.NettyConnectionRequest;
public final class NettyClientInstrumenterFactory { public final class NettyClientInstrumenterFactory {
@ -46,12 +46,12 @@ public final class NettyClientInstrumenterFactory {
.newClientInstrumenter(new HttpRequestHeadersSetter()); .newClientInstrumenter(new HttpRequestHeadersSetter());
} }
public NettyConnectInstrumenter createConnectInstrumenter() { public NettyConnectionInstrumenter createConnectionInstrumenter() {
NettyConnectNetAttributesExtractor netAttributesExtractor = NettyConnectNetAttributesExtractor netAttributesExtractor =
new NettyConnectNetAttributesExtractor(); new NettyConnectNetAttributesExtractor();
Instrumenter<NettyConnectRequest, Channel> instrumenter = Instrumenter<NettyConnectionRequest, Channel> instrumenter =
Instrumenter.<NettyConnectRequest, Channel>builder( Instrumenter.<NettyConnectionRequest, Channel>builder(
GlobalOpenTelemetry.get(), instrumentationName, rq -> "CONNECT") GlobalOpenTelemetry.get(), instrumentationName, NettyConnectionRequest::spanName)
.addAttributesExtractor(netAttributesExtractor) .addAttributesExtractor(netAttributesExtractor)
.addAttributesExtractor(PeerServiceAttributesExtractor.create(netAttributesExtractor)) .addAttributesExtractor(PeerServiceAttributesExtractor.create(netAttributesExtractor))
.setTimeExtractors( .setTimeExtractors(
@ -63,7 +63,7 @@ public final class NettyClientInstrumenterFactory {
: SpanKindExtractor.alwaysClient()); : SpanKindExtractor.alwaysClient());
return alwaysCreateConnectSpan return alwaysCreateConnectSpan
? new NettyConnectInstrumenterImpl(instrumenter) ? new NettyConnectionInstrumenterImpl(instrumenter)
: new NettyErrorOnlyConnectInstrumenter(instrumenter); : new NettyErrorOnlyConnectionInstrumenter(instrumenter);
} }
} }

View File

@ -11,17 +11,17 @@ import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.NetTr
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.netty.channel.socket.DatagramChannel; import io.netty.channel.socket.DatagramChannel;
import io.opentelemetry.instrumentation.api.instrumenter.net.InetSocketAddressNetClientAttributesExtractor; import io.opentelemetry.instrumentation.api.instrumenter.net.InetSocketAddressNetClientAttributesExtractor;
import io.opentelemetry.javaagent.instrumentation.netty.common.NettyConnectRequest; import io.opentelemetry.javaagent.instrumentation.netty.common.NettyConnectionRequest;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.SocketAddress; import java.net.SocketAddress;
import javax.annotation.Nullable; import javax.annotation.Nullable;
final class NettyConnectNetAttributesExtractor final class NettyConnectNetAttributesExtractor
extends InetSocketAddressNetClientAttributesExtractor<NettyConnectRequest, Channel> { extends InetSocketAddressNetClientAttributesExtractor<NettyConnectionRequest, Channel> {
@Nullable @Nullable
@Override @Override
public InetSocketAddress getAddress(NettyConnectRequest request, @Nullable Channel channel) { public InetSocketAddress getAddress(NettyConnectionRequest request, @Nullable Channel channel) {
SocketAddress remoteAddress = null; SocketAddress remoteAddress = null;
if (channel != null) { if (channel != null) {
remoteAddress = channel.remoteAddress(); remoteAddress = channel.remoteAddress();
@ -37,7 +37,7 @@ final class NettyConnectNetAttributesExtractor
} }
@Override @Override
public String transport(NettyConnectRequest request, @Nullable Channel channel) { public String transport(NettyConnectionRequest request, @Nullable Channel channel) {
return channel instanceof DatagramChannel ? IP_UDP : IP_TCP; return channel instanceof DatagramChannel ? IP_UDP : IP_TCP;
} }
} }

View File

@ -7,15 +7,15 @@ package io.opentelemetry.javaagent.instrumentation.netty.common.client;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.opentelemetry.context.Context; import io.opentelemetry.context.Context;
import io.opentelemetry.javaagent.instrumentation.netty.common.NettyConnectRequest; import io.opentelemetry.javaagent.instrumentation.netty.common.NettyConnectionRequest;
import javax.annotation.Nullable; import javax.annotation.Nullable;
public interface NettyConnectInstrumenter { public interface NettyConnectionInstrumenter {
boolean shouldStart(Context parentContext, NettyConnectRequest request); boolean shouldStart(Context parentContext, NettyConnectionRequest request);
Context start(Context parentContext, NettyConnectRequest request); Context start(Context parentContext, NettyConnectionRequest request);
void end( void end(
Context context, NettyConnectRequest request, Channel channel, @Nullable Throwable error); Context context, NettyConnectionRequest request, Channel channel, @Nullable Throwable error);
} }

View File

@ -8,30 +8,30 @@ package io.opentelemetry.javaagent.instrumentation.netty.common.client;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.opentelemetry.context.Context; import io.opentelemetry.context.Context;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.javaagent.instrumentation.netty.common.NettyConnectRequest; import io.opentelemetry.javaagent.instrumentation.netty.common.NettyConnectionRequest;
import javax.annotation.Nullable; import javax.annotation.Nullable;
final class NettyConnectInstrumenterImpl implements NettyConnectInstrumenter { final class NettyConnectionInstrumenterImpl implements NettyConnectionInstrumenter {
private final Instrumenter<NettyConnectRequest, Channel> instrumenter; private final Instrumenter<NettyConnectionRequest, Channel> instrumenter;
NettyConnectInstrumenterImpl(Instrumenter<NettyConnectRequest, Channel> instrumenter) { NettyConnectionInstrumenterImpl(Instrumenter<NettyConnectionRequest, Channel> instrumenter) {
this.instrumenter = instrumenter; this.instrumenter = instrumenter;
} }
@Override @Override
public boolean shouldStart(Context parentContext, NettyConnectRequest request) { public boolean shouldStart(Context parentContext, NettyConnectionRequest request) {
return instrumenter.shouldStart(parentContext, request); return instrumenter.shouldStart(parentContext, request);
} }
@Override @Override
public Context start(Context parentContext, NettyConnectRequest request) { public Context start(Context parentContext, NettyConnectionRequest request) {
return instrumenter.start(parentContext, request); return instrumenter.start(parentContext, request);
} }
@Override @Override
public void end( public void end(
Context context, NettyConnectRequest request, Channel channel, @Nullable Throwable error) { Context context, NettyConnectionRequest request, Channel channel, @Nullable Throwable error) {
instrumenter.end(context, request, channel, error); instrumenter.end(context, request, channel, error);
} }
} }

View File

@ -8,31 +8,31 @@ package io.opentelemetry.javaagent.instrumentation.netty.common.client;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.opentelemetry.context.Context; import io.opentelemetry.context.Context;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.javaagent.instrumentation.netty.common.NettyConnectRequest; import io.opentelemetry.javaagent.instrumentation.netty.common.NettyConnectionRequest;
import javax.annotation.Nullable; import javax.annotation.Nullable;
final class NettyErrorOnlyConnectInstrumenter implements NettyConnectInstrumenter { final class NettyErrorOnlyConnectionInstrumenter implements NettyConnectionInstrumenter {
private final Instrumenter<NettyConnectRequest, Channel> instrumenter; private final Instrumenter<NettyConnectionRequest, Channel> instrumenter;
NettyErrorOnlyConnectInstrumenter(Instrumenter<NettyConnectRequest, Channel> instrumenter) { NettyErrorOnlyConnectionInstrumenter(Instrumenter<NettyConnectionRequest, Channel> instrumenter) {
this.instrumenter = instrumenter; this.instrumenter = instrumenter;
} }
@Override @Override
public boolean shouldStart(Context parentContext, NettyConnectRequest request) { public boolean shouldStart(Context parentContext, NettyConnectionRequest request) {
// the "real" check is done on end() anyway // the "real" check is done on end() anyway
return true; return true;
} }
@Override @Override
public Context start(Context parentContext, NettyConnectRequest request) { public Context start(Context parentContext, NettyConnectionRequest request) {
return parentContext; return parentContext;
} }
@Override @Override
public void end( public void end(
Context context, NettyConnectRequest request, Channel channel, @Nullable Throwable error) { Context context, NettyConnectionRequest request, Channel channel, @Nullable Throwable error) {
if (error != null && instrumenter.shouldStart(context, request)) { if (error != null && instrumenter.shouldStart(context, request)) {
Context connectContext = instrumenter.start(context, request); Context connectContext = instrumenter.start(context, request);
instrumenter.end(connectContext, request, channel, error); instrumenter.end(connectContext, request, channel, error);

View File

@ -5,7 +5,7 @@
package io.opentelemetry.javaagent.instrumentation.netty.v4_0; package io.opentelemetry.javaagent.instrumentation.netty.v4_0;
import static io.opentelemetry.javaagent.instrumentation.netty.v4_0.client.NettyClientSingletons.connectInstrumenter; import static io.opentelemetry.javaagent.instrumentation.netty.v4_0.client.NettyClientSingletons.connectionInstrumenter;
import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
@ -15,7 +15,7 @@ import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge; import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
import io.opentelemetry.javaagent.instrumentation.netty.common.NettyConnectRequest; import io.opentelemetry.javaagent.instrumentation.netty.common.NettyConnectionRequest;
import io.opentelemetry.javaagent.instrumentation.netty.common.client.ConnectionCompleteListener; import io.opentelemetry.javaagent.instrumentation.netty.common.client.ConnectionCompleteListener;
import java.net.SocketAddress; import java.net.SocketAddress;
import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.Advice;
@ -40,17 +40,17 @@ public class BootstrapInstrumentation implements TypeInstrumentation {
public static void startConnect( public static void startConnect(
@Advice.Argument(0) SocketAddress remoteAddress, @Advice.Argument(0) SocketAddress remoteAddress,
@Advice.Local("otelContext") Context context, @Advice.Local("otelContext") Context context,
@Advice.Local("otelRequest") NettyConnectRequest request, @Advice.Local("otelRequest") NettyConnectionRequest request,
@Advice.Local("otelScope") Scope scope) { @Advice.Local("otelScope") Scope scope) {
Context parentContext = Java8BytecodeBridge.currentContext(); Context parentContext = Java8BytecodeBridge.currentContext();
request = NettyConnectRequest.create(remoteAddress); request = NettyConnectionRequest.connect(remoteAddress);
if (!connectInstrumenter().shouldStart(parentContext, request)) { if (!connectionInstrumenter().shouldStart(parentContext, request)) {
return; return;
} }
context = connectInstrumenter().start(parentContext, request); context = connectionInstrumenter().start(parentContext, request);
scope = context.makeCurrent(); scope = context.makeCurrent();
} }
@ -59,7 +59,7 @@ public class BootstrapInstrumentation implements TypeInstrumentation {
@Advice.Thrown Throwable throwable, @Advice.Thrown Throwable throwable,
@Advice.Return ChannelFuture channelFuture, @Advice.Return ChannelFuture channelFuture,
@Advice.Local("otelContext") Context context, @Advice.Local("otelContext") Context context,
@Advice.Local("otelRequest") NettyConnectRequest request, @Advice.Local("otelRequest") NettyConnectionRequest request,
@Advice.Local("otelScope") Scope scope) { @Advice.Local("otelScope") Scope scope) {
if (scope == null) { if (scope == null) {
@ -68,10 +68,10 @@ public class BootstrapInstrumentation implements TypeInstrumentation {
scope.close(); scope.close();
if (throwable != null) { if (throwable != null) {
connectInstrumenter().end(context, request, null, throwable); connectionInstrumenter().end(context, request, null, throwable);
} else { } else {
channelFuture.addListener( channelFuture.addListener(
new ConnectionCompleteListener(connectInstrumenter(), context, request)); new ConnectionCompleteListener(connectionInstrumenter(), context, request));
} }
} }
} }

View File

@ -10,7 +10,7 @@ import io.opentelemetry.instrumentation.api.config.Config;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.javaagent.instrumentation.netty.common.HttpRequestAndChannel; 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.NettyClientInstrumenterFactory;
import io.opentelemetry.javaagent.instrumentation.netty.common.client.NettyConnectInstrumenter; import io.opentelemetry.javaagent.instrumentation.netty.common.client.NettyConnectionInstrumenter;
public final class NettyClientSingletons { public final class NettyClientSingletons {
@ -18,21 +18,21 @@ public final class NettyClientSingletons {
Config.get().getBoolean("otel.instrumentation.netty.always-create-connect-span", false); Config.get().getBoolean("otel.instrumentation.netty.always-create-connect-span", false);
private static final Instrumenter<HttpRequestAndChannel, HttpResponse> INSTRUMENTER; private static final Instrumenter<HttpRequestAndChannel, HttpResponse> INSTRUMENTER;
private static final NettyConnectInstrumenter CONNECT_INSTRUMENTER; private static final NettyConnectionInstrumenter CONNECTION_INSTRUMENTER;
static { static {
NettyClientInstrumenterFactory factory = NettyClientInstrumenterFactory factory =
new NettyClientInstrumenterFactory("io.opentelemetry.netty-4.0", alwaysCreateConnectSpan); new NettyClientInstrumenterFactory("io.opentelemetry.netty-4.0", alwaysCreateConnectSpan);
INSTRUMENTER = factory.createHttpInstrumenter(); INSTRUMENTER = factory.createHttpInstrumenter();
CONNECT_INSTRUMENTER = factory.createConnectInstrumenter(); CONNECTION_INSTRUMENTER = factory.createConnectionInstrumenter();
} }
public static Instrumenter<HttpRequestAndChannel, HttpResponse> instrumenter() { public static Instrumenter<HttpRequestAndChannel, HttpResponse> instrumenter() {
return INSTRUMENTER; return INSTRUMENTER;
} }
public static NettyConnectInstrumenter connectInstrumenter() { public static NettyConnectionInstrumenter connectionInstrumenter() {
return CONNECT_INSTRUMENTER; return CONNECTION_INSTRUMENTER;
} }
private NettyClientSingletons() {} private NettyClientSingletons() {}

View File

@ -5,18 +5,24 @@
package io.opentelemetry.javaagent.instrumentation.netty.v4_1; package io.opentelemetry.javaagent.instrumentation.netty.v4_1;
import static io.opentelemetry.javaagent.instrumentation.netty.v4_1.client.NettyClientSingletons.connectInstrumenter; import static io.opentelemetry.javaagent.instrumentation.netty.v4_1.client.NettyClientSingletons.connectionInstrumenter;
import static net.bytebuddy.matcher.ElementMatchers.isConstructor;
import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
import io.netty.channel.ChannelFuture; import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelPromise;
import io.netty.resolver.AddressResolverGroup;
import io.netty.resolver.DefaultAddressResolverGroup;
import io.opentelemetry.context.Context; import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope; import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge; import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
import io.opentelemetry.javaagent.instrumentation.netty.common.NettyConnectRequest; import io.opentelemetry.javaagent.instrumentation.netty.common.NettyConnectionRequest;
import io.opentelemetry.javaagent.instrumentation.netty.common.client.ConnectionCompleteListener; import io.opentelemetry.javaagent.instrumentation.netty.common.client.ConnectionCompleteListener;
import io.opentelemetry.javaagent.instrumentation.netty.v4_1.client.InstrumentedAddressResolverGroup;
import java.net.SocketAddress; import java.net.SocketAddress;
import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.description.type.TypeDescription;
@ -31,35 +37,68 @@ public class BootstrapInstrumentation implements TypeInstrumentation {
@Override @Override
public void transform(TypeTransformer transformer) { public void transform(TypeTransformer transformer) {
transformer.applyAdviceToMethod( transformer.applyAdviceToMethod(
named("doResolveAndConnect").and(takesArgument(0, SocketAddress.class)), isConstructor().and(takesArguments(0)),
BootstrapInstrumentation.class.getName() + "$ConstructorAdvice");
transformer.applyAdviceToMethod(
named("resolver")
.and(takesArguments(1))
.and(takesArgument(0, named("io.netty.resolver.AddressResolverGroup"))),
BootstrapInstrumentation.class.getName() + "$SetResolverAdvice");
transformer.applyAdviceToMethod(
named("doConnect")
.and(takesArguments(3))
.and(takesArgument(0, SocketAddress.class))
.and(takesArgument(2, named("io.netty.channel.ChannelPromise"))),
BootstrapInstrumentation.class.getName() + "$ConnectAdvice"); BootstrapInstrumentation.class.getName() + "$ConnectAdvice");
} }
@SuppressWarnings("unused")
public static class ConstructorAdvice {
@Advice.OnMethodExit(suppress = Throwable.class)
public static void onExit(@Advice.This Bootstrap bootstrap) {
// this is already the default value, but we're calling the resolver() method to invoke its
// instrumentation
bootstrap.resolver(DefaultAddressResolverGroup.INSTANCE);
}
}
@SuppressWarnings("unused")
public static class SetResolverAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class)
public static void onEnter(
@Advice.Argument(value = 0, readOnly = false) AddressResolverGroup<?> resolver) {
resolver = InstrumentedAddressResolverGroup.wrap(connectionInstrumenter(), resolver);
}
}
@SuppressWarnings("unused")
public static class ConnectAdvice { public static class ConnectAdvice {
@Advice.OnMethodEnter @Advice.OnMethodEnter
public static void startConnect( public static void startConnect(
@Advice.Argument(0) SocketAddress remoteAddress, @Advice.Argument(0) SocketAddress remoteAddress,
@Advice.Local("otelContext") Context context, @Advice.Local("otelContext") Context context,
@Advice.Local("otelRequest") NettyConnectRequest request, @Advice.Local("otelRequest") NettyConnectionRequest request,
@Advice.Local("otelScope") Scope scope) { @Advice.Local("otelScope") Scope scope) {
Context parentContext = Java8BytecodeBridge.currentContext(); Context parentContext = Java8BytecodeBridge.currentContext();
request = NettyConnectRequest.create(remoteAddress); request = NettyConnectionRequest.connect(remoteAddress);
if (!connectInstrumenter().shouldStart(parentContext, request)) { if (!connectionInstrumenter().shouldStart(parentContext, request)) {
return; return;
} }
context = connectInstrumenter().start(parentContext, request); context = connectionInstrumenter().start(parentContext, request);
scope = context.makeCurrent(); scope = context.makeCurrent();
} }
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void endConnect( public static void endConnect(
@Advice.Thrown Throwable throwable, @Advice.Thrown Throwable throwable,
@Advice.Return ChannelFuture channelFuture, @Advice.Argument(2) ChannelPromise channelPromise,
@Advice.Local("otelContext") Context context, @Advice.Local("otelContext") Context context,
@Advice.Local("otelRequest") NettyConnectRequest request, @Advice.Local("otelRequest") NettyConnectionRequest request,
@Advice.Local("otelScope") Scope scope) { @Advice.Local("otelScope") Scope scope) {
if (scope == null) { if (scope == null) {
@ -68,10 +107,10 @@ public class BootstrapInstrumentation implements TypeInstrumentation {
scope.close(); scope.close();
if (throwable != null) { if (throwable != null) {
connectInstrumenter().end(context, request, null, throwable); connectionInstrumenter().end(context, request, null, throwable);
} else { } else {
channelFuture.addListener( channelPromise.addListener(
new ConnectionCompleteListener(connectInstrumenter(), context, request)); new ConnectionCompleteListener(connectionInstrumenter(), context, request));
} }
} }
} }

View File

@ -0,0 +1,123 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.netty.v4_1.client;
import static io.opentelemetry.javaagent.instrumentation.netty.v4_1.client.NettyClientSingletons.connectionInstrumenter;
import io.netty.resolver.AddressResolver;
import io.netty.resolver.AddressResolverGroup;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import io.opentelemetry.context.Context;
import io.opentelemetry.javaagent.instrumentation.netty.common.NettyConnectionRequest;
import io.opentelemetry.javaagent.instrumentation.netty.common.client.NettyConnectionInstrumenter;
import java.net.SocketAddress;
import java.util.List;
import java.util.function.Supplier;
public final class InstrumentedAddressResolverGroup<T extends SocketAddress>
extends AddressResolverGroup<T> {
public static <T extends SocketAddress> AddressResolverGroup<T> wrap(
NettyConnectionInstrumenter instrumenter, AddressResolverGroup<T> delegate) {
if (delegate instanceof InstrumentedAddressResolverGroup) {
return delegate;
}
return new InstrumentedAddressResolverGroup<>(connectionInstrumenter(), delegate);
}
private final NettyConnectionInstrumenter instrumenter;
private final AddressResolverGroup<T> delegate;
private InstrumentedAddressResolverGroup(
NettyConnectionInstrumenter instrumenter, AddressResolverGroup<T> delegate) {
this.instrumenter = instrumenter;
this.delegate = delegate;
}
@Override
public AddressResolver<T> getResolver(EventExecutor executor) {
return new InstrumentedResolver<>(instrumenter, delegate.getResolver(executor));
}
@Override
public void close() {
delegate.close();
}
@Override
protected AddressResolver<T> newResolver(EventExecutor eventExecutor) {
// this method is called from the super class's implementation of `getResolver` which is
// overridden by this class
throw new UnsupportedOperationException("This method should never be called");
}
private static final class InstrumentedResolver<T extends SocketAddress>
implements AddressResolver<T> {
private final NettyConnectionInstrumenter instrumenter;
private final AddressResolver<T> delegate;
private InstrumentedResolver(
NettyConnectionInstrumenter instrumenter, AddressResolver<T> delegate) {
this.instrumenter = instrumenter;
this.delegate = delegate;
}
@Override
public boolean isSupported(SocketAddress socketAddress) {
return delegate.isSupported(socketAddress);
}
@Override
public boolean isResolved(SocketAddress socketAddress) {
return delegate.isResolved(socketAddress);
}
@Override
public Future<T> resolve(SocketAddress socketAddress) {
return instrumentResolve(socketAddress, () -> delegate.resolve(socketAddress));
}
@Override
public Future<T> resolve(SocketAddress socketAddress, Promise<T> promise) {
return instrumentResolve(socketAddress, () -> delegate.resolve(socketAddress, promise));
}
@Override
public Future<List<T>> resolveAll(SocketAddress socketAddress) {
return instrumentResolve(socketAddress, () -> delegate.resolveAll(socketAddress));
}
@Override
public Future<List<T>> resolveAll(SocketAddress socketAddress, Promise<List<T>> promise) {
return instrumentResolve(socketAddress, () -> delegate.resolveAll(socketAddress, promise));
}
private <U> Future<U> instrumentResolve(
SocketAddress socketAddress, Supplier<Future<U>> resolveFunc) {
Context parentContext = Context.current();
NettyConnectionRequest request = NettyConnectionRequest.resolve(socketAddress);
if (!instrumenter.shouldStart(parentContext, request)) {
return resolveFunc.get();
}
Context context = instrumenter.start(parentContext, request);
try {
Future<U> future = resolveFunc.get();
return future.addListener(f -> instrumenter.end(context, request, null, f.cause()));
} catch (Throwable t) {
instrumenter.end(context, request, null, t);
throw t;
}
}
@Override
public void close() {
delegate.close();
}
}
}

View File

@ -11,7 +11,7 @@ import io.opentelemetry.instrumentation.api.config.Config;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.javaagent.instrumentation.netty.common.HttpRequestAndChannel; 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.NettyClientInstrumenterFactory;
import io.opentelemetry.javaagent.instrumentation.netty.common.client.NettyConnectInstrumenter; import io.opentelemetry.javaagent.instrumentation.netty.common.client.NettyConnectionInstrumenter;
public final class NettyClientSingletons { public final class NettyClientSingletons {
@ -24,21 +24,21 @@ public final class NettyClientSingletons {
Config.get().getBoolean("otel.instrumentation.netty.always-create-connect-span", false); Config.get().getBoolean("otel.instrumentation.netty.always-create-connect-span", false);
private static final Instrumenter<HttpRequestAndChannel, HttpResponse> INSTRUMENTER; private static final Instrumenter<HttpRequestAndChannel, HttpResponse> INSTRUMENTER;
private static final NettyConnectInstrumenter CONNECT_INSTRUMENTER; private static final NettyConnectionInstrumenter CONNECTION_INSTRUMENTER;
static { static {
NettyClientInstrumenterFactory factory = NettyClientInstrumenterFactory factory =
new NettyClientInstrumenterFactory("io.opentelemetry.netty-4.1", alwaysCreateConnectSpan); new NettyClientInstrumenterFactory("io.opentelemetry.netty-4.1", alwaysCreateConnectSpan);
INSTRUMENTER = factory.createHttpInstrumenter(); INSTRUMENTER = factory.createHttpInstrumenter();
CONNECT_INSTRUMENTER = factory.createConnectInstrumenter(); CONNECTION_INSTRUMENTER = factory.createConnectionInstrumenter();
} }
public static Instrumenter<HttpRequestAndChannel, HttpResponse> instrumenter() { public static Instrumenter<HttpRequestAndChannel, HttpResponse> instrumenter() {
return INSTRUMENTER; return INSTRUMENTER;
} }
public static NettyConnectInstrumenter connectInstrumenter() { public static NettyConnectionInstrumenter connectionInstrumenter() {
return CONNECT_INSTRUMENTER; return CONNECTION_INSTRUMENTER;
} }
private NettyClientSingletons() {} private NettyClientSingletons() {}

View File

@ -94,13 +94,23 @@ class Netty41ConnectionSpanTest extends InstrumentationSpecification implements
then: then:
responseCode == 200 responseCode == 200
assertTraces(1) { assertTraces(1) {
trace(0, 4) { trace(0, 5) {
span(0) { span(0) {
name "parent" name "parent"
kind INTERNAL kind INTERNAL
hasNoParent() hasNoParent()
} }
span(1) { span(1) {
name "RESOLVE"
kind INTERNAL
childOf span(0)
attributes {
"${SemanticAttributes.NET_TRANSPORT.key}" IP_TCP
"${SemanticAttributes.NET_PEER_NAME.key}" uri.host
"${SemanticAttributes.NET_PEER_PORT.key}" uri.port
}
}
span(2) {
name "CONNECT" name "CONNECT"
kind INTERNAL kind INTERNAL
childOf(span(0)) childOf(span(0))
@ -111,15 +121,15 @@ class Netty41ConnectionSpanTest extends InstrumentationSpecification implements
"${SemanticAttributes.NET_PEER_IP.key}" "127.0.0.1" "${SemanticAttributes.NET_PEER_IP.key}" "127.0.0.1"
} }
} }
span(2) { span(3) {
name "HTTP GET" name "HTTP GET"
kind CLIENT kind CLIENT
childOf(span(0)) childOf(span(0))
} }
span(3) { span(4) {
name "test-http-server" name "test-http-server"
kind SERVER kind SERVER
childOf(span(2)) childOf(span(3))
} }
} }
} }
@ -138,7 +148,7 @@ class Netty41ConnectionSpanTest extends InstrumentationSpecification implements
and: and:
assertTraces(1) { assertTraces(1) {
trace(0, 2) { trace(0, 3) {
span(0) { span(0) {
name "parent" name "parent"
kind INTERNAL kind INTERNAL
@ -147,9 +157,19 @@ class Netty41ConnectionSpanTest extends InstrumentationSpecification implements
errorEvent(thrownException.class, thrownException.message) errorEvent(thrownException.class, thrownException.message)
} }
span(1) { span(1) {
name "RESOLVE"
kind INTERNAL
childOf span(0)
attributes {
"${SemanticAttributes.NET_TRANSPORT.key}" IP_TCP
"${SemanticAttributes.NET_PEER_NAME.key}" uri.host
"${SemanticAttributes.NET_PEER_PORT.key}" uri.port
}
}
span(2) {
name "CONNECT" name "CONNECT"
kind INTERNAL kind INTERNAL
childOf(span(0)) childOf span(0)
status ERROR status ERROR
errorEvent(thrownException.class, thrownException.message) errorEvent(thrownException.class, thrownException.message)
attributes { attributes {

View File

@ -1,23 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.netty.common;
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);
}
public abstract Timer timer();
@Nullable
public abstract SocketAddress remoteAddressOnStart();
}

View File

@ -0,0 +1,29 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.netty.common;
import com.google.auto.value.AutoValue;
import java.net.SocketAddress;
import javax.annotation.Nullable;
@AutoValue
public abstract class NettyConnectionRequest {
public static NettyConnectionRequest resolve(SocketAddress remoteAddress) {
return new AutoValue_NettyConnectionRequest("RESOLVE", Timer.start(), remoteAddress);
}
public static NettyConnectionRequest connect(SocketAddress remoteAddress) {
return new AutoValue_NettyConnectionRequest("CONNECT", Timer.start(), remoteAddress);
}
public abstract String spanName();
public abstract Timer timer();
@Nullable
public abstract SocketAddress remoteAddressOnStart();
}

View File

@ -50,13 +50,23 @@ class ReactorNettyConnectionSpanTest extends InstrumentationSpecification implem
then: then:
responseCode == 200 responseCode == 200
assertTraces(1) { assertTraces(1) {
trace(0, 4) { trace(0, 5) {
span(0) { span(0) {
name "parent" name "parent"
kind INTERNAL kind INTERNAL
hasNoParent() hasNoParent()
} }
span(1) { span(1) {
name "RESOLVE"
kind INTERNAL
childOf span(0)
attributes {
"${SemanticAttributes.NET_TRANSPORT.key}" IP_TCP
"${SemanticAttributes.NET_PEER_NAME.key}" "localhost"
"${SemanticAttributes.NET_PEER_PORT.key}" server.httpPort()
}
}
span(2) {
name "CONNECT" name "CONNECT"
kind INTERNAL kind INTERNAL
childOf(span(0)) childOf(span(0))
@ -67,15 +77,15 @@ class ReactorNettyConnectionSpanTest extends InstrumentationSpecification implem
"${SemanticAttributes.NET_PEER_IP.key}" "127.0.0.1" "${SemanticAttributes.NET_PEER_IP.key}" "127.0.0.1"
} }
} }
span(2) { span(3) {
name "HTTP GET" name "HTTP GET"
kind CLIENT kind CLIENT
childOf(span(0)) childOf(span(0))
} }
span(3) { span(4) {
name "test-http-server" name "test-http-server"
kind SERVER kind SERVER
childOf(span(2)) childOf(span(3))
} }
} }
} }
@ -100,7 +110,7 @@ class ReactorNettyConnectionSpanTest extends InstrumentationSpecification implem
and: and:
assertTraces(1) { assertTraces(1) {
trace(0, 2) { trace(0, 3) {
span(0) { span(0) {
name "parent" name "parent"
kind INTERNAL kind INTERNAL
@ -109,6 +119,16 @@ class ReactorNettyConnectionSpanTest extends InstrumentationSpecification implem
errorEvent(thrownException.class, thrownException.message) errorEvent(thrownException.class, thrownException.message)
} }
span(1) { span(1) {
name "RESOLVE"
kind INTERNAL
childOf span(0)
attributes {
"${SemanticAttributes.NET_TRANSPORT.key}" IP_TCP
"${SemanticAttributes.NET_PEER_NAME.key}" "localhost"
"${SemanticAttributes.NET_PEER_PORT.key}" PortUtils.UNUSABLE_PORT
}
}
span(2) {
name "CONNECT" name "CONNECT"
kind INTERNAL kind INTERNAL
childOf(span(0)) childOf(span(0))

View File

@ -5,18 +5,18 @@
package io.opentelemetry.javaagent.instrumentation.reactornetty.v1_0; package io.opentelemetry.javaagent.instrumentation.reactornetty.v1_0;
import static io.opentelemetry.javaagent.instrumentation.reactornetty.v1_0.ReactorNettySingletons.connectInstrumenter; import static io.opentelemetry.javaagent.instrumentation.reactornetty.v1_0.ReactorNettySingletons.connectionInstrumenter;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.opentelemetry.context.Context; import io.opentelemetry.context.Context;
import io.opentelemetry.javaagent.instrumentation.netty.common.NettyConnectRequest; import io.opentelemetry.javaagent.instrumentation.netty.common.NettyConnectionRequest;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
public class ConnectionWrapper { public class ConnectionWrapper {
public static Mono<Channel> wrap( public static Mono<Channel> wrap(
Context context, NettyConnectRequest request, Mono<Channel> mono) { Context context, NettyConnectionRequest request, Mono<Channel> mono) {
return mono.doOnError(error -> connectInstrumenter().end(context, request, null, error)) return mono.doOnError(error -> connectionInstrumenter().end(context, request, null, error))
.doOnSuccess(channel -> connectInstrumenter().end(context, request, channel, null)); .doOnSuccess(channel -> connectionInstrumenter().end(context, request, channel, null));
} }
} }

View File

@ -7,7 +7,7 @@ package io.opentelemetry.javaagent.instrumentation.reactornetty.v1_0;
import io.opentelemetry.instrumentation.api.config.Config; import io.opentelemetry.instrumentation.api.config.Config;
import io.opentelemetry.javaagent.instrumentation.netty.common.client.NettyClientInstrumenterFactory; import io.opentelemetry.javaagent.instrumentation.netty.common.client.NettyClientInstrumenterFactory;
import io.opentelemetry.javaagent.instrumentation.netty.common.client.NettyConnectInstrumenter; import io.opentelemetry.javaagent.instrumentation.netty.common.client.NettyConnectionInstrumenter;
public final class ReactorNettySingletons { public final class ReactorNettySingletons {
@ -15,17 +15,17 @@ public final class ReactorNettySingletons {
Config.get() Config.get()
.getBoolean("otel.instrumentation.reactor-netty.always-create-connect-span", false); .getBoolean("otel.instrumentation.reactor-netty.always-create-connect-span", false);
private static final NettyConnectInstrumenter CONNECT_INSTRUMENTER; private static final NettyConnectionInstrumenter CONNECTION_INSTRUMENTER;
static { static {
NettyClientInstrumenterFactory instrumenterFactory = NettyClientInstrumenterFactory instrumenterFactory =
new NettyClientInstrumenterFactory( new NettyClientInstrumenterFactory(
"io.opentelemetry.reactor-netty-1.0", alwaysCreateConnectSpan); "io.opentelemetry.reactor-netty-1.0", alwaysCreateConnectSpan);
CONNECT_INSTRUMENTER = instrumenterFactory.createConnectInstrumenter(); CONNECTION_INSTRUMENTER = instrumenterFactory.createConnectionInstrumenter();
} }
public static NettyConnectInstrumenter connectInstrumenter() { public static NettyConnectionInstrumenter connectionInstrumenter() {
return CONNECT_INSTRUMENTER; return CONNECTION_INSTRUMENTER;
} }
private ReactorNettySingletons() {} private ReactorNettySingletons() {}

View File

@ -5,7 +5,7 @@
package io.opentelemetry.javaagent.instrumentation.reactornetty.v1_0; package io.opentelemetry.javaagent.instrumentation.reactornetty.v1_0;
import static io.opentelemetry.javaagent.instrumentation.reactornetty.v1_0.ReactorNettySingletons.connectInstrumenter; import static io.opentelemetry.javaagent.instrumentation.reactornetty.v1_0.ReactorNettySingletons.connectionInstrumenter;
import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
@ -15,7 +15,7 @@ import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge; import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
import io.opentelemetry.javaagent.instrumentation.netty.common.NettyConnectRequest; import io.opentelemetry.javaagent.instrumentation.netty.common.NettyConnectionRequest;
import java.net.SocketAddress; import java.net.SocketAddress;
import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.description.type.TypeDescription;
@ -41,16 +41,16 @@ public class TransportConnectorInstrumentation implements TypeInstrumentation {
public static void startConnect( public static void startConnect(
@Advice.Argument(1) SocketAddress remoteAddress, @Advice.Argument(1) SocketAddress remoteAddress,
@Advice.Local("otelContext") Context context, @Advice.Local("otelContext") Context context,
@Advice.Local("otelRequest") NettyConnectRequest request, @Advice.Local("otelRequest") NettyConnectionRequest request,
@Advice.Local("otelScope") Scope scope) { @Advice.Local("otelScope") Scope scope) {
Context parentContext = Java8BytecodeBridge.currentContext(); Context parentContext = Java8BytecodeBridge.currentContext();
request = NettyConnectRequest.create(remoteAddress); request = NettyConnectionRequest.connect(remoteAddress);
if (!connectInstrumenter().shouldStart(parentContext, request)) { if (!connectionInstrumenter().shouldStart(parentContext, request)) {
return; return;
} }
context = connectInstrumenter().start(parentContext, request); context = connectionInstrumenter().start(parentContext, request);
scope = context.makeCurrent(); scope = context.makeCurrent();
} }
@ -59,7 +59,7 @@ public class TransportConnectorInstrumentation implements TypeInstrumentation {
@Advice.Thrown Throwable throwable, @Advice.Thrown Throwable throwable,
@Advice.Return(readOnly = false) Mono<Channel> mono, @Advice.Return(readOnly = false) Mono<Channel> mono,
@Advice.Local("otelContext") Context context, @Advice.Local("otelContext") Context context,
@Advice.Local("otelRequest") NettyConnectRequest request, @Advice.Local("otelRequest") NettyConnectionRequest request,
@Advice.Local("otelScope") Scope scope) { @Advice.Local("otelScope") Scope scope) {
if (scope != null) { if (scope != null) {
@ -67,7 +67,7 @@ public class TransportConnectorInstrumentation implements TypeInstrumentation {
} }
if (throwable != null) { if (throwable != null) {
connectInstrumenter().end(context, request, null, throwable); connectionInstrumenter().end(context, request, null, throwable);
} else { } else {
mono = ConnectionWrapper.wrap(context, request, mono); mono = ConnectionWrapper.wrap(context, request, mono);
} }