Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

package io.opentelemetry.instrumentation.api.incubator.instrumenter;

import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.ContextCustomizer;
import io.opentelemetry.instrumentation.api.instrumenter.OperationMetrics;
Expand All @@ -30,6 +31,15 @@ public interface InstrumenterCustomizer {
*/
String getInstrumentationName();

/**
* Returns the {@link SpanKind} that this customizer applies to. This allows distinguishing
* between different types of instrumenters (e.g., client, server) within the same
* instrumentation.
*
* @return the span kind this customizer targets
*/
SpanKind getSpanKind();

/**
* Adds a single AttributesExtractor to the instrumenter. This extractor will be used to extract
* attributes from requests and responses during span creation and enrichment.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

package io.opentelemetry.instrumentation.api.incubator.instrumenter.internal;

import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.instrumentation.api.incubator.instrumenter.InstrumenterCustomizer;
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.ContextCustomizer;
Expand All @@ -30,6 +31,11 @@ public String getInstrumentationName() {
return customizer.getInstrumentationName();
}

@Override
public SpanKind getSpanKind() {
return customizer.getSpanKind();
}

@Override
public InstrumenterCustomizer addAttributesExtractor(AttributesExtractor<?, ?> extractor) {
customizer.addAttributesExtractor(extractor);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -285,10 +285,10 @@ public Instrumenter<REQUEST, RESPONSE> buildInstrumenter(
private Instrumenter<REQUEST, RESPONSE> buildInstrumenter(
InstrumenterConstructor<REQUEST, RESPONSE> constructor,
SpanKindExtractor<? super REQUEST> spanKindExtractor) {
this.spanKindExtractor = spanKindExtractor;

applyCustomizers(this);

this.spanKindExtractor = spanKindExtractor;
return constructor.create(this);
}

Expand Down Expand Up @@ -393,6 +393,15 @@ public String getInstrumentationName() {
return builder.instrumentationName;
}

@Override
public SpanKind getSpanKind() {
try {
return builder.spanKindExtractor.extract(null);
} catch (RuntimeException e) {
return null;
}
}

@Override
public void addAttributesExtractor(AttributesExtractor<REQUEST, RESPONSE> extractor) {
builder.addAttributesExtractor(extractor);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

package io.opentelemetry.instrumentation.api.internal;

import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.ContextCustomizer;
import io.opentelemetry.instrumentation.api.instrumenter.OperationMetrics;
Expand All @@ -19,6 +20,8 @@ public interface InternalInstrumenterCustomizer<REQUEST, RESPONSE> {

String getInstrumentationName();

SpanKind getSpanKind();

void addAttributesExtractor(AttributesExtractor<REQUEST, RESPONSE> extractor);

void addAttributesExtractors(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import io.opentelemetry.api.trace.SpanId;
import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.propagation.TextMapGetter;
import io.opentelemetry.instrumentation.api.incubator.instrumenter.InstrumenterCustomizerProvider;
import io.opentelemetry.instrumentation.api.incubator.instrumenter.internal.InternalInstrumenterCustomizerProviderImpl;
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor;
Expand Down Expand Up @@ -110,6 +111,65 @@ void testGetInstrumentationName() {
assertThat(customizerCalled).isTrue();
}

@Test
void testGetSpanKind() {
AtomicBoolean clientCustomizerCalled = new AtomicBoolean();
AtomicBoolean serverCustomizerCalled = new AtomicBoolean();
AtomicBoolean exceptionCustomizerCalled = new AtomicBoolean();

setCustomizer(
customizer -> {
if (customizer.getSpanKind() == SpanKind.CLIENT) {
clientCustomizerCalled.set(true);
assertThat(customizer.getInstrumentationName()).isEqualTo("test");
} else if (customizer.getSpanKind() == SpanKind.SERVER) {
serverCustomizerCalled.set(true);
assertThat(customizer.getInstrumentationName()).isEqualTo("test");
} else if (customizer.getSpanKind() == null) {
// This case handles when spanKindExtractor throws an exception and returns null
exceptionCustomizerCalled.set(true);
assertThat(customizer.getInstrumentationName()).isEqualTo("test");
}
});

// Build client instrumenter
Instrumenter.<Map<String, String>, Map<String, String>>builder(
otelTesting.getOpenTelemetry(), "test", unused -> "client-span")
.buildClientInstrumenter((carrier, key, value) -> {
});

// Build server instrumenter
Instrumenter.<Map<String, String>, Map<String, String>>builder(
otelTesting.getOpenTelemetry(), "test", unused -> "server-span")
.buildServerInstrumenter(
new TextMapGetter<Map<String, String>>() {
@Override
public Iterable<String> keys(Map<String, String> carrier) {
return carrier.keySet();
}

@Override
public String get(Map<String, String> carrier, String key) {
return carrier.get(key);
}
});

// Build instrumenter with a span kind extractor that throws exception with null input
Instrumenter.<Map<String, String>, Map<String, String>>builder(
otelTesting.getOpenTelemetry(), "test", unused -> "test-span")
.buildInstrumenter(
request -> {
if (request == null) {
throw new NullPointerException("Request cannot be null");
}
return SpanKind.CLIENT;
});

assertThat(clientCustomizerCalled).isTrue();
assertThat(serverCustomizerCalled).isTrue();
assertThat(exceptionCustomizerCalled).isTrue();
}

@Test
void testAddAttributesExtractor() {
AtomicBoolean customizerCalled = new AtomicBoolean();
Expand Down