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:
		
							parent
							
								
									b212fce5a1
								
							
						
					
					
						commit
						ca92a9ab03
					
				|  | @ -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}. | ||||
|  |  | |||
|  | @ -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(); | ||||
| } | ||||
|  |  | |||
|  | @ -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(); | ||||
|   } | ||||
| } | ||||
|  | @ -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(); | ||||
| } | ||||
|  | @ -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(); | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -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(); | ||||
|   } | ||||
| } | ||||
|  | @ -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); | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -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(); | ||||
| } | ||||
|  | @ -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(); | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -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()); | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -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) | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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) | ||||
|  |  | |||
|  | @ -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<>(); | ||||
|  |  | |||
|  | @ -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<>(); | ||||
|  |  | |||
|  | @ -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()); | ||||
|  |  | |||
|  | @ -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( | ||||
|  |  | |||
|  | @ -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(); | ||||
|   } | ||||
| 
 | ||||
|  |  | |||
|  | @ -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() {} | ||||
| } | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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); | ||||
|   } | ||||
| } | ||||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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); | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -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); | ||||
|   } | ||||
| } | ||||
|  | @ -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. */ | ||||
|  |  | |||
|  | @ -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]+, " | ||||
|  |  | |||
|  | @ -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); | ||||
|   } | ||||
| 
 | ||||
|  |  | |||
|  | @ -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() { | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue