diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/Instrumenter.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/Instrumenter.java index 3b5921c6d5..1dba5c526c 100644 --- a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/Instrumenter.java +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/Instrumenter.java @@ -58,7 +58,34 @@ public class Instrumenter { OpenTelemetry openTelemetry, String instrumentationName, SpanNameExtractor spanNameExtractor) { - return new InstrumenterBuilder<>(openTelemetry, instrumentationName, spanNameExtractor); + return new InstrumenterBuilder<>( + openTelemetry, instrumentationName, InstrumentationVersion.VERSION, spanNameExtractor); + } + + /** + * Returns a new {@link InstrumenterBuilder}. + * + *

The {@code instrumentationName} is the name of the instrumentation library, not the name of + * the instrument*ed* library. The value passed in this parameter should uniquely identify the + * instrumentation library so that during troubleshooting it's possible to pinpoint what tracer + * produced problematic telemetry. + * + *

The {@code instrumentationVersion} is the version of the instrumentation library, not the + * version of the instrument*ed* library. + * + *

In this project we use a convention to encode the minimum supported version of the + * instrument*ed* library into the instrumentation name, for example {@code + * io.opentelemetry.apache-httpclient-4.0}. This way, if there are different instrumentations for + * different library versions it's easy to find out which instrumentations produced the telemetry + * data. + */ + public static InstrumenterBuilder builder( + OpenTelemetry openTelemetry, + String instrumentationName, + String instrumentationVersion, + SpanNameExtractor spanNameExtractor) { + return new InstrumenterBuilder<>( + openTelemetry, instrumentationName, instrumentationVersion, spanNameExtractor); } private static final SupportabilityMetrics supportability = SupportabilityMetrics.instance(); @@ -82,7 +109,7 @@ public class Instrumenter { Instrumenter(InstrumenterBuilder builder) { this.instrumentationName = builder.instrumentationName; this.tracer = - builder.openTelemetry.getTracer(instrumentationName, InstrumentationVersion.VERSION); + builder.openTelemetry.getTracer(instrumentationName, builder.instrumentationVersion); this.spanNameExtractor = builder.spanNameExtractor; this.spanKindExtractor = builder.spanKindExtractor; this.spanStatusExtractor = builder.spanStatusExtractor; diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/InstrumenterBuilder.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/InstrumenterBuilder.java index 652d09ec86..18b7fa0e04 100644 --- a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/InstrumenterBuilder.java +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/InstrumenterBuilder.java @@ -42,6 +42,7 @@ public final class InstrumenterBuilder { final OpenTelemetry openTelemetry; final Meter meter; final String instrumentationName; + final String instrumentationVersion; final SpanNameExtractor spanNameExtractor; final List> spanLinksExtractors = new ArrayList<>(); @@ -63,11 +64,13 @@ public final class InstrumenterBuilder { InstrumenterBuilder( OpenTelemetry openTelemetry, String instrumentationName, + String instrumentationVersion, SpanNameExtractor spanNameExtractor) { this.openTelemetry = openTelemetry; // TODO(anuraaga): Retrieve from openTelemetry when not alpha anymore. this.meter = GlobalMeterProvider.get().get(instrumentationName); this.instrumentationName = instrumentationName; + this.instrumentationVersion = instrumentationVersion; this.spanNameExtractor = spanNameExtractor; } diff --git a/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/instrumenter/InstrumenterTest.java b/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/instrumenter/InstrumenterTest.java index b86cea5592..1786fc431a 100644 --- a/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/instrumenter/InstrumenterTest.java +++ b/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/instrumenter/InstrumenterTest.java @@ -22,6 +22,7 @@ import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; import io.opentelemetry.context.Context; import io.opentelemetry.context.ContextKey; import io.opentelemetry.context.propagation.TextMapGetter; +import io.opentelemetry.instrumentation.api.InstrumentationVersion; import io.opentelemetry.instrumentation.api.instrumenter.db.DbAttributesExtractor; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerAttributesExtractor; @@ -641,6 +642,53 @@ class InstrumenterTest { assertThat(SpanKey.PRODUCER.fromContextOrNull(context)).isNull(); } + @Test + void instrumentationVersion_default() { + InstrumenterBuilder, Map> builder = + Instrumenter.builder(otelTesting.getOpenTelemetry(), "test", name -> "span"); + + Instrumenter, Map> instrumenter = builder.newInstrumenter(); + + Context context = instrumenter.start(Context.root(), Collections.emptyMap()); + assertThat(Span.fromContext(context)).isNotNull(); + + instrumenter.end(context, Collections.emptyMap(), Collections.emptyMap(), null); + + otelTesting + .assertTraces() + .hasTracesSatisfyingExactly( + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasName("span") + .hasInstrumentationLibraryInfo( + InstrumentationLibraryInfo.create( + "test", InstrumentationVersion.VERSION)))); + } + + @Test + void instrumentationVersion_custom() { + InstrumenterBuilder, Map> builder = + Instrumenter.builder(otelTesting.getOpenTelemetry(), "test", "1.0", name -> "span"); + + Instrumenter, Map> instrumenter = builder.newInstrumenter(); + + Context context = instrumenter.start(Context.root(), Collections.emptyMap()); + assertThat(Span.fromContext(context)).isNotNull(); + + instrumenter.end(context, Collections.emptyMap(), Collections.emptyMap(), null); + + otelTesting + .assertTraces() + .hasTracesSatisfyingExactly( + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasName("span") + .hasInstrumentationLibraryInfo( + InstrumentationLibraryInfo.create("test", "1.0")))); + } + private static void validateInstrumentationTypeSpanPresent(SpanKey spanKey, Context context) { Span span = Span.fromContext(context);