Skip to content

Commit 5606fc6

Browse files
authored
Add code attributes to Grails controller spans (#14885)
1 parent 489f6dd commit 5606fc6

File tree

4 files changed

+66
-19
lines changed

4 files changed

+66
-19
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.javaagent.instrumentation.grails;
7+
8+
import io.opentelemetry.instrumentation.api.incubator.semconv.code.CodeAttributesGetter;
9+
10+
public class GrailsCodeAttributesGetter implements CodeAttributesGetter<HandlerData> {
11+
12+
@Override
13+
public Class<?> getCodeClass(HandlerData handlerData) {
14+
return handlerData.getController().getClass();
15+
}
16+
17+
@Override
18+
public String getMethodName(HandlerData handlerData) {
19+
return handlerData.getAction();
20+
}
21+
}

instrumentation/grails-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/grails/GrailsSingletons.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
package io.opentelemetry.javaagent.instrumentation.grails;
77

88
import io.opentelemetry.api.GlobalOpenTelemetry;
9+
import io.opentelemetry.instrumentation.api.incubator.semconv.code.CodeAttributesExtractor;
10+
import io.opentelemetry.instrumentation.api.incubator.semconv.code.CodeSpanNameExtractor;
911
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
1012
import io.opentelemetry.javaagent.bootstrap.internal.ExperimentalConfig;
1113

@@ -15,9 +17,14 @@ public final class GrailsSingletons {
1517
private static final Instrumenter<HandlerData, Void> INSTRUMENTER;
1618

1719
static {
20+
GrailsCodeAttributesGetter codeAttributesGetter = new GrailsCodeAttributesGetter();
21+
1822
INSTRUMENTER =
1923
Instrumenter.<HandlerData, Void>builder(
20-
GlobalOpenTelemetry.get(), INSTRUMENTATION_NAME, HandlerData::spanName)
24+
GlobalOpenTelemetry.get(),
25+
INSTRUMENTATION_NAME,
26+
CodeSpanNameExtractor.create(codeAttributesGetter))
27+
.addAttributesExtractor(CodeAttributesExtractor.create(codeAttributesGetter))
2128
.setEnabled(ExperimentalConfig.get().controllerTelemetryEnabled())
2229
.buildInstrumenter();
2330
}

instrumentation/grails-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/grails/HandlerData.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55

66
package io.opentelemetry.javaagent.instrumentation.grails;
77

8-
import io.opentelemetry.instrumentation.api.semconv.util.SpanNames;
9-
108
public class HandlerData {
119

1210
private final Object controller;
@@ -17,7 +15,11 @@ public HandlerData(Object controller, String action) {
1715
this.action = action;
1816
}
1917

20-
String spanName() {
21-
return SpanNames.fromMethod(controller.getClass(), action);
18+
public Object getController() {
19+
return controller;
20+
}
21+
22+
public String getAction() {
23+
return action;
2224
}
2325
}

instrumentation/grails-3.0/javaagent/src/test/java/test/GrailsTest.java

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717

1818
import grails.boot.GrailsApp;
1919
import grails.boot.config.GrailsAutoConfiguration;
20-
import io.opentelemetry.api.common.Attributes;
2120
import io.opentelemetry.api.trace.SpanKind;
2221
import io.opentelemetry.instrumentation.api.internal.HttpConstants;
2322
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
@@ -132,25 +131,40 @@ ConfigurableApplicationContext startServer(int port) {
132131
return TestApplication.start(port, getContextPath());
133132
}
134133

135-
private static String getHandlerSpanName(ServerEndpoint endpoint) {
134+
private static String getHandlerMethod(ServerEndpoint endpoint) {
136135
if (QUERY_PARAM.equals(endpoint)) {
137-
return "TestController.query";
136+
return "query";
138137
} else if (PATH_PARAM.equals(endpoint)) {
139-
return "TestController.path";
138+
return "path";
140139
} else if (CAPTURE_HEADERS.equals(endpoint)) {
141-
return "TestController.captureHeaders";
140+
return "captureHeaders";
142141
} else if (INDEXED_CHILD.equals(endpoint)) {
143-
return "TestController.child";
142+
return "child";
144143
} else if (NOT_FOUND.equals(endpoint)) {
145-
return "ResourceHttpRequestHandler.handleRequest";
144+
return "handleRequest";
146145
}
147-
return "TestController." + endpoint.name().toLowerCase(Locale.ROOT);
146+
return endpoint.name().toLowerCase(Locale.ROOT);
147+
}
148+
149+
private static String getHandlerClass(ServerEndpoint endpoint) {
150+
if (NOT_FOUND.equals(endpoint)) {
151+
return "org.springframework.web.servlet.resource.ResourceHttpRequestHandler";
152+
}
153+
return "test.TestController";
148154
}
149155

150156
@Override
151157
public SpanDataAssert assertHandlerSpan(
152158
SpanDataAssert span, String method, ServerEndpoint endpoint) {
153-
span.hasName(getHandlerSpanName(endpoint)).hasKind(SpanKind.INTERNAL);
159+
String handlerClass = getHandlerClass(endpoint);
160+
String handlerMethod = getHandlerMethod(endpoint);
161+
String handlerSpanName =
162+
handlerClass.substring(handlerClass.lastIndexOf('.') + 1) + "." + handlerMethod;
163+
span.hasName(handlerSpanName).hasKind(SpanKind.INTERNAL);
164+
165+
span.hasAttributesSatisfyingExactly(
166+
SemconvCodeStabilityUtil.codeFunctionAssertions(handlerClass, handlerMethod));
167+
154168
if (endpoint == EXCEPTION) {
155169
span.hasStatus(StatusData.error());
156170
span.hasException(new IllegalStateException(EXCEPTION.getBody()));
@@ -182,11 +196,14 @@ public List<Consumer<SpanDataAssert>> errorPageSpanAssertions(
182196
String method, ServerEndpoint endpoint) {
183197
List<Consumer<SpanDataAssert>> spanAssertions = new ArrayList<>();
184198
spanAssertions.add(
185-
span ->
186-
span.hasName(
187-
endpoint == NOT_FOUND ? "ErrorController.notFound" : "ErrorController.index")
188-
.hasKind(SpanKind.INTERNAL)
189-
.hasAttributes(Attributes.empty()));
199+
span -> {
200+
String actionName = endpoint == NOT_FOUND ? "notFound" : "index";
201+
span.hasName("ErrorController." + actionName)
202+
.hasKind(SpanKind.INTERNAL)
203+
.hasAttributesSatisfyingExactly(
204+
SemconvCodeStabilityUtil.codeFunctionAssertions(
205+
"test.ErrorController", actionName));
206+
});
190207
if (endpoint == NOT_FOUND) {
191208
spanAssertions.add(
192209
span ->

0 commit comments

Comments
 (0)