Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions .github/workflows/java-firestore-ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ jobs:
runs-on: ubuntu-latest
outputs:
library: ${{ steps.filter.outputs.library }}
otel_grpc: ${{ steps.filter.outputs.otel_grpc }}
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
Expand All @@ -39,6 +40,9 @@ jobs:
filters: |
library:
- 'java-firestore/**'
otel_grpc:
- 'java-firestore/google-cloud-firestore/src/main/java/com/google/cloud/firestore/telemetry/**'
- 'sdk-platform-java/java-shared-dependencies/third-party-dependencies/pom.xml'
units:
needs: filter
if: ${{ needs.filter.outputs.library == 'true' }}
Expand All @@ -60,6 +64,37 @@ jobs:
- run: .kokoro/build.sh
env:
JOB_TYPE: test
otel-grpc-compatibility:
needs: filter
if: ${{ needs.filter.outputs.otel_grpc == 'true' }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# One release on each side of the createClientInterceptor rename.
otel-grpc-version: ['2.1.0-alpha', '2.25.0-alpha']
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
persist-credentials: false
- uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4.8.0
with:
distribution: temurin
java-version: 11
cache: maven
- run: .kokoro/build.sh
env:
JOB_TYPE: install
- run: |
mvn test -B -V -ntp \
-Dclirr.skip \
-Denforcer.skip \
-Dmaven.javadoc.skip \
-Dopentelemetry-grpc-instrumentation.version="${OTEL_GRPC_VERSION}" \
-T 1C
working-directory: java-firestore
env:
OTEL_GRPC_VERSION: ${{ matrix.otel-grpc-version }}
units-java8:
needs: filter
if: ${{ needs.filter.outputs.library == 'true' }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -34,6 +35,9 @@
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.Arrays;
import java.util.Map;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
Expand All @@ -44,6 +48,13 @@
*/
@InternalApi
public class EnabledTraceUtil implements TraceUtil {
// opentelemetry-instrumentation-grpc-1.6 2.25.0-alpha renamed newClientInterceptor() to
// createClientInterceptor(). See https://github.com/googleapis/google-cloud-java/issues/13095
private static final String[] CLIENT_INTERCEPTOR_METHOD_NAMES = {
"createClientInterceptor", "newClientInterceptor"
};
private static final Method CLIENT_INTERCEPTOR_METHOD = resolveClientInterceptorMethod();

private final Tracer tracer;
private final OpenTelemetry openTelemetry;
private final FirestoreOptions firestoreOptions;
Expand Down Expand Up @@ -73,13 +84,40 @@ public OpenTelemetry getOpenTelemetry() {
return openTelemetry;
}

@SuppressWarnings("JavaReflectionMemberAccess")
private static Method resolveClientInterceptorMethod() {
for (String methodName : CLIENT_INTERCEPTOR_METHOD_NAMES) {
try {
return GrpcTelemetry.class.getMethod(methodName);
} catch (NoSuchMethodException ignored) {
// Try the next known name.
}
}
throw new IllegalStateException(
"GrpcTelemetry declares none of "
+ Arrays.toString(CLIENT_INTERCEPTOR_METHOD_NAMES)
+ ". An incompatible opentelemetry-instrumentation-grpc-1.6 version is on the"
+ " classpath.");
}

private static ClientInterceptor createClientInterceptor(GrpcTelemetry grpcTelemetry) {
try {
return (ClientInterceptor) CLIENT_INTERCEPTOR_METHOD.invoke(grpcTelemetry);
} catch (IllegalAccessException e) {
throw new IllegalStateException(e);
} catch (InvocationTargetException e) {
Throwables.throwIfUnchecked(e.getCause());
throw new IllegalStateException(e.getCause());
}
}

// The gRPC channel configurator that intercepts gRPC calls for tracing purposes.
public class OpenTelemetryGrpcChannelConfigurator
implements ApiFunction<ManagedChannelBuilder, ManagedChannelBuilder> {
@Override
public ManagedChannelBuilder apply(ManagedChannelBuilder managedChannelBuilder) {
GrpcTelemetry grpcTelemetry = GrpcTelemetry.create(getOpenTelemetry());
return managedChannelBuilder.intercept(grpcTelemetry.newClientInterceptor());
return managedChannelBuilder.intercept(createClientInterceptor(grpcTelemetry));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -111,6 +113,19 @@ public void openTelemetryInstanceRegistersGrpcChannelConfigurator() {
assertThat(traceUtil.getChannelConfigurator()).isNotNull();
}

// Fails on an opentelemetry-grpc-1.6 version whose interceptor method name EnabledTraceUtil does
// not handle. The version shared-dependencies does not manage is covered by the
// otel-grpc-compatibility job in java-firestore-ci.yaml.
@Test
public void grpcChannelConfiguratorInterceptsWithGrpcTelemetry() {
OpenTelemetrySdk.builder().buildAndRegisterGlobal();
ApiFunction<ManagedChannelBuilder, ManagedChannelBuilder> configurator =
defaultEnabledTraceUtil().getChannelConfigurator();
ManagedChannelBuilder<?> builder = ManagedChannelBuilder.forAddress("localhost", 9999);

assertThat(configurator.apply(builder)).isNotNull();
}

@Test
public void usesEnabledContext() {
assertThat(defaultEnabledTraceUtil().currentContext() instanceof EnabledTraceUtil.Context)
Expand Down
Loading