Introduce usage of the OpenTelemetry schema with a Tracer/MeterBuilder (#3309)

* Add the OpenTelemetry schema URL to the InstrumentationLibraryInfo and the corresponding API calls.

* small refactoring and doc tweaks from feedback

* make the instrumentation version nullable on the method that takes a schema

* update the apidiffs

* add since tags and a few more missing nullable annotations

* Switch to using a Builder rather than method overloads.
This commit is contained in:
John Watson 2021-06-11 20:50:23 -07:00 committed by GitHub
parent b212fce5a1
commit ca92a9ab03
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 527 additions and 49 deletions

View File

@ -7,6 +7,7 @@ package io.opentelemetry.api;
import io.opentelemetry.api.internal.GuardedBy;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.api.trace.TracerBuilder;
import io.opentelemetry.api.trace.TracerProvider;
import io.opentelemetry.context.propagation.ContextPropagators;
import java.lang.reflect.InvocationTargetException;
@ -126,6 +127,20 @@ public final class GlobalOpenTelemetry {
return get().getTracer(instrumentationName, instrumentationVersion);
}
/**
* Creates a TracerBuilder for a named {@link Tracer} instance.
*
* <p>This is a shortcut method for {@code get().tracerBuilder(instrumentationName)}
*
* @param instrumentationName The name of the instrumentation library, not the name of the
* instrument*ed* library.
* @return a TracerBuilder instance.
* @since 1.4.0
*/
public static TracerBuilder tracerBuilder(String instrumentationName) {
return get().tracerBuilder(instrumentationName);
}
/**
* Unsets the global {@link OpenTelemetry}. This is only meant to be used from tests which need to
* reconfigure {@link OpenTelemetry}.

View File

@ -6,6 +6,7 @@
package io.opentelemetry.api;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.api.trace.TracerBuilder;
import io.opentelemetry.api.trace.TracerProvider;
import io.opentelemetry.context.propagation.ContextPropagators;
@ -63,6 +64,18 @@ public interface OpenTelemetry {
return getTracerProvider().get(instrumentationName, instrumentationVersion);
}
/**
* Creates a {@link TracerBuilder} for a named {@link Tracer} instance.
*
* @param instrumentationName The name of the instrumentation library, not the name of the
* instrument*ed* library.
* @return a TracerBuilder instance.
* @since 1.4.0
*/
default TracerBuilder tracerBuilder(String instrumentationName) {
return getTracerProvider().tracerBuilder(instrumentationName);
}
/** Returns the {@link ContextPropagators} for this {@link OpenTelemetry}. */
ContextPropagators getPropagators();
}

View File

@ -0,0 +1,29 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.trace;
class DefaultTracerBuilder implements TracerBuilder {
private static final DefaultTracerBuilder INSTANCE = new DefaultTracerBuilder();
static TracerBuilder getInstance() {
return INSTANCE;
}
@Override
public TracerBuilder setSchemaUrl(String schemaUrl) {
return this;
}
@Override
public TracerBuilder setInstrumentationVersion(String instrumentationVersion) {
return this;
}
@Override
public Tracer build() {
return DefaultTracer.getInstance();
}
}

View File

@ -0,0 +1,38 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.trace;
/**
* Builder class for creating {@link Tracer} instances.
*
* @since 1.4.0
*/
public interface TracerBuilder {
/**
* Assign an OpenTelemetry schema URL to the resulting Tracer.
*
* @param schemaUrl The URL of the OpenTelemetry schema being used by this instrumentation
* library.
* @return this
*/
TracerBuilder setSchemaUrl(String schemaUrl);
/**
* Assign a version to the instrumentation library that is using the resulting Tracer.
*
* @param instrumentationVersion The version of the instrumentation library.
* @return this
*/
TracerBuilder setInstrumentationVersion(String instrumentationVersion);
/**
* Gets or creates a {@link Tracer} instance.
*
* @return a {@link Tracer} instance configured with the provided options.
*/
Tracer build();
}

View File

@ -46,4 +46,16 @@ public interface TracerProvider {
* @return a tracer instance.
*/
Tracer get(String instrumentationName, String instrumentationVersion);
/**
* Creates a TracerBuilder for a named {@link Tracer} instance.
*
* @param instrumentationName The name of the instrumentation library, not the name of the
* instrument*ed* library.
* @return a TracerBuilder instance.
* @since 1.4.0
*/
default TracerBuilder tracerBuilder(String instrumentationName) {
return DefaultTracerBuilder.getInstance();
}
}

View File

@ -0,0 +1,29 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
class DefaultMeterBuilder implements MeterBuilder {
private static final MeterBuilder INSTANCE = new DefaultMeterBuilder();
static MeterBuilder getInstance() {
return INSTANCE;
}
@Override
public MeterBuilder setSchemaUrl(String schemaUrl) {
return this;
}
@Override
public MeterBuilder setInstrumentationVersion(String instrumentationVersion) {
return this;
}
@Override
public Meter build() {
return DefaultMeter.getInstance();
}
}

View File

@ -68,4 +68,18 @@ public final class GlobalMeterProvider {
public static Meter getMeter(String instrumentationName, String instrumentationVersion) {
return get().get(instrumentationName, instrumentationVersion);
}
/**
* Creates a {@link MeterBuilder} for a named meter instance.
*
* <p>This is a shortcut method for {@code get().meterBuilder(instrumentationName)}
*
* @param instrumentationName The name of the instrumentation library, not the name of the
* instrument*ed* library.
* @return a MeterBuilder instance.
* @since 1.4.0
*/
public static MeterBuilder meterBuilder(String instrumentationName) {
return get().meterBuilder(instrumentationName);
}
}

View File

@ -0,0 +1,38 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
/**
* Builder class for creating {@link Meter} instances.
*
* @since 1.4.0
*/
public interface MeterBuilder {
/**
* Assign an OpenTelemetry schema URL to the resulting Meter.
*
* @param schemaUrl The URL of the OpenTelemetry schema being used by this instrumentation
* library.
* @return this
*/
MeterBuilder setSchemaUrl(String schemaUrl);
/**
* Assign a version to the instrumentation library that is using the resulting Meter.
*
* @param instrumentationVersion The version of the instrumentation library.
* @return this
*/
MeterBuilder setInstrumentationVersion(String instrumentationVersion);
/**
* Gets or creates a {@link Meter} instance.
*
* @return a {@link Meter} instance configured with the provided options.
*/
Meter build();
}

View File

@ -42,4 +42,16 @@ public interface MeterProvider {
* @return a tracer instance.
*/
Meter get(String instrumentationName, String instrumentationVersion);
/**
* Creates a MeterBuilder for a named meter instance.
*
* @param instrumentationName The name of the instrumentation library, not the name of the
* instrument*ed* library.
* @return a MeterBuilder instance.
* @since 1.4.0
*/
default MeterBuilder meterBuilder(String instrumentationName) {
return DefaultMeterBuilder.getInstance();
}
}

View File

@ -15,5 +15,12 @@ class DefaultMeterTest {
assertThat(MeterProvider.noop().get("test")).isInstanceOf(DefaultMeter.class);
assertThat(MeterProvider.noop().get("test")).isSameAs(DefaultMeter.getInstance());
assertThat(MeterProvider.noop().get("test", "0.1.0")).isSameAs(DefaultMeter.getInstance());
assertThat(
MeterProvider.noop()
.meterBuilder("test")
.setInstrumentationVersion("0.1.0")
.setSchemaUrl("http://url")
.build())
.isSameAs(DefaultMeter.getInstance());
}
}

View File

@ -1,2 +1,16 @@
Comparing source compatibility of against
No changes.
*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.api.GlobalOpenTelemetry (not serializable)
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
+++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.api.trace.TracerBuilder tracerBuilder(java.lang.String)
***! MODIFIED INTERFACE: PUBLIC ABSTRACT io.opentelemetry.api.OpenTelemetry (not serializable)
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
+++! NEW METHOD: PUBLIC(+) io.opentelemetry.api.trace.TracerBuilder tracerBuilder(java.lang.String)
+++ NEW INTERFACE: PUBLIC(+) ABSTRACT(+) io.opentelemetry.api.trace.TracerBuilder (not serializable)
+++ CLASS FILE FORMAT VERSION: 52.0 <- n.a.
+++ NEW SUPERCLASS: java.lang.Object
+++ NEW METHOD: PUBLIC(+) ABSTRACT(+) io.opentelemetry.api.trace.Tracer build()
+++ NEW METHOD: PUBLIC(+) ABSTRACT(+) io.opentelemetry.api.trace.TracerBuilder setInstrumentationVersion(java.lang.String)
+++ NEW METHOD: PUBLIC(+) ABSTRACT(+) io.opentelemetry.api.trace.TracerBuilder setSchemaUrl(java.lang.String)
***! MODIFIED INTERFACE: PUBLIC ABSTRACT io.opentelemetry.api.trace.TracerProvider (not serializable)
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
+++! NEW METHOD: PUBLIC(+) io.opentelemetry.api.trace.TracerBuilder tracerBuilder(java.lang.String)

View File

@ -1,2 +1,6 @@
Comparing source compatibility of against
No changes.
**** MODIFIED CLASS: PUBLIC ABSTRACT io.opentelemetry.sdk.common.InstrumentationLibraryInfo (not serializable)
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
+++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.common.InstrumentationLibraryInfo create(java.lang.String, java.lang.String, java.lang.String)
+++* NEW METHOD: PUBLIC(+) ABSTRACT(+) java.lang.String getSchemaUrl()
+++ NEW ANNOTATION: javax.annotation.Nullable

View File

@ -1,2 +1,4 @@
Comparing source compatibility of against
No changes.
*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.sdk.trace.SdkTracerProvider (not serializable)
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.api.trace.TracerBuilder tracerBuilder(java.lang.String)

View File

@ -58,12 +58,7 @@ public final class MetricAdapter {
new ArrayList<>(entryResource.getValue().size());
for (Map.Entry<InstrumentationLibraryInfo, List<Metric>> entryLibrary :
entryResource.getValue().entrySet()) {
instrumentationLibraryMetrics.add(
InstrumentationLibraryMetrics.newBuilder()
.setInstrumentationLibrary(
CommonAdapter.toProtoInstrumentationLibrary(entryLibrary.getKey()))
.addAllMetrics(entryLibrary.getValue())
.build());
instrumentationLibraryMetrics.add(buildInstrumentationLibraryMetrics(entryLibrary));
}
resourceMetrics.add(
ResourceMetrics.newBuilder()
@ -74,6 +69,19 @@ public final class MetricAdapter {
return resourceMetrics;
}
private static InstrumentationLibraryMetrics buildInstrumentationLibraryMetrics(
Map.Entry<InstrumentationLibraryInfo, List<Metric>> entryLibrary) {
InstrumentationLibraryMetrics.Builder metricsBuilder =
InstrumentationLibraryMetrics.newBuilder()
.setInstrumentationLibrary(
CommonAdapter.toProtoInstrumentationLibrary(entryLibrary.getKey()))
.addAllMetrics(entryLibrary.getValue());
if (entryLibrary.getKey().getSchemaUrl() != null) {
metricsBuilder.setSchemaUrl(entryLibrary.getKey().getSchemaUrl());
}
return metricsBuilder.build();
}
private static Map<Resource, Map<InstrumentationLibraryInfo, List<Metric>>>
groupByResourceAndLibrary(Collection<MetricData> metricDataList) {
Map<Resource, Map<InstrumentationLibraryInfo, List<Metric>>> result = new HashMap<>();

View File

@ -75,18 +75,27 @@ public final class SpanAdapter {
ResourceSpans.Builder resourceSpansBuilder =
ResourceSpans.newBuilder().setResource(ResourceAdapter.toProtoResource(resource));
librarySpans.forEach(
(library, spans) ->
resourceSpansBuilder.addInstrumentationLibrarySpans(
InstrumentationLibrarySpans.newBuilder()
.setInstrumentationLibrary(
CommonAdapter.toProtoInstrumentationLibrary(library))
.addAllSpans(spans)
.build()));
(library, spans) -> {
resourceSpansBuilder.addInstrumentationLibrarySpans(
buildInstrumentationLibrarySpan(library, spans));
});
resourceSpans.add(resourceSpansBuilder.build());
});
return resourceSpans;
}
private static InstrumentationLibrarySpans buildInstrumentationLibrarySpan(
InstrumentationLibraryInfo library, List<Span> spans) {
InstrumentationLibrarySpans.Builder spansBuilder =
InstrumentationLibrarySpans.newBuilder()
.setInstrumentationLibrary(CommonAdapter.toProtoInstrumentationLibrary(library))
.addAllSpans(spans);
if (library.getSchemaUrl() != null) {
spansBuilder.setSchemaUrl(library.getSchemaUrl());
}
return spansBuilder.build();
}
private static Map<Resource, Map<InstrumentationLibraryInfo, List<Span>>>
groupByResourceAndLibrary(Collection<SpanData> spanDataList) {
Map<Resource, Map<InstrumentationLibraryInfo, List<Span>>> result = new HashMap<>();

View File

@ -568,7 +568,7 @@ class MetricAdapterTest {
io.opentelemetry.proto.resource.v1.Resource emptyResourceProto =
io.opentelemetry.proto.resource.v1.Resource.newBuilder().build();
InstrumentationLibraryInfo instrumentationLibraryInfo =
InstrumentationLibraryInfo.create("name", "version");
InstrumentationLibraryInfo.create("name", "version", "http://url");
InstrumentationLibrary instrumentationLibraryProto =
InstrumentationLibrary.newBuilder().setName("name").setVersion("version").build();
InstrumentationLibrary emptyInstrumentationLibraryProto =
@ -652,6 +652,7 @@ class MetricAdapterTest {
InstrumentationLibraryMetrics.newBuilder()
.setInstrumentationLibrary(instrumentationLibraryProto)
.addAllMetrics(ImmutableList.of(metricDoubleSum, metricDoubleSum))
.setSchemaUrl("http://url")
.build()))
.build(),
ResourceMetrics.newBuilder()
@ -659,11 +660,12 @@ class MetricAdapterTest {
.addAllInstrumentationLibraryMetrics(
ImmutableList.of(
InstrumentationLibraryMetrics.newBuilder()
.setInstrumentationLibrary(emptyInstrumentationLibraryProto)
.setInstrumentationLibrary(instrumentationLibraryProto)
.addAllMetrics(singletonList(metricDoubleSum))
.setSchemaUrl("http://url")
.build(),
InstrumentationLibraryMetrics.newBuilder()
.setInstrumentationLibrary(instrumentationLibraryProto)
.setInstrumentationLibrary(emptyInstrumentationLibraryProto)
.addAllMetrics(singletonList(metricDoubleSum))
.build()))
.build());

View File

@ -29,14 +29,19 @@ import io.opentelemetry.api.trace.TraceFlags;
import io.opentelemetry.api.trace.TraceId;
import io.opentelemetry.api.trace.TraceState;
import io.opentelemetry.proto.common.v1.AnyValue;
import io.opentelemetry.proto.common.v1.InstrumentationLibrary;
import io.opentelemetry.proto.common.v1.KeyValue;
import io.opentelemetry.proto.trace.v1.InstrumentationLibrarySpans;
import io.opentelemetry.proto.trace.v1.ResourceSpans;
import io.opentelemetry.proto.trace.v1.Span;
import io.opentelemetry.proto.trace.v1.Status;
import io.opentelemetry.sdk.common.InstrumentationLibraryInfo;
import io.opentelemetry.sdk.testing.trace.TestSpanData;
import io.opentelemetry.sdk.trace.data.EventData;
import io.opentelemetry.sdk.trace.data.LinkData;
import io.opentelemetry.sdk.trace.data.StatusData;
import java.util.Collections;
import java.util.List;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.Test;
@ -52,6 +57,35 @@ class SpanAdapterTest {
private static final SpanAdapter.ThreadLocalCache threadLocalCache =
new SpanAdapter.ThreadLocalCache();
@Test
void toProtoResourceSpans() {
List<ResourceSpans> resourceSpans =
SpanAdapter.toProtoResourceSpans(
Collections.singleton(
TestSpanData.builder()
.setHasEnded(true)
.setSpanContext(SPAN_CONTEXT)
.setParentSpanContext(SpanContext.getInvalid())
.setName("GET /api/endpoint")
.setKind(SpanKind.SERVER)
.setStartEpochNanos(12345)
.setEndEpochNanos(12349)
.setStatus(StatusData.unset())
.setInstrumentationLibraryInfo(
InstrumentationLibraryInfo.create("testLib", "1.0", "http://url"))
.build()));
assertThat(resourceSpans).hasSize(1);
ResourceSpans onlyResourceSpans = resourceSpans.get(0);
assertThat(onlyResourceSpans.getInstrumentationLibrarySpansCount()).isEqualTo(1);
InstrumentationLibrarySpans instrumentationLibrarySpans =
onlyResourceSpans.getInstrumentationLibrarySpans(0);
assertThat(instrumentationLibrarySpans.getSchemaUrl()).isEqualTo("http://url");
assertThat(instrumentationLibrarySpans.getInstrumentationLibrary())
.isEqualTo(
InstrumentationLibrary.newBuilder().setName("testLib").setVersion("1.0").build());
}
// Repeat to reuse the cache. If we forgot to clear any reused builder it will fail.
@RepeatedTest(3)
void toProtoSpan() {
@ -115,7 +149,8 @@ class SpanAdapterTest {
}
@Test
@SuppressWarnings("deprecation") // setDeprecatedCode is deprecated.
@SuppressWarnings("deprecation")
// setDeprecatedCode is deprecated.
void toProtoStatus() {
assertThat(SpanAdapter.toStatusProto(StatusData.unset()))
.isEqualTo(

View File

@ -28,6 +28,7 @@ import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceResponse;
import io.opentelemetry.proto.collector.trace.v1.TraceServiceGrpc;
import io.opentelemetry.proto.trace.v1.ResourceSpans;
import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.common.InstrumentationLibraryInfo;
import io.opentelemetry.sdk.testing.trace.TestSpanData;
import io.opentelemetry.sdk.trace.data.SpanData;
import io.opentelemetry.sdk.trace.data.StatusData;
@ -301,6 +302,8 @@ class OtlpGrpcSpanExporterTest {
.setLinks(Collections.emptyList())
.setTotalRecordedLinks(0)
.setTotalRecordedEvents(0)
.setInstrumentationLibraryInfo(
InstrumentationLibraryInfo.create("testLib", "1.0", "http://url"))
.build();
}

View File

@ -31,7 +31,24 @@ public abstract class InstrumentationLibraryInfo {
*/
public static InstrumentationLibraryInfo create(String name, @Nullable String version) {
requireNonNull(name, "name");
return new AutoValue_InstrumentationLibraryInfo(name, version);
return new AutoValue_InstrumentationLibraryInfo(name, version, null);
}
/**
* Creates a new instance of {@link InstrumentationLibraryInfo}.
*
* @param name name of the instrumentation library (e.g., "io.opentelemetry.contrib.mongodb"),
* must not be null
* @param version version of the instrumentation library (e.g., "1.0.0"), might be null
* @param schemaUrl the URL of the OpenTelemetry schema being used by this instrumentation
* library.
* @return the new instance
* @since 1.4.0
*/
public static InstrumentationLibraryInfo create(
String name, @Nullable String version, @Nullable String schemaUrl) {
requireNonNull(name, "name");
return new AutoValue_InstrumentationLibraryInfo(name, version, schemaUrl);
}
/**
@ -58,6 +75,16 @@ public abstract class InstrumentationLibraryInfo {
@Nullable
public abstract String getVersion();
/**
* Returns the URL of the schema used by this instrumentation library, or {@code null} if not
* available.
*
* @return the URL of the schema used by this instrumentation library, or {@code null} if not
* available.
*/
@Nullable
public abstract String getSchemaUrl();
// Package protected ctor to avoid others to extend this class.
InstrumentationLibraryInfo() {}
}

View File

@ -30,8 +30,8 @@ public final class ComponentRegistry<V> {
/**
* Returns the registered value associated with this name and {@code null} version if any,
* otherwise creates a new instance and associates it with the given name and {@code null}
* version.
* otherwise creates a new instance and associates it with the given name and {@code null} version
* and schemaUrl.
*
* @param instrumentationName the name of the instrumentation library.
* @return the registered value associated with this name and {@code null} version.
@ -42,15 +42,33 @@ public final class ComponentRegistry<V> {
/**
* Returns the registered value associated with this name and version if any, otherwise creates a
* new instance and associates it with the given name and version.
* new instance and associates it with the given name and version. The schemaUrl will be set to
* null.
*
* @param instrumentationName the name of the instrumentation library.
* @param instrumentationVersion the version of the instrumentation library.
* @return the registered value associated with this name and version.
*/
public final V get(String instrumentationName, @Nullable String instrumentationVersion) {
return get(instrumentationName, instrumentationVersion, null);
}
/**
* Returns the registered value associated with this name and version if any, otherwise creates a
* new instance and associates it with the given name and version.
*
* @param instrumentationName the name of the instrumentation library.
* @param instrumentationVersion the version of the instrumentation library.
* @param schemaUrl the URL of the OpenTelemetry schema used by the instrumentation library.
* @return the registered value associated with this name and version.
* @since 1.4.0
*/
public final V get(
String instrumentationName,
@Nullable String instrumentationVersion,
@Nullable String schemaUrl) {
InstrumentationLibraryInfo instrumentationLibraryInfo =
InstrumentationLibraryInfo.create(instrumentationName, instrumentationVersion);
InstrumentationLibraryInfo.create(instrumentationName, instrumentationVersion, schemaUrl);
// Optimistic lookup, before creating the new component.
V component = registry.get(instrumentationLibraryInfo);

View File

@ -0,0 +1,40 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.sdk.metrics;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.api.metrics.MeterBuilder;
import io.opentelemetry.sdk.internal.ComponentRegistry;
class SdkMeterBuilder implements MeterBuilder {
private final ComponentRegistry<SdkMeter> registry;
private final String instrumentationName;
private String instrumentationVersion;
private String schemaUrl;
SdkMeterBuilder(ComponentRegistry<SdkMeter> registry, String instrumentationName) {
this.registry = registry;
this.instrumentationName = instrumentationName;
}
@Override
public MeterBuilder setSchemaUrl(String schemaUrl) {
this.schemaUrl = schemaUrl;
return this;
}
@Override
public MeterBuilder setInstrumentationVersion(String instrumentationVersion) {
this.instrumentationVersion = instrumentationVersion;
return this;
}
@Override
public Meter build() {
return registry.get(instrumentationName, instrumentationVersion, schemaUrl);
}
}

View File

@ -7,6 +7,7 @@ package io.opentelemetry.sdk.metrics;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.api.metrics.MeterBuilder;
import io.opentelemetry.api.metrics.MeterProvider;
import io.opentelemetry.sdk.common.Clock;
import io.opentelemetry.sdk.internal.ComponentRegistry;
@ -47,17 +48,23 @@ public final class SdkMeterProvider implements MeterProvider, MetricProducer {
@Override
public Meter get(String instrumentationName) {
return get(instrumentationName, null);
return meterBuilder(instrumentationName).build();
}
@Override
public Meter get(String instrumentationName, @Nullable String instrumentationVersion) {
// Per the spec, both null and empty are "invalid" and a "default" should be used.
public Meter get(String instrumentationName, String instrumentationVersion) {
return meterBuilder(instrumentationName)
.setInstrumentationVersion(instrumentationVersion)
.build();
}
@Override
public MeterBuilder meterBuilder(@Nullable String instrumentationName) {
if (instrumentationName == null || instrumentationName.isEmpty()) {
LOGGER.fine("Meter requested without instrumentation name.");
instrumentationName = DEFAULT_METER_NAME;
}
return registry.get(instrumentationName, instrumentationVersion);
return new SdkMeterBuilder(registry, instrumentationName);
}
@Override

View File

@ -62,18 +62,43 @@ class SdkMeterRegistryTest {
void getSameInstanceForSameName_WithoutVersion() {
assertThat(meterProvider.get("test")).isSameAs(meterProvider.get("test"));
assertThat(meterProvider.get("test")).isSameAs(meterProvider.get("test", null));
assertThat(meterProvider.get("test")).isSameAs(meterProvider.meterBuilder("test").build());
}
@Test
void getSameInstanceForSameName_WithVersion() {
assertThat(meterProvider.get("test", "version")).isSameAs(meterProvider.get("test", "version"));
assertThat(meterProvider.get("test", "version"))
.isSameAs(meterProvider.get("test", "version"))
.isSameAs(meterProvider.meterBuilder("test").setInstrumentationVersion("version").build());
}
@Test
void getSameInstanceForSameName_WithVersionAndSchema() {
assertThat(
meterProvider
.meterBuilder("test")
.setInstrumentationVersion("version")
.setSchemaUrl("http://url")
.build())
.isSameAs(
meterProvider
.meterBuilder("test")
.setInstrumentationVersion("version")
.setSchemaUrl("http://url")
.build());
}
@Test
void propagatesInstrumentationLibraryInfoToMeter() {
InstrumentationLibraryInfo expected =
InstrumentationLibraryInfo.create("theName", "theVersion");
SdkMeter meter = (SdkMeter) meterProvider.get(expected.getName(), expected.getVersion());
InstrumentationLibraryInfo.create("theName", "theVersion", "http://theschema");
SdkMeter meter =
(SdkMeter)
meterProvider
.meterBuilder(expected.getName())
.setInstrumentationVersion(expected.getVersion())
.setSchemaUrl(expected.getSchemaUrl())
.build();
assertThat(meter.getInstrumentationLibraryInfo()).isEqualTo(expected);
}
@ -123,6 +148,10 @@ class SdkMeterRegistryTest {
meter = (SdkMeter) meterProvider.get(null, null);
assertThat(meter.getInstrumentationLibraryInfo().getName())
.isEqualTo(SdkMeterProvider.DEFAULT_METER_NAME);
meter = (SdkMeter) meterProvider.meterBuilder(null).build();
assertThat(meter.getInstrumentationLibraryInfo().getName())
.isEqualTo(SdkMeterProvider.DEFAULT_METER_NAME);
}
@Test
@ -134,5 +163,9 @@ class SdkMeterRegistryTest {
meter = (SdkMeter) meterProvider.get("", "");
assertThat(meter.getInstrumentationLibraryInfo().getName())
.isEqualTo(SdkMeterProvider.DEFAULT_METER_NAME);
meter = (SdkMeter) meterProvider.meterBuilder("").build();
assertThat(meter.getInstrumentationLibraryInfo().getName())
.isEqualTo(SdkMeterProvider.DEFAULT_METER_NAME);
}
}

View File

@ -0,0 +1,40 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.sdk.trace;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.api.trace.TracerBuilder;
import io.opentelemetry.sdk.internal.ComponentRegistry;
class SdkTracerBuilder implements TracerBuilder {
private final ComponentRegistry<SdkTracer> registry;
private final String instrumentationName;
private String instrumentationVersion;
private String schemaUrl;
SdkTracerBuilder(ComponentRegistry<SdkTracer> registry, String instrumentationName) {
this.registry = registry;
this.instrumentationName = instrumentationName;
}
@Override
public TracerBuilder setSchemaUrl(String schemaUrl) {
this.schemaUrl = schemaUrl;
return this;
}
@Override
public TracerBuilder setInstrumentationVersion(String instrumentationVersion) {
this.instrumentationVersion = instrumentationVersion;
return this;
}
@Override
public Tracer build() {
return registry.get(instrumentationName, instrumentationVersion, schemaUrl);
}
}

View File

@ -7,6 +7,7 @@ package io.opentelemetry.sdk.trace;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.api.trace.TracerBuilder;
import io.opentelemetry.api.trace.TracerProvider;
import io.opentelemetry.sdk.common.Clock;
import io.opentelemetry.sdk.common.CompletableResultCode;
@ -60,17 +61,24 @@ public final class SdkTracerProvider implements TracerProvider, Closeable {
@Override
public Tracer get(String instrumentationName) {
return get(instrumentationName, null);
return tracerBuilder(instrumentationName).build();
}
@Override
public Tracer get(String instrumentationName, @Nullable String instrumentationVersion) {
public Tracer get(String instrumentationName, String instrumentationVersion) {
return tracerBuilder(instrumentationName)
.setInstrumentationVersion(instrumentationVersion)
.build();
}
@Override
public TracerBuilder tracerBuilder(@Nullable String instrumentationName) {
// Per the spec, both null and empty are "invalid" and a default value should be used.
if (instrumentationName == null || instrumentationName.isEmpty()) {
logger.fine("Tracer requested without instrumentation name.");
instrumentationName = DEFAULT_TRACER_NAME;
}
return tracerSdkComponentRegistry.get(instrumentationName, instrumentationVersion);
return new SdkTracerBuilder(tracerSdkComponentRegistry, instrumentationName);
}
/** Returns the {@link SpanLimits} that are currently applied to created spans. */

View File

@ -957,7 +957,7 @@ class SdkSpanBuilderTest {
+ "telemetry.sdk.language=\"java\", telemetry.sdk.name=\"opentelemetry\", "
+ "telemetry.sdk.version=\"\\d+.\\d+.\\d+(-SNAPSHOT)?\"}}, "
+ "instrumentationLibraryInfo=InstrumentationLibraryInfo\\{"
+ "name=SpanBuilderSdkTest, version=null}, "
+ "name=SpanBuilderSdkTest, version=null, schemaUrl=null}, "
+ "name=span_name, "
+ "kind=INTERNAL, "
+ "startEpochNanos=[0-9]+, "

View File

@ -139,19 +139,44 @@ class SdkTracerProviderTest {
@Test
void getSameInstanceForSameName_WithoutVersion() {
assertThat(tracerFactory.get("test")).isSameAs(tracerFactory.get("test"));
assertThat(tracerFactory.get("test")).isSameAs(tracerFactory.get("test", null));
assertThat(tracerFactory.get("test"))
.isSameAs(tracerFactory.get("test", null))
.isSameAs(tracerFactory.tracerBuilder("test").build());
}
@Test
void getSameInstanceForSameName_WithVersion() {
assertThat(tracerFactory.get("test", "version")).isSameAs(tracerFactory.get("test", "version"));
assertThat(tracerFactory.get("test", "version"))
.isSameAs(tracerFactory.get("test", "version"))
.isSameAs(tracerFactory.tracerBuilder("test").setInstrumentationVersion("version").build());
}
@Test
void getSameInstanceForSameName_WithVersionAndSchema() {
assertThat(
tracerFactory
.tracerBuilder("test")
.setInstrumentationVersion("version")
.setSchemaUrl("http://url")
.build())
.isSameAs(
tracerFactory
.tracerBuilder("test")
.setInstrumentationVersion("version")
.setSchemaUrl("http://url")
.build());
}
@Test
void propagatesInstrumentationLibraryInfoToTracer() {
InstrumentationLibraryInfo expected =
InstrumentationLibraryInfo.create("theName", "theVersion");
Tracer tracer = tracerFactory.get(expected.getName(), expected.getVersion());
InstrumentationLibraryInfo.create("theName", "theVersion", "http://url");
Tracer tracer =
tracerFactory
.tracerBuilder(expected.getName())
.setInstrumentationVersion(expected.getVersion())
.setSchemaUrl(expected.getSchemaUrl())
.build();
assertThat(((SdkTracer) tracer).getInstrumentationLibraryInfo()).isEqualTo(expected);
}

View File

@ -19,14 +19,7 @@ import io.opentelemetry.sdk.trace.export.SpanExporter;
import java.util.Collection;
import java.util.concurrent.atomic.AtomicLong;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
/** Unit tests for {@link SdkTracer}. */
// Need to suppress warnings for MustBeClosed because Android 14 does not support
// try-with-resources.
@SuppressWarnings("MustBeClosedChecker")
@ExtendWith(MockitoExtension.class)
class SdkTracerTest {
private static final String SPAN_NAME = "span_name";
@ -35,12 +28,15 @@ class SdkTracerTest {
private static final String INSTRUMENTATION_LIBRARY_VERSION = "0.2.0";
private static final InstrumentationLibraryInfo instrumentationLibraryInfo =
InstrumentationLibraryInfo.create(
INSTRUMENTATION_LIBRARY_NAME, INSTRUMENTATION_LIBRARY_VERSION);
INSTRUMENTATION_LIBRARY_NAME, INSTRUMENTATION_LIBRARY_VERSION, "http://schemaurl");
private final SdkTracer tracer =
(SdkTracer)
SdkTracerProvider.builder()
.build()
.get(INSTRUMENTATION_LIBRARY_NAME, INSTRUMENTATION_LIBRARY_VERSION);
.tracerBuilder(INSTRUMENTATION_LIBRARY_NAME)
.setInstrumentationVersion(INSTRUMENTATION_LIBRARY_VERSION)
.setSchemaUrl("http://schemaurl")
.build();
@Test
void defaultSpanBuilder() {