Migrate netty-3.8 server instrumentation to Instrumenter API
MODIFY
instrumentation/netty/netty-3.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v3_8/DefaultChannelPipelineInstrumentation.java
instrumentation/netty/netty-3.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v3_8/DefaultChannelPipelineInstrumentation.java
package io.opentelemetry.javaagent.instrumentation.netty.v3_8;
-import static io.opentelemetry.javaagent.instrumentation.netty.v3_8.server.NettyHttpServerTracer.tracer;
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
@@ -13,6 +12,7 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
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.v3_8.server.NettyServerErrorHandler;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
@@ -39,7 +39,7 @@ public class DefaultChannelPipelineInstrumentation implements TypeInstrumentatio
@Advice.OnMethodEnter
public static void onEnter(@Advice.Argument(1) Throwable throwable) {
if (throwable != null) {
- tracer().onException(Java8BytecodeBridge.currentContext(), throwable);
+ NettyServerErrorHandler.onError(Java8BytecodeBridge.currentContext(), throwable);
}
}
}

ADD
instrumentation/netty/netty-3.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v3_8/server/HttpRequestAndChannel.java
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.instrumentation.netty.v3_8.server;
+
+import com.google.auto.value.AutoValue;
+import org.jboss.netty.channel.Channel;
+import org.jboss.netty.handler.codec.http.HttpRequest;
+
+@AutoValue
+abstract class HttpRequestAndChannel {
+
+ public static HttpRequestAndChannel create(HttpRequest request, Channel channel) {
+ return new AutoValue_HttpRequestAndChannel(request, channel);
+ }
+
+ abstract HttpRequest request();
+
+ abstract Channel channel();
+}

MODIFY
instrumentation/netty/netty-3.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v3_8/server/HttpServerRequestTracingHandler.java
instrumentation/netty/netty-3.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v3_8/server/HttpServerRequestTracingHandler.java
package io.opentelemetry.javaagent.instrumentation.netty.v3_8.server;
-import static io.opentelemetry.javaagent.instrumentation.netty.v3_8.server.NettyHttpServerTracer.tracer;
+import static io.opentelemetry.javaagent.instrumentation.netty.v3_8.server.NettyServerSingletons.instrumenter;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.instrumentation.api.field.VirtualField;
-import io.opentelemetry.javaagent.instrumentation.netty.v3_8.NettyRequestContexts;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.MessageEvent;
@@ -19,35 +18,40 @@ import org.jboss.netty.handler.codec.http.HttpRequest;
public class HttpServerRequestTracingHandler extends SimpleChannelUpstreamHandler {
- private static final VirtualField<Channel, NettyRequestContexts> requestContextsField =
- VirtualField.find(Channel.class, NettyRequestContexts.class);
+ private static final VirtualField<Channel, NettyServerRequestAndContext> requestAndContextField =
+ VirtualField.find(Channel.class, NettyServerRequestAndContext.class);
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent event) {
Object message = event.getMessage();
if (!(message instanceof HttpRequest)) {
- NettyRequestContexts requestContexts = requestContextsField.get(ctx.getChannel());
- if (requestContexts == null) {
+ NettyServerRequestAndContext requestAndContext = requestAndContextField.get(ctx.getChannel());
+ if (requestAndContext == null) {
ctx.sendUpstream(event);
} else {
- try (Scope ignored = requestContexts.context().makeCurrent()) {
+ try (Scope ignored = requestAndContext.context().makeCurrent()) {
ctx.sendUpstream(event);
}
}
return;
}
- HttpRequest request = (HttpRequest) message;
+ Context parentContext = Context.current();
+ HttpRequestAndChannel request =
+ HttpRequestAndChannel.create((HttpRequest) message, ctx.getChannel());
+ if (!instrumenter().shouldStart(parentContext, request)) {
+ ctx.sendUpstream(event);
+ }
- Context context =
- tracer().startSpan(request, ctx.getChannel(), null, "HTTP " + request.getMethod());
- requestContextsField.set(ctx.getChannel(), NettyRequestContexts.create(null, context));
+ Context context = instrumenter().start(parentContext, request);
+ requestAndContextField.set(
+ ctx.getChannel(), NettyServerRequestAndContext.create(request, context));
try (Scope ignored = context.makeCurrent()) {
ctx.sendUpstream(event);
// the span is ended normally in HttpServerResponseTracingHandler
} catch (Throwable throwable) {
- tracer().endExceptionally(context, throwable);
+ instrumenter().end(context, request, null, throwable);
throw throwable;
}
}

MODIFY
instrumentation/netty/netty-3.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v3_8/server/HttpServerResponseTracingHandler.java
instrumentation/netty/netty-3.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v3_8/server/HttpServerResponseTracingHandler.java
package io.opentelemetry.javaagent.instrumentation.netty.v3_8.server;
-import static io.opentelemetry.javaagent.instrumentation.netty.v3_8.server.NettyHttpServerTracer.tracer;
+import static io.opentelemetry.javaagent.instrumentation.netty.v3_8.server.NettyServerSingletons.instrumenter;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.instrumentation.api.field.VirtualField;
-import io.opentelemetry.javaagent.instrumentation.netty.v3_8.NettyRequestContexts;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.MessageEvent;
@@ -19,24 +18,27 @@ import org.jboss.netty.handler.codec.http.HttpResponse;
public class HttpServerResponseTracingHandler extends SimpleChannelDownstreamHandler {
- private static final VirtualField<Channel, NettyRequestContexts> requestContextsField =
- VirtualField.find(Channel.class, NettyRequestContexts.class);
+ private static final VirtualField<Channel, NettyServerRequestAndContext> requestAndContextField =
+ VirtualField.find(Channel.class, NettyServerRequestAndContext.class);
@Override
public void writeRequested(ChannelHandlerContext ctx, MessageEvent msg) {
- NettyRequestContexts requestContexts = requestContextsField.get(ctx.getChannel());
+ NettyServerRequestAndContext requestAndContext = requestAndContextField.get(ctx.getChannel());
- if (requestContexts == null || !(msg.getMessage() instanceof HttpResponse)) {
+ if (requestAndContext == null || !(msg.getMessage() instanceof HttpResponse)) {
ctx.sendDownstream(msg);
return;
}
- Context context = requestContexts.context();
+ Context context = requestAndContext.context();
+ HttpRequestAndChannel request = requestAndContext.request();
+ HttpResponse response = (HttpResponse) msg.getMessage();
+
try (Scope ignored = context.makeCurrent()) {
ctx.sendDownstream(msg);
- tracer().end(context, (HttpResponse) msg.getMessage());
+ instrumenter().end(context, request, response, null);
} catch (Throwable throwable) {
- tracer().endExceptionally(context, throwable);
+ instrumenter().end(context, request, response, throwable);
throw throwable;
}
}

ADD
instrumentation/netty/netty-3.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v3_8/server/NettyHeadersGetter.java
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.instrumentation.netty.v3_8.server;
+
+import io.opentelemetry.context.propagation.TextMapGetter;
+import javax.annotation.Nullable;
+
+final class NettyHeadersGetter implements TextMapGetter<HttpRequestAndChannel> {
+
+ @Override
+ public Iterable<String> keys(HttpRequestAndChannel requestAndChannel) {
+ return requestAndChannel.request().headers().names();
+ }
+
+ @Nullable
+ @Override
+ public String get(@Nullable HttpRequestAndChannel requestAndChannel, String s) {
+ return requestAndChannel.request().headers().get(s);
+ }
+}

ADD
instrumentation/netty/netty-3.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v3_8/server/NettyHttpServerAttributesExtractor.java
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.instrumentation.netty.v3_8.server;
+
+import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerAttributesExtractor;
+import java.util.List;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.jboss.netty.handler.codec.http.HttpResponse;
+
+final class NettyHttpServerAttributesExtractor
+ extends HttpServerAttributesExtractor<HttpRequestAndChannel, HttpResponse> {
+
+ @Override
+ protected String method(HttpRequestAndChannel requestAndChannel) {
+ return requestAndChannel.request().getMethod().getName();
+ }
+
+ @Override
+ protected List<String> requestHeader(HttpRequestAndChannel requestAndChannel, String name) {
+ return requestAndChannel.request().headers().getAll(name);
+ }
+
+ @Override
+ protected @Nullable Long requestContentLength(
+ HttpRequestAndChannel requestAndChannel, @Nullable HttpResponse response) {
+ return null;
+ }
+
+ @Override
+ protected @Nullable Long requestContentLengthUncompressed(
+ HttpRequestAndChannel requestAndChannel, @Nullable HttpResponse response) {
+ return null;
+ }
+
+ @Override
+ protected Integer statusCode(HttpRequestAndChannel requestAndChannel, HttpResponse response) {
+ return response.getStatus().getCode();
+ }
+
+ @Override
+ protected @Nullable Long responseContentLength(
+ HttpRequestAndChannel requestAndChannel, HttpResponse response) {
+ return null;
+ }
+
+ @Override
+ protected @Nullable Long responseContentLengthUncompressed(
+ HttpRequestAndChannel requestAndChannel, HttpResponse response) {
+ return null;
+ }
+
+ @Override
+ protected List<String> responseHeader(
+ HttpRequestAndChannel requestAndChannel, HttpResponse response, String name) {
+ return response.headers().getAll(name);
+ }
+
+ @Override
+ protected String flavor(HttpRequestAndChannel requestAndChannel) {
+ String flavor = requestAndChannel.request().getProtocolVersion().toString();
+ if (flavor.startsWith("HTTP/")) {
+ flavor = flavor.substring("HTTP/".length());
+ }
+ return flavor;
+ }
+
+ @Override
+ protected String target(HttpRequestAndChannel requestAndChannel) {
+ return requestAndChannel.request().getUri();
+ }
+
+ @Override
+ protected @Nullable String route(HttpRequestAndChannel requestAndChannel) {
+ return null;
+ }
+
+ @Override
+ protected @Nullable String scheme(HttpRequestAndChannel requestAndChannel) {
+ return null;
+ }
+
+ @Override
+ protected @Nullable String serverName(
+ HttpRequestAndChannel requestAndChannel, @Nullable HttpResponse response) {
+ return null;
+ }
+}

DELETE
instrumentation/netty/netty-3.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v3_8/server/NettyHttpServerTracer.java
-/*
- * Copyright The OpenTelemetry Authors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package io.opentelemetry.javaagent.instrumentation.netty.v3_8.server;
-
-import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.HOST;
-
-import io.opentelemetry.context.Context;
-import io.opentelemetry.context.propagation.TextMapGetter;
-import io.opentelemetry.instrumentation.api.tracer.HttpServerTracer;
-import java.net.InetSocketAddress;
-import java.net.SocketAddress;
-import org.checkerframework.checker.nullness.qual.Nullable;
-import org.jboss.netty.channel.Channel;
-import org.jboss.netty.handler.codec.http.HttpRequest;
-import org.jboss.netty.handler.codec.http.HttpResponse;
-
-public class NettyHttpServerTracer
- extends HttpServerTracer<HttpRequest, HttpResponse, Channel, Void> {
- private static final NettyHttpServerTracer TRACER = new NettyHttpServerTracer();
-
- public static NettyHttpServerTracer tracer() {
- return TRACER;
- }
-
- @Override
- protected String method(HttpRequest httpRequest) {
- return httpRequest.getMethod().getName();
- }
-
- @Override
- protected String requestHeader(HttpRequest httpRequest, String name) {
- return httpRequest.headers().get(name);
- }
-
- @Override
- protected int responseStatus(HttpResponse httpResponse) {
- return httpResponse.getStatus().getCode();
- }
-
- @Override
- protected void attachServerContext(Context context, Void unused) {}
-
- @Override
- public Context getServerContext(Void unused) {
- return null;
- }
-
- @Override
- protected String url(HttpRequest request) {
- String uri = request.getUri();
- if (isRelativeUrl(uri) && request.headers().contains(HOST)) {
- return "http://" + request.headers().get(HOST) + request.getUri();
- } else {
- return uri;
- }
- }
-
- @Override
- @Nullable
- protected String scheme(HttpRequest request) {
- return null;
- }
-
- @Override
- @Nullable
- protected String host(HttpRequest request) {
- return null;
- }
-
- @Override
- @Nullable
- protected String target(HttpRequest request) {
- return null;
- }
-
- @Override
- protected String peerHostIp(Channel channel) {
- SocketAddress socketAddress = channel.getRemoteAddress();
- if (socketAddress instanceof InetSocketAddress) {
- return ((InetSocketAddress) socketAddress).getAddress().getHostAddress();
- }
- return null;
- }
-
- @Override
- protected String flavor(Channel channel, HttpRequest request) {
- return request.getProtocolVersion().toString();
- }
-
- @Override
- protected TextMapGetter<HttpRequest> getGetter() {
- return NettyRequestExtractAdapter.GETTER;
- }
-
- @Override
- protected String getInstrumentationName() {
- return "io.opentelemetry.netty-3.8";
- }
-
- @Override
- protected Integer peerPort(Channel channel) {
- SocketAddress socketAddress = channel.getRemoteAddress();
- if (socketAddress instanceof InetSocketAddress) {
- return ((InetSocketAddress) socketAddress).getPort();
- }
- return null;
- }
-}

ADD
instrumentation/netty/netty-3.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v3_8/server/NettyNetServerAttributesExtractor.java
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.instrumentation.netty.v3_8.server;
+
+import io.opentelemetry.instrumentation.api.instrumenter.net.InetSocketAddressNetServerAttributesExtractor;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.jboss.netty.handler.codec.http.HttpResponse;
+
+final class NettyNetServerAttributesExtractor
+ extends InetSocketAddressNetServerAttributesExtractor<HttpRequestAndChannel, HttpResponse> {
+
+ @Override
+ public @Nullable String transport(HttpRequestAndChannel requestAndChannel) {
+ return null;
+ }
+
+ @Override
+ public @Nullable InetSocketAddress getAddress(HttpRequestAndChannel requestAndChannel) {
+ SocketAddress address = requestAndChannel.channel().getRemoteAddress();
+ if (address instanceof InetSocketAddress) {
+ return (InetSocketAddress) address;
+ }
+ return null;
+ }
+}

DELETE
instrumentation/netty/netty-3.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v3_8/server/NettyRequestExtractAdapter.java
-/*
- * Copyright The OpenTelemetry Authors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package io.opentelemetry.javaagent.instrumentation.netty.v3_8.server;
-
-import io.opentelemetry.context.propagation.TextMapGetter;
-import org.jboss.netty.handler.codec.http.HttpRequest;
-
-public class NettyRequestExtractAdapter implements TextMapGetter<HttpRequest> {
-
- public static final NettyRequestExtractAdapter GETTER = new NettyRequestExtractAdapter();
-
- @Override
- public Iterable<String> keys(HttpRequest request) {
- return request.headers().names();
- }
-
- @Override
- public String get(HttpRequest request, String key) {
- return request.headers().get(key);
- }
-}

ADD
instrumentation/netty/netty-3.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v3_8/server/NettyServerErrorHandler.java
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.instrumentation.netty.v3_8.server;
+
+import io.opentelemetry.api.trace.Span;
+import io.opentelemetry.api.trace.StatusCode;
+import io.opentelemetry.context.Context;
+import io.opentelemetry.instrumentation.api.instrumenter.ErrorCauseExtractor;
+
+public final class NettyServerErrorHandler {
+
+ // copied from BaseTracer#onException()
+ public static void onError(Context context, Throwable error) {
+ Span span = Span.fromContext(context);
+ span.setStatus(StatusCode.ERROR);
+ span.recordException(ErrorCauseExtractor.jdk().extractCause(error));
+ }
+
+ private NettyServerErrorHandler() {}
+}

ADD
instrumentation/netty/netty-3.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v3_8/server/NettyServerRequestAndContext.java
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.instrumentation.netty.v3_8.server;
+
+import com.google.auto.value.AutoValue;
+import io.opentelemetry.context.Context;
+
+@AutoValue
+abstract class NettyServerRequestAndContext {
+
+ static NettyServerRequestAndContext create(HttpRequestAndChannel request, Context context) {
+ return new AutoValue_NettyServerRequestAndContext(request, context);
+ }
+
+ abstract HttpRequestAndChannel request();
+
+ abstract Context context();
+}

ADD
instrumentation/netty/netty-3.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v3_8/server/NettyServerSingletons.java
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.instrumentation.netty.v3_8.server;
+
+import io.opentelemetry.api.GlobalOpenTelemetry;
+import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
+import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerMetrics;
+import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
+import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
+import org.jboss.netty.handler.codec.http.HttpResponse;
+
+final class NettyServerSingletons {
+
+ private static final Instrumenter<HttpRequestAndChannel, HttpResponse> INSTRUMENTER;
+
+ static {
+ NettyHttpServerAttributesExtractor httpServerAttributesExtractor =
+ new NettyHttpServerAttributesExtractor();
+
+ INSTRUMENTER =
+ Instrumenter.<HttpRequestAndChannel, HttpResponse>newBuilder(
+ GlobalOpenTelemetry.get(),
+ "io.opentelemetry.netty-3.8",
+ HttpSpanNameExtractor.create(httpServerAttributesExtractor))
+ .setSpanStatusExtractor(HttpSpanStatusExtractor.create(httpServerAttributesExtractor))
+ .addAttributesExtractor(httpServerAttributesExtractor)
+ .addAttributesExtractor(new NettyNetServerAttributesExtractor())
+ .addRequestMetrics(HttpServerMetrics.get())
+ .newServerInstrumenter(new NettyHeadersGetter());
+ }
+
+ public static Instrumenter<HttpRequestAndChannel, HttpResponse> instrumenter() {
+ return INSTRUMENTER;
+ }
+
+ private NettyServerSingletons() {}
+}

MODIFY
instrumentation/netty/netty-3.8/javaagent/src/test/groovy/Netty38ServerTest.groovy
instrumentation/netty/netty-3.8/javaagent/src/test/groovy/Netty38ServerTest.groovy
* SPDX-License-Identifier: Apache-2.0
*/
-import io.opentelemetry.api.common.AttributeKey
import io.opentelemetry.instrumentation.test.AgentTestTrait
import io.opentelemetry.instrumentation.test.base.HttpServerTest
-import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
import org.jboss.netty.bootstrap.ServerBootstrap
import org.jboss.netty.buffer.ChannelBuffer
import org.jboss.netty.buffer.ChannelBuffers
@@ -167,11 +165,4 @@ class Netty38ServerTest extends HttpServerTest<ServerBootstrap> implements Agent
boolean testConcurrency() {
return true
}
-
- @Override
- List<AttributeKey<?>> extraAttributes() {
- return [
- SemanticAttributes.HTTP_URL
- ]
- }
}

Migrate netty-3.8 server instrumentation to Instrumenter API (#4368)