Skip to content

Commit 7f6c0a0

Browse files
xiepuhuanxiepuhuan
authored and
xiepuhuan
committed
Add withParent option to annotation @WithSpan
Signed-off-by: xiepuhuan <[email protected]>
1 parent 0209294 commit 7f6c0a0

File tree

8 files changed

+106
-3
lines changed

8 files changed

+106
-3
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
Comparing source compatibility of opentelemetry-instrumentation-annotations-2.13.0-SNAPSHOT.jar against opentelemetry-instrumentation-annotations-2.12.0.jar
2-
No changes.
2+
**** MODIFIED ANNOTATION: PUBLIC ABSTRACT io.opentelemetry.instrumentation.annotations.WithSpan (not serializable)
3+
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
4+
+++* NEW METHOD: PUBLIC(+) ABSTRACT(+) boolean withParent()

instrumentation-annotations/src/main/java/io/opentelemetry/instrumentation/annotations/WithSpan.java

+3
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,7 @@
3434

3535
/** Specify the {@link SpanKind} of span to be created. Defaults to {@link SpanKind#INTERNAL}. */
3636
SpanKind kind() default SpanKind.INTERNAL;
37+
38+
/** Specify whether to create a new span with parent. Defaults to {@code true}. */
39+
boolean withParent() default true;
3740
}

instrumentation/opentelemetry-instrumentation-annotations-1.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/instrumentationannotations/AnnotationSingletons.java

+19
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99

1010
import application.io.opentelemetry.instrumentation.annotations.WithSpan;
1111
import io.opentelemetry.api.GlobalOpenTelemetry;
12+
import io.opentelemetry.api.common.Attributes;
1213
import io.opentelemetry.api.trace.SpanKind;
14+
import io.opentelemetry.context.Context;
1315
import io.opentelemetry.instrumentation.api.annotation.support.MethodSpanAttributesExtractor;
1416
import io.opentelemetry.instrumentation.api.annotation.support.SpanAttributesExtractor;
1517
import io.opentelemetry.instrumentation.api.incubator.semconv.code.CodeAttributesExtractor;
@@ -47,6 +49,7 @@ private static Instrumenter<Method, Object> createInstrumenter() {
4749
INSTRUMENTATION_NAME,
4850
AnnotationSingletons::spanNameFromMethod)
4951
.addAttributesExtractor(CodeAttributesExtractor.create(MethodCodeAttributesGetter.INSTANCE))
52+
.addContextCustomizer(AnnotationSingletons::parentContextFromMethod)
5053
.buildInstrumenter(AnnotationSingletons::spanKindFromMethod);
5154
}
5255

@@ -62,6 +65,7 @@ private static Instrumenter<MethodRequest, Object> createInstrumenterWithAttribu
6265
MethodRequest::method,
6366
WithSpanParameterAttributeNamesExtractor.INSTANCE,
6467
MethodRequest::args))
68+
.addContextCustomizer(AnnotationSingletons::parentContextFromMethodRequest)
6569
.buildInstrumenter(AnnotationSingletons::spanKindFromMethodRequest);
6670
}
6771

@@ -104,5 +108,20 @@ private static String spanNameFromMethod(Method method) {
104108
return spanName;
105109
}
106110

111+
private static Context parentContextFromMethodRequest(
112+
Context context, MethodRequest request, Attributes attributes) {
113+
return parentContextFromMethod(context, request.method(), attributes);
114+
}
115+
116+
private static Context parentContextFromMethod(
117+
Context context, Method method, Attributes attributes) {
118+
WithSpan annotation = method.getDeclaredAnnotation(WithSpan.class);
119+
if (annotation.withParent()) {
120+
return context;
121+
}
122+
123+
return Context.root();
124+
}
125+
107126
private AnnotationSingletons() {}
108127
}

instrumentation/opentelemetry-instrumentation-annotations-1.16/javaagent/src/test/java/io/opentelemetry/test/annotation/TracedWithSpan.java

+10
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,14 @@ public CompletionStage<String> completionStage(CompletableFuture<String> future)
5757
public CompletableFuture<String> completableFuture(CompletableFuture<String> future) {
5858
return future;
5959
}
60+
61+
@WithSpan(withParent = false)
62+
public String withoutParent() {
63+
return "hello!";
64+
}
65+
66+
@WithSpan(kind = SpanKind.CONSUMER)
67+
public String consumer() {
68+
return withoutParent();
69+
}
6070
}

instrumentation/opentelemetry-instrumentation-annotations-1.16/javaagent/src/test/java/io/opentelemetry/test/annotation/WithSpanInstrumentationTest.java

+25
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,31 @@ void multipleSpans() {
107107
equalTo(CODE_FUNCTION, "otel"))));
108108
}
109109

110+
@Test
111+
void multipleSpansWithoutParent() {
112+
new TracedWithSpan().consumer();
113+
114+
testing.waitAndAssertTraces(
115+
trace ->
116+
trace.hasSpansSatisfyingExactly(
117+
span ->
118+
span.hasName("TracedWithSpan.consumer")
119+
.hasKind(SpanKind.CONSUMER)
120+
.hasNoParent()
121+
.hasAttributesSatisfyingExactly(
122+
equalTo(CODE_NAMESPACE, TracedWithSpan.class.getName()),
123+
equalTo(CODE_FUNCTION, "consumer"))),
124+
trace ->
125+
trace.hasSpansSatisfyingExactly(
126+
span ->
127+
span.hasName("TracedWithSpan.withoutParent")
128+
.hasKind(SpanKind.INTERNAL)
129+
.hasNoParent()
130+
.hasAttributesSatisfyingExactly(
131+
equalTo(CODE_NAMESPACE, TracedWithSpan.class.getName()),
132+
equalTo(CODE_FUNCTION, "withoutParent"))));
133+
}
134+
110135
@Test
111136
void excludedMethod() throws Exception {
112137
new TracedWithSpan().ignored();

instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/annotations/JoinPointRequest.java

+10-2
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@ final class JoinPointRequest {
1818
private final Method method;
1919
private final String spanName;
2020
private final SpanKind spanKind;
21+
private final boolean withParent;
2122

22-
private JoinPointRequest(JoinPoint joinPoint, Method method, String spanName, SpanKind spanKind) {
23+
private JoinPointRequest(
24+
JoinPoint joinPoint, Method method, String spanName, SpanKind spanKind, boolean withParent) {
2325
if (spanName.isEmpty()) {
2426
spanName = SpanNames.fromMethod(method);
2527
}
@@ -28,6 +30,7 @@ private JoinPointRequest(JoinPoint joinPoint, Method method, String spanName, Sp
2830
this.method = method;
2931
this.spanName = spanName;
3032
this.spanKind = spanKind;
33+
this.withParent = withParent;
3134
}
3235

3336
String spanName() {
@@ -46,6 +49,10 @@ Object[] args() {
4649
return joinPoint.getArgs();
4750
}
4851

52+
boolean withParent() {
53+
return withParent;
54+
}
55+
4956
interface Factory {
5057

5158
JoinPointRequest create(JoinPoint joinPoint);
@@ -65,8 +72,9 @@ public JoinPointRequest create(JoinPoint joinPoint) {
6572
WithSpan annotation = method.getDeclaredAnnotation(WithSpan.class);
6673
String spanName = annotation != null ? annotation.value() : "";
6774
SpanKind spanKind = annotation != null ? annotation.kind() : SpanKind.INTERNAL;
75+
boolean withParent = annotation == null || annotation.withParent();
6876

69-
return new JoinPointRequest(joinPoint, method, spanName, spanKind);
77+
return new JoinPointRequest(joinPoint, method, spanName, spanKind, withParent);
7078
}
7179
}
7280
}

instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/annotations/WithSpanAspect.java

+10
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
package io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.annotations;
77

88
import io.opentelemetry.api.OpenTelemetry;
9+
import io.opentelemetry.api.common.Attributes;
910
import io.opentelemetry.api.trace.Span;
1011
import io.opentelemetry.context.Context;
1112
import io.opentelemetry.context.Scope;
@@ -53,10 +54,19 @@ abstract class WithSpanAspect {
5354
JoinPointRequest::method,
5455
parameterAttributeNamesExtractor,
5556
JoinPointRequest::args))
57+
.addContextCustomizer(WithSpanAspect::parentContext)
5658
.buildInstrumenter(JoinPointRequest::spanKind);
5759
this.requestFactory = requestFactory;
5860
}
5961

62+
static Context parentContext(Context parentContext, JoinPointRequest request, Attributes unused) {
63+
if (request.withParent()) {
64+
return parentContext;
65+
}
66+
67+
return Context.root();
68+
}
69+
6070
public Object traceMethod(ProceedingJoinPoint pjp) throws Throwable {
6171
JoinPointRequest request = requestFactory.create(pjp);
6272
Context parentContext = Context.current();

instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/annotations/InstrumentationWithSpanAspectTest.java

+26
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,27 @@ void withSpanAttributes() {
180180
equalTo(stringKey("explicitName"), "baz"))));
181181
}
182182

183+
@Test
184+
@DisplayName(
185+
"when method is annotated with @WithSpan(withParent=false) should build span without parent")
186+
void withSpanWithoutParent() {
187+
// when
188+
testing.runWithSpan("parent", withSpanTester::testWithoutParentSpan);
189+
190+
// then
191+
testing.waitAndAssertTraces(
192+
trace -> trace.hasSpansSatisfyingExactly(span -> span.hasName("parent").hasKind(INTERNAL)),
193+
trace ->
194+
trace.hasSpansSatisfyingExactly(
195+
span ->
196+
span.hasName(unproxiedTesterSimpleClassName + ".testWithoutParentSpan")
197+
.hasKind(INTERNAL)
198+
.hasNoParent()
199+
.hasAttributesSatisfyingExactly(
200+
equalTo(CODE_NAMESPACE, unproxiedTesterClassName),
201+
equalTo(CODE_FUNCTION, "testWithoutParentSpan"))));
202+
}
203+
183204
static class InstrumentationWithSpanTester {
184205
@WithSpan
185206
public String testWithSpan() {
@@ -221,6 +242,11 @@ public String withSpanAttributes(
221242

222243
return "hello!";
223244
}
245+
246+
@WithSpan(withParent = false)
247+
public String testWithoutParentSpan() {
248+
return "Span without parent span was created";
249+
}
224250
}
225251

226252
@Nested

0 commit comments

Comments
 (0)