diff --git a/sdk/core/azure-core-amqp/src/main/java/com/azure/core/amqp/implementation/TracerProvider.java b/sdk/core/azure-core-amqp/src/main/java/com/azure/core/amqp/implementation/TracerProvider.java index 526d657154fe..b181712d40e9 100644 --- a/sdk/core/azure-core-amqp/src/main/java/com/azure/core/amqp/implementation/TracerProvider.java +++ b/sdk/core/azure-core-amqp/src/main/java/com/azure/core/amqp/implementation/TracerProvider.java @@ -3,30 +3,31 @@ package com.azure.core.amqp.implementation; import com.azure.core.amqp.exception.AmqpException; -import com.azure.core.util.tracing.ProcessKind; import com.azure.core.util.Context; import com.azure.core.util.logging.ClientLogger; +import com.azure.core.util.tracing.ProcessKind; import com.azure.core.util.tracing.Tracer; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; import reactor.core.publisher.Signal; +import java.util.Objects; + public class TracerProvider { private final ClientLogger logger = new ClientLogger(TracerProvider.class); - private final List tracers = new ArrayList<>(); + private Tracer tracer; public TracerProvider(Iterable tracers) { Objects.requireNonNull(tracers, "'tracers' cannot be null."); - tracers.forEach(e -> this.tracers.add(e)); + if (tracers.iterator().hasNext()) { + tracer = tracers.iterator().next(); + } } public boolean isEnabled() { - return tracers.size() > 0; + return tracer != null; } /** - * For each tracer plugged into the SDK a new tracing span is created. + * For a plugged tracer implementation a new tracing span is created. * * The {@code context} will be checked for containing information about a parent span. If a parent span is found the * new span will be added as a child, otherwise the span will be created and added to the context and any downstream @@ -37,15 +38,14 @@ public boolean isEnabled() { * @return An updated context object. */ public Context startSpan(Context context, ProcessKind processKind) { - Context local = Objects.requireNonNull(context, "'context' cannot be null."); + if (tracer == null) { + return context; + } + Objects.requireNonNull(context, "'context' cannot be null."); Objects.requireNonNull(processKind, "'processKind' cannot be null."); String spanName = getSpanName(processKind); - for (Tracer tracer : tracers) { - local = tracer.start(spanName, local, processKind); - } - - return local; + return tracer.start(spanName, context, processKind); } /** @@ -56,6 +56,9 @@ public Context startSpan(Context context, ProcessKind processKind) { * @param signal The signal indicates the status and contains the metadata we need to end the tracing span. */ public void endSpan(Context context, Signal signal) { + if (tracer == null) { + return; + } Objects.requireNonNull(context, "'context' cannot be null."); Objects.requireNonNull(signal, "'signal' cannot be null."); @@ -84,48 +87,49 @@ public void endSpan(Context context, Signal signal) { } /** - * For each tracer plugged into the SDK a link is created between the parent tracing span and + * For a plugged tracer implementation a link is created between the parent tracing span and * the current service call. * * @param context Additional metadata that is passed through the call stack. */ public void addSpanLinks(Context context) { + if (tracer == null) { + return; + } Objects.requireNonNull(context, "'context' cannot be null."); - tracers.forEach(tracer -> tracer.addLink(context)); + tracer.addLink(context); } /** - * For each tracer plugged into the SDK a new context is extracted from the event's diagnostic Id. + * For a plugged tracer implementation a new context is extracted from the event's diagnostic Id. * * @param diagnosticId Unique identifier of an external call from producer to the queue. */ public Context extractContext(String diagnosticId, Context context) { - Context local = Objects.requireNonNull(context, "'context' cannot be null."); - Objects.requireNonNull(diagnosticId, "'diagnosticId' cannot be null."); - for (Tracer tracer : tracers) { - local = tracer.extractContext(diagnosticId, local); + if (tracer == null) { + return context; } - return local; + Objects.requireNonNull(context, "'context' cannot be null."); + Objects.requireNonNull(diagnosticId, "'diagnosticId' cannot be null."); + return tracer.extractContext(diagnosticId, context); } /** - * For each tracer plugged into the SDK a new context containing the span builder is returned. + * For a plugged tracer implementation a new context containing the span builder is returned. * - * @param context Additional metadata containing the span name for creating the span builer. + * @param context Additional metadata containing the span name for creating the span builder. */ public Context getSharedSpanBuilder(Context context) { - Context local = Objects.requireNonNull(context, "'context' cannot be null."); - String spanName = getSpanName(ProcessKind.SEND); - for (Tracer tracer : tracers) { - local = tracer.getSharedSpanBuilder(spanName, local); + if (tracer == null) { + return context; } - return local; + Objects.requireNonNull(context, "'context' cannot be null."); + String spanName = getSpanName(ProcessKind.SEND); + return tracer.getSharedSpanBuilder(spanName, context); } private void end(String statusMessage, Throwable throwable, Context context) { - for (Tracer tracer : tracers) { - tracer.end(statusMessage, throwable, context); - } + tracer.end(statusMessage, throwable, context); } private String getSpanName(ProcessKind processKind) { @@ -144,7 +148,6 @@ private String getSpanName(ProcessKind processKind) { logger.warning("Unknown processKind type: {}", processKind); break; } - return spanName; } } diff --git a/sdk/core/azure-core-amqp/src/test/java/com/azure/core/amqp/implementation/TracerProviderTest.java b/sdk/core/azure-core-amqp/src/test/java/com/azure/core/amqp/implementation/TracerProviderTest.java index e9d3f120e6d0..28e37fc0daf7 100644 --- a/sdk/core/azure-core-amqp/src/test/java/com/azure/core/amqp/implementation/TracerProviderTest.java +++ b/sdk/core/azure-core-amqp/src/test/java/com/azure/core/amqp/implementation/TracerProviderTest.java @@ -17,28 +17,19 @@ import org.mockito.MockitoAnnotations; import reactor.core.publisher.Signal; -import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Optional; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.isNull; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; public class TracerProviderTest { private static final String METHOD_NAME = "EventHubs.send"; @Mock private Tracer tracer; - @Mock - private Tracer tracer2; private List tracers; private TracerProvider tracerProvider; @@ -47,7 +38,7 @@ public class TracerProviderTest { public void setup() { MockitoAnnotations.initMocks(this); - tracers = Arrays.asList(tracer, tracer2); + tracers = Collections.singletonList(tracer); tracerProvider = new TracerProvider(tracers); } @@ -82,8 +73,6 @@ public void startSpanReturnsUpdatedContext() { // Arrange final String parentKey = "parent-key"; final String parentValue = "parent-value"; - final String childKey = "child-key"; - final String childValue = "child-value"; final Context startingContext = Context.NONE; when(tracer.start(METHOD_NAME, startingContext, ProcessKind.SEND)).thenAnswer( invocation -> { @@ -91,25 +80,15 @@ public void startSpanReturnsUpdatedContext() { return passed.addData(parentKey, parentValue); } ); - when(tracer2.start(eq(METHOD_NAME), any(), eq(ProcessKind.SEND))).thenAnswer( - invocation -> { - Context passed = invocation.getArgument(1, Context.class); - return passed.addData(childKey, childValue); - } - ); // Act final Context updatedContext = tracerProvider.startSpan(startingContext, ProcessKind.SEND); // Assert - // Want to ensure that the data added to the parent and child are available. + // Want to ensure that the data added to the parent are available. final Optional parentData = updatedContext.getData(parentKey); Assertions.assertTrue(parentData.isPresent()); Assertions.assertEquals(parentValue, parentData.get()); - - final Optional childData = updatedContext.getData(childKey); - Assertions.assertTrue(childData.isPresent()); - Assertions.assertEquals(childValue, childData.get()); } @Test @@ -202,8 +181,6 @@ public void getSpanBuilderReturnsUpdatedContext() { final String spanBuilderKey = "spanBuilder-key"; final String spanBuilderValue = "spanBuilder-value"; - final String spanBuilderKey1 = "spanBuilder-key1"; - final String spanBuilderValue1 = "spanBuilder-value1"; final Context startingContext = Context.NONE; when(tracer.getSharedSpanBuilder(anyString(), any())).thenAnswer( @@ -212,12 +189,6 @@ public void getSpanBuilderReturnsUpdatedContext() { return passed.addData(spanBuilderKey, spanBuilderValue); } ); - when(tracer2.getSharedSpanBuilder(anyString(), any())).thenAnswer( - invocation -> { - Context passed = invocation.getArgument(1, Context.class); - return passed.addData(spanBuilderKey1, spanBuilderValue1); - } - ); // Act final Context updatedContext = tracerProvider.getSharedSpanBuilder(startingContext); @@ -226,9 +197,5 @@ public void getSpanBuilderReturnsUpdatedContext() { final Optional spanBuilderData = updatedContext.getData(spanBuilderKey); Assertions.assertTrue(spanBuilderData.isPresent()); Assertions.assertEquals(spanBuilderValue, spanBuilderData.get()); - - final Optional spanBuilderData1 = updatedContext.getData(spanBuilderKey1); - Assertions.assertTrue(spanBuilderData1.isPresent()); - Assertions.assertEquals(spanBuilderValue1, spanBuilderData1.get()); } } diff --git a/sdk/core/azure-core-tracing-opentelemetry/src/main/java/com/azure/core/tracing/opentelemetry/OpenTelemetryTracer.java b/sdk/core/azure-core-tracing-opentelemetry/src/main/java/com/azure/core/tracing/opentelemetry/OpenTelemetryTracer.java index b8aa4948311f..a794fff4bff0 100644 --- a/sdk/core/azure-core-tracing-opentelemetry/src/main/java/com/azure/core/tracing/opentelemetry/OpenTelemetryTracer.java +++ b/sdk/core/azure-core-tracing-opentelemetry/src/main/java/com/azure/core/tracing/opentelemetry/OpenTelemetryTracer.java @@ -311,7 +311,7 @@ private Builder getSpanBuilder(String spanName, Context context) { private T getOrDefault(Context context, String key, T defaultValue, Class clazz) { final Optional optional = context.getData(key); final Object result = optional.filter(value -> clazz.isAssignableFrom(value.getClass())).orElseGet(() -> { - logger.warning("Could not extract key '{}' of type '{}' from context.", key, clazz); + logger.verbose("Could not extract key '{}' of type '{}' from context.", key, clazz); return defaultValue; }); diff --git a/sdk/core/azure-core/src/main/java/com/azure/core/util/tracing/TracerProxy.java b/sdk/core/azure-core/src/main/java/com/azure/core/util/tracing/TracerProxy.java index 12d87cd07ae1..8548aa8f030a 100644 --- a/sdk/core/azure-core/src/main/java/com/azure/core/util/tracing/TracerProxy.java +++ b/sdk/core/azure-core/src/main/java/com/azure/core/util/tracing/TracerProxy.java @@ -4,9 +4,7 @@ import com.azure.core.util.Context; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import java.util.Iterator; import java.util.ServiceLoader; /** @@ -17,14 +15,14 @@ */ public final class TracerProxy { - private static final List TRACERS; + private static Tracer tracer; + static { ServiceLoader serviceLoader = ServiceLoader.load(Tracer.class); - List tracers = new ArrayList<>(); - for (Tracer tracer : serviceLoader) { - tracers.add(tracer); + Iterator iterator = serviceLoader.iterator(); + if (iterator.hasNext()) { + tracer = serviceLoader.iterator().next(); } - TRACERS = Collections.unmodifiableList(tracers); } private TracerProxy() { @@ -33,7 +31,7 @@ private TracerProxy() { /** * A new tracing span is created for each {@link Tracer tracer} plugged into the SDK. - * + *

* The {@code context} will be checked for information about a parent span. If a parent span is found, the new span * will be added as a child. Otherwise, the parent span will be created and added to the {@code context} and any * downstream {@code start()} calls will use the created span as the parent. @@ -44,16 +42,14 @@ private TracerProxy() { * @return An updated {@link Context} object. */ public static Context start(String methodName, Context context) { - Context local = context; - for (Tracer tracer : TRACERS) { - local = tracer.start(methodName, local); + if (tracer == null) { + return context; } - - return local; + return tracer.start(methodName, context); } /** - * For each {@link Tracer tracer} plugged into the SDK, the key-value pair metadata is added to its current span. If + * For the plugged in {@link Tracer tracer}, the key-value pair metadata is added to its current span. If * the {@code context} does not contain a span, then no metadata is added. * * @param key Name of the metadata. @@ -61,18 +57,24 @@ public static Context start(String methodName, Context context) { * @param context Additional metadata that is passed through the call stack. */ public static void setAttribute(String key, String value, Context context) { - TRACERS.forEach(tracer -> tracer.setAttribute(key, value, context)); + if (tracer == null) { + return; + } + tracer.setAttribute(key, value, context); } /** - * For each {@link Tracer tracer} plugged into the SDK, its current tracing span is marked as completed. + * For the plugged in {@link Tracer tracer}, its current tracing span is marked as completed. * * @param responseCode Response status code if the span is in a HTTP call context. * @param error {@link Throwable} that happened during the span or {@code null} if no exception occurred. * @param context Additional metadata that is passed through the call stack. */ public static void end(int responseCode, Throwable error, Context context) { - TRACERS.forEach(tracer -> tracer.end(responseCode, error, context)); + if (tracer == null) { + return; + } + tracer.end(responseCode, error, context); } /** @@ -84,11 +86,9 @@ public static void end(int responseCode, Throwable error, Context context) { * @return An updated {@link Context} object. */ public static Context setSpanName(String spanName, Context context) { - Context local = context; - for (Tracer tracer : TRACERS) { - local = tracer.setSpanName(spanName, context); + if (tracer == null) { + return context; } - - return local; + return tracer.setSpanName(spanName, context); } }