diff --git a/instrumentation/grails-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/grails/GrailsCodeAttributesGetter.java b/instrumentation/grails-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/grails/GrailsCodeAttributesGetter.java new file mode 100644 index 000000000000..c735b5aa6d43 --- /dev/null +++ b/instrumentation/grails-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/grails/GrailsCodeAttributesGetter.java @@ -0,0 +1,21 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.grails; + +import io.opentelemetry.instrumentation.api.incubator.semconv.code.CodeAttributesGetter; + +public class GrailsCodeAttributesGetter implements CodeAttributesGetter { + + @Override + public Class getCodeClass(HandlerData handlerData) { + return handlerData.getController().getClass(); + } + + @Override + public String getMethodName(HandlerData handlerData) { + return handlerData.getAction(); + } +} diff --git a/instrumentation/grails-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/grails/GrailsSingletons.java b/instrumentation/grails-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/grails/GrailsSingletons.java index 240e8d0eb223..e12b8418aa3f 100644 --- a/instrumentation/grails-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/grails/GrailsSingletons.java +++ b/instrumentation/grails-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/grails/GrailsSingletons.java @@ -6,6 +6,8 @@ package io.opentelemetry.javaagent.instrumentation.grails; import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.instrumentation.api.incubator.semconv.code.CodeAttributesExtractor; +import io.opentelemetry.instrumentation.api.incubator.semconv.code.CodeSpanNameExtractor; import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; import io.opentelemetry.javaagent.bootstrap.internal.ExperimentalConfig; @@ -15,9 +17,14 @@ public final class GrailsSingletons { private static final Instrumenter INSTRUMENTER; static { + GrailsCodeAttributesGetter codeAttributesGetter = new GrailsCodeAttributesGetter(); + INSTRUMENTER = Instrumenter.builder( - GlobalOpenTelemetry.get(), INSTRUMENTATION_NAME, HandlerData::spanName) + GlobalOpenTelemetry.get(), + INSTRUMENTATION_NAME, + CodeSpanNameExtractor.create(codeAttributesGetter)) + .addAttributesExtractor(CodeAttributesExtractor.create(codeAttributesGetter)) .setEnabled(ExperimentalConfig.get().controllerTelemetryEnabled()) .buildInstrumenter(); } diff --git a/instrumentation/grails-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/grails/HandlerData.java b/instrumentation/grails-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/grails/HandlerData.java index 6427f466d13f..6e557ef48497 100644 --- a/instrumentation/grails-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/grails/HandlerData.java +++ b/instrumentation/grails-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/grails/HandlerData.java @@ -5,8 +5,6 @@ package io.opentelemetry.javaagent.instrumentation.grails; -import io.opentelemetry.instrumentation.api.semconv.util.SpanNames; - public class HandlerData { private final Object controller; @@ -17,7 +15,11 @@ public HandlerData(Object controller, String action) { this.action = action; } - String spanName() { - return SpanNames.fromMethod(controller.getClass(), action); + public Object getController() { + return controller; + } + + public String getAction() { + return action; } } diff --git a/instrumentation/grails-3.0/javaagent/src/test/java/test/GrailsTest.java b/instrumentation/grails-3.0/javaagent/src/test/java/test/GrailsTest.java index 526efe0ce171..c6e34cb43542 100644 --- a/instrumentation/grails-3.0/javaagent/src/test/java/test/GrailsTest.java +++ b/instrumentation/grails-3.0/javaagent/src/test/java/test/GrailsTest.java @@ -17,7 +17,6 @@ import grails.boot.GrailsApp; import grails.boot.config.GrailsAutoConfiguration; -import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.instrumentation.api.internal.HttpConstants; import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; @@ -132,25 +131,40 @@ ConfigurableApplicationContext startServer(int port) { return TestApplication.start(port, getContextPath()); } - private static String getHandlerSpanName(ServerEndpoint endpoint) { + private static String getHandlerMethod(ServerEndpoint endpoint) { if (QUERY_PARAM.equals(endpoint)) { - return "TestController.query"; + return "query"; } else if (PATH_PARAM.equals(endpoint)) { - return "TestController.path"; + return "path"; } else if (CAPTURE_HEADERS.equals(endpoint)) { - return "TestController.captureHeaders"; + return "captureHeaders"; } else if (INDEXED_CHILD.equals(endpoint)) { - return "TestController.child"; + return "child"; } else if (NOT_FOUND.equals(endpoint)) { - return "ResourceHttpRequestHandler.handleRequest"; + return "handleRequest"; } - return "TestController." + endpoint.name().toLowerCase(Locale.ROOT); + return endpoint.name().toLowerCase(Locale.ROOT); + } + + private static String getHandlerClass(ServerEndpoint endpoint) { + if (NOT_FOUND.equals(endpoint)) { + return "org.springframework.web.servlet.resource.ResourceHttpRequestHandler"; + } + return "test.TestController"; } @Override public SpanDataAssert assertHandlerSpan( SpanDataAssert span, String method, ServerEndpoint endpoint) { - span.hasName(getHandlerSpanName(endpoint)).hasKind(SpanKind.INTERNAL); + String handlerClass = getHandlerClass(endpoint); + String handlerMethod = getHandlerMethod(endpoint); + String handlerSpanName = + handlerClass.substring(handlerClass.lastIndexOf('.') + 1) + "." + handlerMethod; + span.hasName(handlerSpanName).hasKind(SpanKind.INTERNAL); + + span.hasAttributesSatisfyingExactly( + SemconvCodeStabilityUtil.codeFunctionAssertions(handlerClass, handlerMethod)); + if (endpoint == EXCEPTION) { span.hasStatus(StatusData.error()); span.hasException(new IllegalStateException(EXCEPTION.getBody())); @@ -182,11 +196,14 @@ public List> errorPageSpanAssertions( String method, ServerEndpoint endpoint) { List> spanAssertions = new ArrayList<>(); spanAssertions.add( - span -> - span.hasName( - endpoint == NOT_FOUND ? "ErrorController.notFound" : "ErrorController.index") - .hasKind(SpanKind.INTERNAL) - .hasAttributes(Attributes.empty())); + span -> { + String actionName = endpoint == NOT_FOUND ? "notFound" : "index"; + span.hasName("ErrorController." + actionName) + .hasKind(SpanKind.INTERNAL) + .hasAttributesSatisfyingExactly( + SemconvCodeStabilityUtil.codeFunctionAssertions( + "test.ErrorController", actionName)); + }); if (endpoint == NOT_FOUND) { spanAssertions.add( span ->