From 1eac8250e24c6f1d260bbaf5c8371ea8d8f4c0aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?TATSUNO=20=E2=80=9CTaz=E2=80=9D=20Yasuhiro?= Date: Thu, 4 Jun 2026 14:35:13 +0900 Subject: [PATCH] fix(firestore): support opentelemetry-instrumentation-grpc 2.25.0+ --- java-firestore/google-cloud-firestore/pom.xml | 30 ++++++++++++++++ .../firestore/telemetry/EnabledTraceUtil.java | 36 ++++++++++++++++++- .../telemetry/EnabledTraceUtilTest.java | 24 +++++++++++++ 3 files changed, 89 insertions(+), 1 deletion(-) diff --git a/java-firestore/google-cloud-firestore/pom.xml b/java-firestore/google-cloud-firestore/pom.xml index a96df01e18a3..5c03162d83c0 100644 --- a/java-firestore/google-cloud-firestore/pom.xml +++ b/java-firestore/google-cloud-firestore/pom.xml @@ -363,6 +363,36 @@ + + + otel-grpc-old + + + + io.opentelemetry.instrumentation + opentelemetry-grpc-1.6 + 2.1.0-alpha + + + + + + otel-grpc-new + + + + io.opentelemetry.instrumentation + opentelemetry-grpc-1.6 + 2.25.0-alpha + + + + java17-test diff --git a/java-firestore/google-cloud-firestore/src/main/java/com/google/cloud/firestore/telemetry/EnabledTraceUtil.java b/java-firestore/google-cloud-firestore/src/main/java/com/google/cloud/firestore/telemetry/EnabledTraceUtil.java index 863012b4e5cc..0919c65f9bb2 100644 --- a/java-firestore/google-cloud-firestore/src/main/java/com/google/cloud/firestore/telemetry/EnabledTraceUtil.java +++ b/java-firestore/google-cloud-firestore/src/main/java/com/google/cloud/firestore/telemetry/EnabledTraceUtil.java @@ -23,6 +23,7 @@ import com.google.api.core.InternalApi; import com.google.cloud.firestore.FirestoreOptions; import com.google.common.base.Throwables; +import io.grpc.ClientInterceptor; import io.grpc.ManagedChannelBuilder; import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.OpenTelemetry; @@ -34,6 +35,8 @@ import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.api.trace.TracerProvider; import io.opentelemetry.instrumentation.grpc.v1_6.GrpcTelemetry; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.Map; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -73,13 +76,44 @@ public OpenTelemetry getOpenTelemetry() { return openTelemetry; } + // See https://github.com/googleapis/google-cloud-java/issues/13095 + private static final Method GRPC_CLIENT_INTERCEPTOR_METHOD = resolveGrpcClientInterceptorMethod(); + + private static Method resolveGrpcClientInterceptorMethod() { + try { + return GrpcTelemetry.class.getMethod("createClientInterceptor"); + } catch (NoSuchMethodException ignored) { + // Fall back to the pre-2.25.0 method name. + } + try { + return GrpcTelemetry.class.getMethod("newClientInterceptor"); + } catch (NoSuchMethodException e) { + throw new IllegalStateException( + "Neither GrpcTelemetry#createClientInterceptor nor GrpcTelemetry#newClientInterceptor" + + " is available on the classpath. Incompatible" + + " opentelemetry-instrumentation-grpc-1.6 version.", + e); + } + } + + private static ClientInterceptor newGrpcClientInterceptor(GrpcTelemetry grpcTelemetry) { + try { + return (ClientInterceptor) GRPC_CLIENT_INTERCEPTOR_METHOD.invoke(grpcTelemetry); + } catch (IllegalAccessException e) { + throw new IllegalStateException(e); + } catch (InvocationTargetException e) { + Throwables.throwIfUnchecked(e.getCause()); + throw new RuntimeException(e.getCause()); + } + } + // The gRPC channel configurator that intercepts gRPC calls for tracing purposes. public class OpenTelemetryGrpcChannelConfigurator implements ApiFunction { @Override public ManagedChannelBuilder apply(ManagedChannelBuilder managedChannelBuilder) { GrpcTelemetry grpcTelemetry = GrpcTelemetry.create(getOpenTelemetry()); - return managedChannelBuilder.intercept(grpcTelemetry.newClientInterceptor()); + return managedChannelBuilder.intercept(newGrpcClientInterceptor(grpcTelemetry)); } } diff --git a/java-firestore/google-cloud-firestore/src/test/java/com/google/cloud/firestore/telemetry/EnabledTraceUtilTest.java b/java-firestore/google-cloud-firestore/src/test/java/com/google/cloud/firestore/telemetry/EnabledTraceUtilTest.java index d3fb7e216787..61f347228f6c 100644 --- a/java-firestore/google-cloud-firestore/src/test/java/com/google/cloud/firestore/telemetry/EnabledTraceUtilTest.java +++ b/java-firestore/google-cloud-firestore/src/test/java/com/google/cloud/firestore/telemetry/EnabledTraceUtilTest.java @@ -17,8 +17,10 @@ import static com.google.common.truth.Truth.assertThat; +import com.google.api.core.ApiFunction; import com.google.cloud.firestore.FirestoreOpenTelemetryOptions; import com.google.cloud.firestore.FirestoreOptions; +import io.grpc.ManagedChannelBuilder; import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.trace.TracerProvider; import io.opentelemetry.sdk.OpenTelemetrySdk; @@ -111,6 +113,28 @@ public void openTelemetryInstanceRegistersGrpcChannelConfigurator() { assertThat(traceUtil.getChannelConfigurator()).isNotNull(); } + // Exercises the reflection fallback that resolves either + // GrpcTelemetry#createClientInterceptor (>= 2.25.0) or #newClientInterceptor (< 2.25.0). + // See https://github.com/googleapis/google-cloud-java/issues/13095 + @Test + public void channelConfiguratorAppliesInterceptorAcrossOtelGrpcVersions() { + OpenTelemetrySdk myOpenTelemetrySdk = OpenTelemetrySdk.builder().build(); + FirestoreOptions firestoreOptions = + getBaseOptions() + .setOpenTelemetryOptions( + FirestoreOpenTelemetryOptions.newBuilder() + .setOpenTelemetry(myOpenTelemetrySdk) + .build()) + .build(); + EnabledTraceUtil traceUtil = new EnabledTraceUtil(firestoreOptions); + ApiFunction configurator = + traceUtil.getChannelConfigurator(); + assertThat(configurator).isNotNull(); + + ManagedChannelBuilder builder = ManagedChannelBuilder.forAddress("localhost", 9999); + assertThat(configurator.apply(builder)).isNotNull(); + } + @Test public void usesEnabledContext() { assertThat(defaultEnabledTraceUtil().currentContext() instanceof EnabledTraceUtil.Context)