Skip to content

Commit 12874fb

Browse files
authored
Add span status customizer (#15288)
1 parent 4690642 commit 12874fb

File tree

5 files changed

+77
-0
lines changed

5 files changed

+77
-0
lines changed

instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/instrumenter/InstrumenterCustomizer.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
1212
import io.opentelemetry.instrumentation.api.instrumenter.OperationMetrics;
1313
import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor;
14+
import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor;
1415
import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesExtractor;
1516
import java.util.function.Function;
1617
import java.util.function.UnaryOperator;
@@ -106,6 +107,16 @@ default InstrumenterCustomizer setSpanNameExtractor(
106107
InstrumenterCustomizer setSpanNameExtractor(
107108
UnaryOperator<SpanNameExtractor<?>> spanNameExtractor);
108109

110+
/**
111+
* Sets a transformer function that will modify the {@link SpanStatusExtractor}. This allows
112+
* customizing how span statuses are generated for the instrumented operations.
113+
*
114+
* @param spanStatusExtractor function that transforms the original span status extractor
115+
* @return this InstrumenterCustomizer for method chaining
116+
*/
117+
InstrumenterCustomizer setSpanStatusExtractor(
118+
UnaryOperator<SpanStatusExtractor<?, ?>> spanStatusExtractor);
119+
109120
/** Types of instrumentation. */
110121
enum InstrumentationType {
111122
HTTP_CLIENT,

instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/instrumenter/internal/InstrumenterCustomizerImpl.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import io.opentelemetry.instrumentation.api.instrumenter.ContextCustomizer;
1111
import io.opentelemetry.instrumentation.api.instrumenter.OperationMetrics;
1212
import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor;
13+
import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor;
1314
import io.opentelemetry.instrumentation.api.internal.InternalInstrumenterCustomizer;
1415
import io.opentelemetry.instrumentation.api.internal.SpanKey;
1516
import java.util.HashMap;
@@ -87,4 +88,11 @@ public InstrumenterCustomizer setSpanNameExtractor(
8788
customizer.setSpanNameExtractor(spanNameExtractor);
8889
return this;
8990
}
91+
92+
@Override
93+
public InstrumenterCustomizer setSpanStatusExtractor(
94+
UnaryOperator<SpanStatusExtractor<?, ?>> spanStatusExtractor) {
95+
customizer.setSpanStatusExtractor(spanStatusExtractor);
96+
return this;
97+
}
9098
}

instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/InstrumenterBuilder.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,14 @@ public void setSpanNameExtractor(
442442
builder.spanNameExtractor =
443443
spanNameExtractorTransformer.apply(builder.spanNameExtractor);
444444
}
445+
446+
@Override
447+
public void setSpanStatusExtractor(
448+
UnaryOperator<SpanStatusExtractor<? super REQUEST, ? super RESPONSE>>
449+
spanStatusExtractorTransformer) {
450+
builder.spanStatusExtractor =
451+
spanStatusExtractorTransformer.apply(builder.spanStatusExtractor);
452+
}
445453
});
446454
}
447455
}

instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/InternalInstrumenterCustomizer.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import io.opentelemetry.instrumentation.api.instrumenter.ContextCustomizer;
1010
import io.opentelemetry.instrumentation.api.instrumenter.OperationMetrics;
1111
import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor;
12+
import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor;
1213
import java.util.function.UnaryOperator;
1314

1415
/**
@@ -32,4 +33,8 @@ void addAttributesExtractors(
3233

3334
void setSpanNameExtractor(
3435
UnaryOperator<SpanNameExtractor<? super REQUEST>> spanNameExtractorTransformer);
36+
37+
void setSpanStatusExtractor(
38+
UnaryOperator<SpanStatusExtractor<? super REQUEST, ? super RESPONSE>>
39+
spanStatusExtractorTransformer);
3540
}

instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/internal/InstrumentationCustomizerTest.java

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import io.opentelemetry.api.trace.SpanContext;
2222
import io.opentelemetry.api.trace.SpanId;
2323
import io.opentelemetry.api.trace.SpanKind;
24+
import io.opentelemetry.api.trace.StatusCode;
2425
import io.opentelemetry.context.Context;
2526
import io.opentelemetry.instrumentation.api.incubator.instrumenter.InstrumenterCustomizer.InstrumentationType;
2627
import io.opentelemetry.instrumentation.api.incubator.instrumenter.InstrumenterCustomizerProvider;
@@ -359,6 +360,50 @@ void testSetSpanNameExtractor() {
359360
.hasAttributes(Attributes.empty())));
360361
}
361362

363+
@Test
364+
void testSetSpanStatusExtractor() {
365+
AtomicBoolean customizerCalled = new AtomicBoolean();
366+
setCustomizer(
367+
customizer -> {
368+
customizerCalled.set(true);
369+
customizer.setSpanStatusExtractor(
370+
unused ->
371+
(spanStatusBuilder, request, response, error) ->
372+
spanStatusBuilder.setStatus(StatusCode.OK));
373+
});
374+
375+
Instrumenter<Map<String, String>, Map<String, String>> instrumenter =
376+
Instrumenter.<Map<String, String>, Map<String, String>>builder(
377+
otelTesting.getOpenTelemetry(), "test", unused -> "span")
378+
.setSpanStatusExtractor(
379+
(spanStatusBuilder, request, response, error) ->
380+
spanStatusBuilder.setStatus(StatusCode.ERROR))
381+
.buildInstrumenter();
382+
383+
assertThat(customizerCalled).isTrue();
384+
385+
Context context = instrumenter.start(Context.root(), REQUEST);
386+
SpanContext spanContext = Span.fromContext(context).getSpanContext();
387+
assertThat(spanContext.isValid()).isTrue();
388+
389+
instrumenter.end(context, REQUEST, RESPONSE, null);
390+
391+
otelTesting
392+
.assertTraces()
393+
.hasTracesSatisfyingExactly(
394+
trace ->
395+
trace.hasSpansSatisfyingExactly(
396+
span ->
397+
span.hasName("span")
398+
.hasKind(SpanKind.INTERNAL)
399+
.hasInstrumentationScopeInfo(InstrumentationScopeInfo.create("test"))
400+
.hasTraceId(spanContext.getTraceId())
401+
.hasSpanId(spanContext.getSpanId())
402+
.hasParentSpanId(SpanId.getInvalid())
403+
.hasStatus(StatusData.ok())
404+
.hasAttributes(Attributes.empty())));
405+
}
406+
362407
static class AttributesExtractor1
363408
implements AttributesExtractor<Map<String, String>, Map<String, String>> {
364409

0 commit comments

Comments
 (0)