Migrate Ratpack javaagent instrumentation to Instrumenter API
MODIFY
instrumentation/netty/netty-4-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/common/server/NettyServerInstrumenterFactory.java
instrumentation/netty/netty-4-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/common/server/NettyServerInstrumenterFactory.java
@@ -11,6 +11,7 @@ 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 io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming;
import io.opentelemetry.javaagent.instrumentation.netty.common.HttpRequestAndChannel;
import io.opentelemetry.javaagent.instrumentation.netty.common.NettyCommonNetAttributesExtractor;
@@ -30,6 +31,11 @@ public final class NettyServerInstrumenterFactory {
.addAttributesExtractor(httpAttributesExtractor)
.addAttributesExtractor(new NettyCommonNetAttributesExtractor())
.addRequestMetrics(HttpServerMetrics.get())
+ .addContextCustomizer(
+ (context, request, attributes) -> {
+ // netty is not exactly a "container", but it's the best match out of these
+ return ServerSpanNaming.init(context, ServerSpanNaming.Source.CONTAINER);
+ })
.newServerInstrumenter(new HttpRequestHeadersGetter());
}

ADD
instrumentation/ratpack-1.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/ratpack/RatpackSingletons.java
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.instrumentation.ratpack;
+
+import io.opentelemetry.api.GlobalOpenTelemetry;
+import io.opentelemetry.api.trace.Span;
+import io.opentelemetry.api.trace.StatusCode;
+import io.opentelemetry.instrumentation.api.instrumenter.ErrorCauseExtractor;
+import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
+import io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming;
+import ratpack.handling.Context;
+
+public final class RatpackSingletons {
+
+ private static final Instrumenter<String, Void> INSTRUMENTER =
+ Instrumenter.<String, Void>newBuilder(
+ GlobalOpenTelemetry.get(), "io.opentelemetry.ratpack-1.4", s -> s)
+ .newInstrumenter();
+
+ public static Instrumenter<String, Void> instrumenter() {
+ return INSTRUMENTER;
+ }
+
+ public static void updateSpanNames(io.opentelemetry.context.Context otelContext, Context ctx) {
+ String matchedRoute = updateServerSpanName(otelContext, ctx);
+ // update ratpack span name
+ Span.fromContext(otelContext).updateName(matchedRoute);
+ }
+
+ public static String updateServerSpanName(
+ io.opentelemetry.context.Context otelContext, Context ctx) {
+ String matchedRoute = ctx.getPathBinding().getDescription();
+ if (matchedRoute == null || matchedRoute.isEmpty()) {
+ matchedRoute = "/";
+ } else if (!matchedRoute.startsWith("/")) {
+ matchedRoute = "/" + matchedRoute;
+ }
+
+ // update the netty server span name; FILTER is probably the best match for ratpack Handlers
+ ServerSpanNaming.updateServerSpanName(
+ otelContext, ServerSpanNaming.Source.FILTER, (context, name) -> name, matchedRoute);
+ return matchedRoute;
+ }
+
+ // copied from BaseTracer#onException()
+ public static void onError(io.opentelemetry.context.Context context, Throwable error) {
+ Span span = Span.fromContext(context);
+ span.setStatus(StatusCode.ERROR);
+ span.recordException(ErrorCauseExtractor.jdk().extractCause(error));
+ }
+
+ private RatpackSingletons() {}
+}

DELETE
instrumentation/ratpack-1.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/ratpack/RatpackTracer.java
-/*
- * Copyright The OpenTelemetry Authors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package io.opentelemetry.javaagent.instrumentation.ratpack;
-
-import io.opentelemetry.api.trace.Span;
-import io.opentelemetry.instrumentation.api.tracer.BaseTracer;
-import ratpack.handling.Context;
-
-public class RatpackTracer extends BaseTracer {
- private static final RatpackTracer TRACER = new RatpackTracer();
-
- public static RatpackTracer tracer() {
- return TRACER;
- }
-
- public void onContext(io.opentelemetry.context.Context otelContext, Context ctx) {
- String description = ctx.getPathBinding().getDescription();
- if (description == null || description.isEmpty()) {
- description = "/";
- } else if (!description.startsWith("/")) {
- description = "/" + description;
- }
-
- Span.fromContext(otelContext).updateName(description);
- }
-
- @Override
- protected String getInstrumentationName() {
- return "io.opentelemetry.ratpack-1.4";
- }
-
- @Override
- protected Throwable unwrapThrowable(Throwable throwable) {
- if (throwable.getCause() != null && throwable instanceof Error) {
- throwable = throwable.getCause();
- }
- return super.unwrapThrowable(throwable);
- }
-}

MODIFY
instrumentation/ratpack-1.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/ratpack/ServerErrorHandlerInstrumentation.java
instrumentation/ratpack-1.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/ratpack/ServerErrorHandlerInstrumentation.java
@@ -7,7 +7,6 @@ package io.opentelemetry.javaagent.instrumentation.ratpack;
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed;
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface;
-import static io.opentelemetry.javaagent.instrumentation.ratpack.RatpackTracer.tracer;
import static net.bytebuddy.matcher.ElementMatchers.isAbstract;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.not;
@@ -51,7 +50,7 @@ public class ServerErrorHandlerInstrumentation implements TypeInstrumentation {
Optional<io.opentelemetry.context.Context> otelContext =
ctx.maybeGet(io.opentelemetry.context.Context.class);
if (otelContext.isPresent()) {
- tracer().onException(otelContext.get(), throwable);
+ RatpackSingletons.onError(otelContext.get(), throwable);
}
}
}

MODIFY
instrumentation/ratpack-1.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/ratpack/TracingHandler.java
instrumentation/ratpack-1.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/ratpack/TracingHandler.java
package io.opentelemetry.javaagent.instrumentation.ratpack;
-import static io.opentelemetry.javaagent.instrumentation.ratpack.RatpackTracer.tracer;
+import static io.opentelemetry.javaagent.instrumentation.ratpack.RatpackSingletons.instrumenter;
+import static io.opentelemetry.javaagent.instrumentation.ratpack.RatpackSingletons.updateServerSpanName;
+import static io.opentelemetry.javaagent.instrumentation.ratpack.RatpackSingletons.updateSpanNames;
import io.netty.util.Attribute;
-import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.context.Scope;
import io.opentelemetry.instrumentation.netty.v4_1.AttributeKeys;
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
@@ -16,6 +17,9 @@ import ratpack.handling.Context;
import ratpack.handling.Handler;
public final class TracingHandler implements Handler {
+
+ private static final String INITIAL_SPAN_NAME = "ratpack.handler";
+
public static final Handler INSTANCE = new TracingHandler();
@Override
@@ -27,25 +31,28 @@ public final class TracingHandler implements Handler {
// Must use context from channel, as executor instrumentation is not accurate - Ratpack
// internally queues events and then drains them in batches, causing executor instrumentation to
// attach the same context to a batch of events from different requests.
- io.opentelemetry.context.Context parentContext =
+ io.opentelemetry.context.Context parentOtelContext =
serverSpanContext != null ? serverSpanContext : Java8BytecodeBridge.currentContext();
+ io.opentelemetry.context.Context callbackContext;
- io.opentelemetry.context.Context ratpackContext =
- tracer().startSpan(parentContext, "ratpack.handler", SpanKind.INTERNAL);
- ctx.getExecution().add(ratpackContext);
-
+ if (instrumenter().shouldStart(parentOtelContext, INITIAL_SPAN_NAME)) {
+ io.opentelemetry.context.Context otelContext =
+ instrumenter().start(parentOtelContext, INITIAL_SPAN_NAME);
+ ctx.getExecution().add(otelContext);
ctx.getResponse()
.beforeSend(
response -> {
- if (serverSpanContext != null) {
- // Rename the netty span name with the ratpack route.
- tracer().onContext(serverSpanContext, ctx);
- }
- tracer().onContext(ratpackContext, ctx);
- tracer().end(ratpackContext);
+ updateSpanNames(otelContext, ctx);
+ instrumenter().end(otelContext, INITIAL_SPAN_NAME, null, null);
});
+ callbackContext = otelContext;
+ } else {
+ // just update the server span name
+ ctx.getResponse().beforeSend(response -> updateServerSpanName(parentOtelContext, ctx));
+ callbackContext = parentOtelContext;
+ }
- try (Scope ignored = ratpackContext.makeCurrent()) {
+ try (Scope ignored = callbackContext.makeCurrent()) {
ctx.next();
// exceptions are captured by ServerErrorHandlerInstrumentation
}

Migrate Ratpack javaagent instrumentation to Instrumenter API (#4399)