From 7016e872e0f555707136b0029a08542457bcd45e Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Fri, 3 Oct 2025 12:34:53 -0700 Subject: [PATCH] Capture code attributes in Ratpack instrumentation --- .../ratpack/RatpackCodeAttributesGetter.java | 25 +++++++++++++++++++ .../ratpack/RatpackSingletons.java | 24 +++++++++++++----- .../ratpack/TracingHandler.java | 8 +++--- .../server/AbstractRatpackHttpServerTest.java | 7 +++++- .../server/AbstractRatpackRoutesTest.java | 7 ++++-- 5 files changed, 57 insertions(+), 14 deletions(-) create mode 100644 instrumentation/ratpack/ratpack-1.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/ratpack/RatpackCodeAttributesGetter.java diff --git a/instrumentation/ratpack/ratpack-1.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/ratpack/RatpackCodeAttributesGetter.java b/instrumentation/ratpack/ratpack-1.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/ratpack/RatpackCodeAttributesGetter.java new file mode 100644 index 000000000000..a7c47aacb406 --- /dev/null +++ b/instrumentation/ratpack/ratpack-1.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/ratpack/RatpackCodeAttributesGetter.java @@ -0,0 +1,25 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.ratpack; + +import io.opentelemetry.instrumentation.api.incubator.semconv.code.CodeAttributesGetter; +import javax.annotation.Nullable; +import ratpack.handling.Handler; + +public class RatpackCodeAttributesGetter implements CodeAttributesGetter { + + @Nullable + @Override + public Class getCodeClass(Handler handler) { + return handler.getClass(); + } + + @Nullable + @Override + public String getMethodName(Handler handler) { + return "handle"; + } +} diff --git a/instrumentation/ratpack/ratpack-1.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/ratpack/RatpackSingletons.java b/instrumentation/ratpack/ratpack-1.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/ratpack/RatpackSingletons.java index 6796026d6dfd..5e2ac9ada1a9 100644 --- a/instrumentation/ratpack/ratpack-1.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/ratpack/RatpackSingletons.java +++ b/instrumentation/ratpack/ratpack-1.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/ratpack/RatpackSingletons.java @@ -8,22 +8,34 @@ import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.StatusCode; +import io.opentelemetry.instrumentation.api.incubator.semconv.code.CodeAttributesExtractor; +import io.opentelemetry.instrumentation.api.incubator.semconv.code.CodeSpanNameExtractor; import io.opentelemetry.instrumentation.api.instrumenter.ErrorCauseExtractor; import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRoute; import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRouteSource; import io.opentelemetry.javaagent.bootstrap.internal.ExperimentalConfig; import ratpack.handling.Context; +import ratpack.handling.Handler; public final class RatpackSingletons { - private static final Instrumenter INSTRUMENTER = - Instrumenter.builder( - GlobalOpenTelemetry.get(), "io.opentelemetry.ratpack-1.4", s -> s) - .setEnabled(ExperimentalConfig.get().controllerTelemetryEnabled()) - .buildInstrumenter(); + private static final Instrumenter INSTRUMENTER; - public static Instrumenter instrumenter() { + static { + RatpackCodeAttributesGetter codeAttributesGetter = new RatpackCodeAttributesGetter(); + + INSTRUMENTER = + Instrumenter.builder( + GlobalOpenTelemetry.get(), + "io.opentelemetry.ratpack-1.4", + CodeSpanNameExtractor.create(codeAttributesGetter)) + .addAttributesExtractor(CodeAttributesExtractor.create(codeAttributesGetter)) + .setEnabled(ExperimentalConfig.get().controllerTelemetryEnabled()) + .buildInstrumenter(); + } + + public static Instrumenter instrumenter() { return INSTRUMENTER; } diff --git a/instrumentation/ratpack/ratpack-1.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/ratpack/TracingHandler.java b/instrumentation/ratpack/ratpack-1.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/ratpack/TracingHandler.java index cdfd48657a56..22163e723810 100644 --- a/instrumentation/ratpack/ratpack-1.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/ratpack/TracingHandler.java +++ b/instrumentation/ratpack/ratpack-1.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/ratpack/TracingHandler.java @@ -18,8 +18,6 @@ public final class TracingHandler implements Handler { - private static final String INITIAL_SPAN_NAME = "ratpack.handler"; - public static final Handler INSTANCE = new TracingHandler(); @Override @@ -34,15 +32,15 @@ public void handle(Context ctx) { serverContext != null ? serverContext.context() : Java8BytecodeBridge.currentContext(); io.opentelemetry.context.Context callbackContext; - if (instrumenter().shouldStart(parentOtelContext, INITIAL_SPAN_NAME)) { + if (instrumenter().shouldStart(parentOtelContext, INSTANCE)) { io.opentelemetry.context.Context otelContext = - instrumenter().start(parentOtelContext, INITIAL_SPAN_NAME); + instrumenter().start(parentOtelContext, INSTANCE); ctx.getExecution().add(otelContext); ctx.getResponse() .beforeSend( response -> { updateSpanNames(otelContext, ctx); - instrumenter().end(otelContext, INITIAL_SPAN_NAME, null, null); + instrumenter().end(otelContext, INSTANCE, null, null); }); callbackContext = otelContext; } else { diff --git a/instrumentation/ratpack/ratpack-1.4/testing/src/main/java/io/opentelemetry/instrumentation/ratpack/server/AbstractRatpackHttpServerTest.java b/instrumentation/ratpack/ratpack-1.4/testing/src/main/java/io/opentelemetry/instrumentation/ratpack/server/AbstractRatpackHttpServerTest.java index 6f4e8c0f3696..7aad570009f9 100644 --- a/instrumentation/ratpack/ratpack-1.4/testing/src/main/java/io/opentelemetry/instrumentation/ratpack/server/AbstractRatpackHttpServerTest.java +++ b/instrumentation/ratpack/ratpack-1.4/testing/src/main/java/io/opentelemetry/instrumentation/ratpack/server/AbstractRatpackHttpServerTest.java @@ -5,6 +5,7 @@ package io.opentelemetry.instrumentation.ratpack.server; +import static io.opentelemetry.instrumentation.testing.junit.code.SemconvCodeStabilityUtil.codeFunctionAssertions; import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.CAPTURE_HEADERS; import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.ERROR; import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.EXCEPTION; @@ -315,7 +316,11 @@ protected SpanDataAssert assertHandlerSpan( } else { spanName = endpoint.getPath(); } - span.hasName(spanName).hasKind(SpanKind.INTERNAL); + span.hasName(spanName) + .hasKind(SpanKind.INTERNAL) + .hasAttributesSatisfyingExactly( + codeFunctionAssertions( + "io.opentelemetry.javaagent.instrumentation.ratpack.TracingHandler", "handle")); if (endpoint == EXCEPTION) { span.hasStatus(StatusData.error()) .hasException(new IllegalStateException(EXCEPTION.getBody())); diff --git a/instrumentation/ratpack/ratpack-1.4/testing/src/main/java/io/opentelemetry/instrumentation/ratpack/server/AbstractRatpackRoutesTest.java b/instrumentation/ratpack/ratpack-1.4/testing/src/main/java/io/opentelemetry/instrumentation/ratpack/server/AbstractRatpackRoutesTest.java index e5e02ef2c24f..09eb3d65e583 100644 --- a/instrumentation/ratpack/ratpack-1.4/testing/src/main/java/io/opentelemetry/instrumentation/ratpack/server/AbstractRatpackRoutesTest.java +++ b/instrumentation/ratpack/ratpack-1.4/testing/src/main/java/io/opentelemetry/instrumentation/ratpack/server/AbstractRatpackRoutesTest.java @@ -5,6 +5,7 @@ package io.opentelemetry.instrumentation.ratpack.server; +import static io.opentelemetry.instrumentation.testing.junit.code.SemconvCodeStabilityUtil.codeFunctionAssertions; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies; import static io.opentelemetry.semconv.ClientAttributes.CLIENT_ADDRESS; @@ -22,7 +23,6 @@ import static io.opentelemetry.semconv.UserAgentAttributes.USER_AGENT_ORIGINAL; import static org.assertj.core.api.Assertions.assertThat; -import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.instrumentation.test.utils.PortUtils; import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; @@ -162,7 +162,10 @@ void bindingsForPath(String path, String route) { span.hasName("/" + route) .hasKind(SpanKind.INTERNAL) .hasParent(trace.getSpan(0)) - .hasAttributes(Attributes.empty())); + .hasAttributesSatisfyingExactly( + codeFunctionAssertions( + "io.opentelemetry.javaagent.instrumentation.ratpack.TracingHandler", + "handle"))); } trace.hasSpansSatisfyingExactly(assertions);