diff --git a/gax-java/gax/src/main/java/com/google/api/gax/tracing/OpenTelemetryTracingRecorder.java b/gax-java/gax/src/main/java/com/google/api/gax/tracing/OpenTelemetryTracingRecorder.java new file mode 100644 index 0000000000..9d3409c3bc --- /dev/null +++ b/gax-java/gax/src/main/java/com/google/api/gax/tracing/OpenTelemetryTracingRecorder.java @@ -0,0 +1,57 @@ +/* + * Copyright 2026 Google LLC + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.google.api.gax.tracing; + +import com.google.api.core.BetaApi; +import com.google.api.core.InternalApi; +import io.opentelemetry.api.OpenTelemetry; + +/** + * OpenTelemetry implementation of recording traces. This implementation collects the measurements + * related to the lifecyle of an RPC. + */ +@BetaApi +@InternalApi +public class OpenTelemetryTracingRecorder implements TracingRecorder { + private final OpenTelemetry openTelemetry; + private final String serviceName; + + /** + * Creates a new instance of OpenTelemetryTracingRecorder. + * + * @param openTelemetry OpenTelemetry instance + * @param serviceName Service Name + */ + public OpenTelemetryTracingRecorder(OpenTelemetry openTelemetry, String serviceName) { + this.openTelemetry = openTelemetry; + this.serviceName = serviceName; + } +} diff --git a/gax-java/gax/src/main/java/com/google/api/gax/tracing/TracingRecorder.java b/gax-java/gax/src/main/java/com/google/api/gax/tracing/TracingRecorder.java new file mode 100644 index 0000000000..afb7ff6078 --- /dev/null +++ b/gax-java/gax/src/main/java/com/google/api/gax/tracing/TracingRecorder.java @@ -0,0 +1,46 @@ +/* + * Copyright 2026 Google LLC + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.google.api.gax.tracing; + +import com.google.api.core.BetaApi; +import com.google.api.core.InternalApi; + +/** + * Provides an interface for tracing recording. The implementer is expected to use an observability + * framework, e.g. OpenTelemetry. There should be only one instance of TracingRecorder per client, + * all the methods in this class are expected to be called from multiple threads, hence the + * implementation must be thread safe. + */ +@BetaApi +@InternalApi +public interface TracingRecorder { + // Minimal working feature: noop implementation for now. +} diff --git a/gax-java/gax/src/main/java/com/google/api/gax/tracing/TracingTracer.java b/gax-java/gax/src/main/java/com/google/api/gax/tracing/TracingTracer.java new file mode 100644 index 0000000000..c5ea38a9b1 --- /dev/null +++ b/gax-java/gax/src/main/java/com/google/api/gax/tracing/TracingTracer.java @@ -0,0 +1,49 @@ +/* + * Copyright 2026 Google LLC + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.google.api.gax.tracing; + +import com.google.api.core.BetaApi; +import com.google.api.core.InternalApi; + +/** + * This class computes generic traces that can be observed in the lifecycle of an RPC operation. The + * responsibility of recording traces should delegate to {@link TracingRecorder}, hence this class + * should not have any knowledge about the observability framework used for tracing recording. + */ +@BetaApi +@InternalApi +public class TracingTracer extends BaseApiTracer { + private final TracingRecorder tracingRecorder; + + public TracingTracer(TracingRecorder tracingRecorder) { + this.tracingRecorder = tracingRecorder; + } +} diff --git a/gax-java/gax/src/main/java/com/google/api/gax/tracing/TracingTracerFactory.java b/gax-java/gax/src/main/java/com/google/api/gax/tracing/TracingTracerFactory.java new file mode 100644 index 0000000000..750947b67d --- /dev/null +++ b/gax-java/gax/src/main/java/com/google/api/gax/tracing/TracingTracerFactory.java @@ -0,0 +1,75 @@ +/* + * Copyright 2026 Google LLC + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.google.api.gax.tracing; + +import com.google.api.core.BetaApi; +import com.google.api.core.InternalApi; +import com.google.common.collect.ImmutableMap; +import java.util.Map; + +/** + * A {@link ApiTracerFactory} to build instances of {@link TracingTracer}. + * + *

This class wraps the {@link TracingRecorder} and pass it to {@link TracingTracer}. It will be + * used to record traces in {@link TracingTracer}. + * + *

This class is expected to be initialized once during client initialization. + */ +@BetaApi +@InternalApi +public class TracingTracerFactory implements ApiTracerFactory { + protected TracingRecorder tracingRecorder; + + /** Mapping of client attributes that are set for every TracingTracer */ + private final Map attributes; + + /** Creates a TracingTracerFactory with no additional client level attributes. */ + public TracingTracerFactory(TracingRecorder tracingRecorder) { + this(tracingRecorder, ImmutableMap.of()); + } + + /** + * Pass in a Map of client level attributes which will be added to every single TracingTracer + * created from the ApiTracerFactory. + */ + public TracingTracerFactory(TracingRecorder tracingRecorder, Map attributes) { + this.tracingRecorder = tracingRecorder; + this.attributes = ImmutableMap.copyOf(attributes); + } + + @Override + public ApiTracer newTracer(ApiTracer parent, SpanName spanName, OperationType operationType) { + if (!TracingUtils.isTracingEnabled()) { + return BaseApiTracer.getInstance(); + } + return new TracingTracer(tracingRecorder); + } +} diff --git a/gax-java/gax/src/main/java/com/google/api/gax/tracing/TracingUtils.java b/gax-java/gax/src/main/java/com/google/api/gax/tracing/TracingUtils.java new file mode 100644 index 0000000000..161f93f558 --- /dev/null +++ b/gax-java/gax/src/main/java/com/google/api/gax/tracing/TracingUtils.java @@ -0,0 +1,59 @@ +/* + * Copyright 2026 Google LLC + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.google.api.gax.tracing; + +import com.google.api.core.InternalApi; +import com.google.common.annotations.VisibleForTesting; + +/** Internal utility class to manage tracing configuration. */ +@InternalApi +public class TracingUtils { + static final String GOOGLE_CLOUD_ENABLE_TRACING = "GOOGLE_CLOUD_ENABLE_TRACING"; + + private TracingUtils() {} + + /** + * Returns true if tracing is enabled via the GOOGLE_CLOUD_ENABLE_TRACING environment variable or + * system property. + */ + public static boolean isTracingEnabled() { + String enableTracing = System.getProperty(GOOGLE_CLOUD_ENABLE_TRACING); + if (enableTracing == null) { + enableTracing = System.getenv(GOOGLE_CLOUD_ENABLE_TRACING); + } + return isTracingEnabled(enableTracing); + } + + @VisibleForTesting + static boolean isTracingEnabled(String envValue) { + return "true".equalsIgnoreCase(envValue); + } +} diff --git a/gax-java/gax/src/test/java/com/google/api/gax/tracing/TracingTracerFactoryTest.java b/gax-java/gax/src/test/java/com/google/api/gax/tracing/TracingTracerFactoryTest.java new file mode 100644 index 0000000000..9169b14abd --- /dev/null +++ b/gax-java/gax/src/test/java/com/google/api/gax/tracing/TracingTracerFactoryTest.java @@ -0,0 +1,79 @@ +/* + * Copyright 2026 Google LLC + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.google.api.gax.tracing; + +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.mock; + +import com.google.api.gax.tracing.ApiTracerFactory.OperationType; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class TracingTracerFactoryTest { + private TracingRecorder tracingRecorder; + private TracingTracerFactory factory; + private ApiTracer parent; + private SpanName spanName; + + @BeforeEach + void setUp() { + tracingRecorder = mock(TracingRecorder.class); + factory = new TracingTracerFactory(tracingRecorder); + parent = mock(ApiTracer.class); + spanName = mock(SpanName.class); + } + + @AfterEach + void tearDown() { + System.clearProperty("GOOGLE_CLOUD_ENABLE_TRACING"); + } + + @Test + void testNewTracer_enabled() { + System.setProperty("GOOGLE_CLOUD_ENABLE_TRACING", "true"); + ApiTracer tracer = factory.newTracer(parent, spanName, OperationType.Unary); + assertThat(tracer).isInstanceOf(TracingTracer.class); + } + + @Test + void testNewTracer_disabled() { + System.setProperty("GOOGLE_CLOUD_ENABLE_TRACING", "false"); + ApiTracer tracer = factory.newTracer(parent, spanName, OperationType.Unary); + assertThat(tracer).isSameInstanceAs(BaseApiTracer.getInstance()); + } + + @Test + void testNewTracer_defaultDisabled() { + ApiTracer tracer = factory.newTracer(parent, spanName, OperationType.Unary); + assertThat(tracer).isSameInstanceAs(BaseApiTracer.getInstance()); + } +} diff --git a/gax-java/gax/src/test/java/com/google/api/gax/tracing/TracingTracerTest.java b/gax-java/gax/src/test/java/com/google/api/gax/tracing/TracingTracerTest.java new file mode 100644 index 0000000000..f8506d9f06 --- /dev/null +++ b/gax-java/gax/src/test/java/com/google/api/gax/tracing/TracingTracerTest.java @@ -0,0 +1,46 @@ +/* + * Copyright 2026 Google LLC + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.google.api.gax.tracing; + +import static com.google.common.truth.Truth.assertThat; + +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +class TracingTracerTest { + + @Test + void testConstructor() { + TracingRecorder recorder = Mockito.mock(TracingRecorder.class); + TracingTracer tracer = new TracingTracer(recorder); + assertThat(tracer).isNotNull(); + } +} diff --git a/gax-java/gax/src/test/java/com/google/api/gax/tracing/TracingUtilsTest.java b/gax-java/gax/src/test/java/com/google/api/gax/tracing/TracingUtilsTest.java new file mode 100644 index 0000000000..9449fc571f --- /dev/null +++ b/gax-java/gax/src/test/java/com/google/api/gax/tracing/TracingUtilsTest.java @@ -0,0 +1,56 @@ +/* + * Copyright 2026 Google LLC + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.google.api.gax.tracing; + +import static com.google.common.truth.Truth.assertThat; + +import org.junit.jupiter.api.Test; + +class TracingUtilsTest { + + @Test + void testIsTracingEnabled_defaultToFalse() { + assertThat(TracingUtils.isTracingEnabled(null)).isFalse(); + } + + @Test + void testIsTracingEnabled_true() { + assertThat(TracingUtils.isTracingEnabled("true")).isTrue(); + assertThat(TracingUtils.isTracingEnabled("TRUE")).isTrue(); + } + + @Test + void testIsTracingEnabled_false() { + assertThat(TracingUtils.isTracingEnabled("false")).isFalse(); + assertThat(TracingUtils.isTracingEnabled("random")).isFalse(); + assertThat(TracingUtils.isTracingEnabled("")).isFalse(); + } +} diff --git a/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITOtelMetrics.java b/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITOtelMetrics.java index 06f46deee8..8fb7348851 100644 --- a/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITOtelMetrics.java +++ b/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITOtelMetrics.java @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2026 Google LLC * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -30,6 +30,7 @@ package com.google.showcase.v1beta1.it; +import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertThrows; import com.google.api.client.http.javanet.NetHttpTransport; @@ -42,9 +43,17 @@ import com.google.api.gax.rpc.StatusCode.Code; import com.google.api.gax.rpc.UnaryCallable; import com.google.api.gax.rpc.UnavailableException; +import com.google.api.gax.tracing.ApiTracer; +import com.google.api.gax.tracing.ApiTracerFactory; +import com.google.api.gax.tracing.BaseApiTracer; import com.google.api.gax.tracing.MetricsTracer; import com.google.api.gax.tracing.MetricsTracerFactory; import com.google.api.gax.tracing.OpenTelemetryMetricsRecorder; +import com.google.api.gax.tracing.OpenTelemetryTracingRecorder; +import com.google.api.gax.tracing.SpanName; +import com.google.api.gax.tracing.TracingRecorder; +import com.google.api.gax.tracing.TracingTracer; +import com.google.api.gax.tracing.TracingTracerFactory; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; @@ -72,6 +81,7 @@ import io.opentelemetry.sdk.metrics.data.MetricData; import io.opentelemetry.sdk.metrics.data.PointData; import io.opentelemetry.sdk.testing.exporter.InMemoryMetricReader; +import io.opentelemetry.sdk.trace.SdkTracerProvider; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; @@ -146,12 +156,18 @@ private OpenTelemetryMetricsRecorder createOtelMetricsRecorder( InMemoryMetricReader inMemoryMetricReader) { SdkMeterProvider sdkMeterProvider = SdkMeterProvider.builder().registerMetricReader(inMemoryMetricReader).build(); - OpenTelemetry openTelemetry = OpenTelemetrySdk.builder().setMeterProvider(sdkMeterProvider).build(); return new OpenTelemetryMetricsRecorder(openTelemetry, SERVICE_NAME); } + private OpenTelemetryTracingRecorder createOtelTracingRecorder() { + SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder().build(); + OpenTelemetry openTelemetry = + OpenTelemetrySdk.builder().setTracerProvider(sdkTracerProvider).build(); + return new OpenTelemetryTracingRecorder(openTelemetry, SERVICE_NAME); + } + @BeforeEach void setup() throws Exception { inMemoryMetricReader = InMemoryMetricReader.create(); @@ -167,6 +183,8 @@ void setup() throws Exception { @AfterEach void cleanup() throws InterruptedException, IOException { + System.clearProperty("GOOGLE_CLOUD_ENABLE_TRACING"); + inMemoryMetricReader.close(); inMemoryMetricReader.shutdown(); @@ -919,4 +937,28 @@ void grpcOpenTelemetryImplementation_setSampledToLocalTracing_methodFullNameIsRe echoClient.close(); echoClient.awaitTermination(TestClientInitializer.AWAIT_TERMINATION_SECONDS, TimeUnit.SECONDS); } + + @Test + void testTracingFeatureFlag() { + // Test tracing disabled + System.setProperty("GOOGLE_CLOUD_ENABLE_TRACING", "false"); + TracingRecorder recorder = createOtelTracingRecorder(); + TracingTracerFactory factory = new TracingTracerFactory(recorder); + ApiTracer tracer = + factory.newTracer( + BaseApiTracer.getInstance(), + SpanName.of("EchoClient", "Echo"), + ApiTracerFactory.OperationType.Unary); + assertThat(tracer).isNotInstanceOf(TracingTracer.class); + assertThat(tracer).isSameInstanceAs(BaseApiTracer.getInstance()); + + // Test tracing enabled + System.setProperty("GOOGLE_CLOUD_ENABLE_TRACING", "true"); + tracer = + factory.newTracer( + BaseApiTracer.getInstance(), + SpanName.of("EchoClient", "Echo"), + ApiTracerFactory.OperationType.Unary); + assertThat(tracer).isInstanceOf(TracingTracer.class); + } }