Skip to content

Commit 81011f2

Browse files
committed
fix: preserve channel configurator for grpc-gcp and add opt-out for gcp OTel metrics
1 parent 4092a98 commit 81011f2

File tree

3 files changed

+90
-3
lines changed

3 files changed

+90
-3
lines changed

google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@ public static GcpChannelPoolOptions createDefaultDynamicChannelPoolOptions() {
227227
private final boolean autoThrottleAdministrativeRequests;
228228
private final RetrySettings retryAdministrativeRequestsSettings;
229229
private final boolean trackTransactionStarter;
230+
private final boolean enableGrpcGcpOtelMetrics;
230231
private final BuiltInMetricsProvider builtInMetricsProvider = BuiltInMetricsProvider.INSTANCE;
231232

232233
/**
@@ -895,6 +896,7 @@ protected SpannerOptions(Builder builder) {
895896
autoThrottleAdministrativeRequests = builder.autoThrottleAdministrativeRequests;
896897
retryAdministrativeRequestsSettings = builder.retryAdministrativeRequestsSettings;
897898
trackTransactionStarter = builder.trackTransactionStarter;
899+
enableGrpcGcpOtelMetrics = builder.enableGrpcGcpOtelMetrics;
898900
defaultQueryOptions = builder.defaultQueryOptions;
899901
envQueryOptions = builder.getEnvironmentQueryOptions();
900902
if (envQueryOptions.equals(QueryOptions.getDefaultInstance())) {
@@ -975,6 +977,10 @@ default boolean isEnableGRPCBuiltInMetrics() {
975977
return false;
976978
}
977979

980+
default boolean isEnableGrpcGcpOtelMetrics() {
981+
return true;
982+
}
983+
978984
default boolean isEnableEndToEndTracing() {
979985
return false;
980986
}
@@ -1013,6 +1019,8 @@ private static class SpannerEnvironmentImpl implements SpannerEnvironment {
10131019
private static final String SPANNER_DISABLE_BUILTIN_METRICS = "SPANNER_DISABLE_BUILTIN_METRICS";
10141020
private static final String SPANNER_DISABLE_DIRECT_ACCESS_GRPC_BUILTIN_METRICS =
10151021
"SPANNER_DISABLE_DIRECT_ACCESS_GRPC_BUILTIN_METRICS";
1022+
private static final String SPANNER_DISABLE_GRPC_GCP_OTEL_METRICS =
1023+
"SPANNER_DISABLE_GRPC_GCP_OTEL_METRICS";
10161024
private static final String SPANNER_MONITORING_HOST = "SPANNER_MONITORING_HOST";
10171025

10181026
private SpannerEnvironmentImpl() {}
@@ -1058,6 +1066,11 @@ public boolean isEnableGRPCBuiltInMetrics() {
10581066
System.getenv(SPANNER_DISABLE_DIRECT_ACCESS_GRPC_BUILTIN_METRICS));
10591067
}
10601068

1069+
@Override
1070+
public boolean isEnableGrpcGcpOtelMetrics() {
1071+
return !Boolean.parseBoolean(System.getenv(SPANNER_DISABLE_GRPC_GCP_OTEL_METRICS));
1072+
}
1073+
10611074
@Override
10621075
public boolean isEnableEndToEndTracing() {
10631076
return Boolean.parseBoolean(System.getenv(SPANNER_ENABLE_END_TO_END_TRACING));
@@ -1128,6 +1141,8 @@ public static class Builder
11281141
private boolean autoThrottleAdministrativeRequests = false;
11291142
private boolean trackTransactionStarter = false;
11301143
private Map<DatabaseId, QueryOptions> defaultQueryOptions = new HashMap<>();
1144+
private boolean enableGrpcGcpOtelMetrics =
1145+
SpannerOptions.environment.isEnableGrpcGcpOtelMetrics();
11311146
private CallCredentialsProvider callCredentialsProvider;
11321147
private CloseableExecutorProvider asyncExecutorProvider;
11331148
private String compressorName;
@@ -1231,6 +1246,7 @@ protected Builder() {
12311246
this.autoThrottleAdministrativeRequests = options.autoThrottleAdministrativeRequests;
12321247
this.retryAdministrativeRequestsSettings = options.retryAdministrativeRequestsSettings;
12331248
this.trackTransactionStarter = options.trackTransactionStarter;
1249+
this.enableGrpcGcpOtelMetrics = options.enableGrpcGcpOtelMetrics;
12341250
this.defaultQueryOptions = options.defaultQueryOptions;
12351251
this.callCredentialsProvider = options.callCredentialsProvider;
12361252
this.asyncExecutorProvider = options.asyncExecutorProvider;
@@ -1750,6 +1766,17 @@ public Builder disableDynamicChannelPool() {
17501766
return this;
17511767
}
17521768

1769+
/**
1770+
* Sets whether to enable or disable grpc-gcp OpenTelemetry metrics injection. When disabled,
1771+
* Spanner will not automatically inject an OpenTelemetry {@link
1772+
* io.opentelemetry.api.metrics.Meter} into grpc-gcp. If a Meter or MetricRegistry is explicitly
1773+
* provided via {@link GcpManagedChannelOptions}, those settings will still be honored.
1774+
*/
1775+
public Builder setGrpcGcpOtelMetricsEnabled(boolean enableGrpcGcpOtelMetrics) {
1776+
this.enableGrpcGcpOtelMetrics = enableGrpcGcpOtelMetrics;
1777+
return this;
1778+
}
1779+
17531780
/**
17541781
* Sets the channel pool options for dynamic channel pooling. Use this to configure the dynamic
17551782
* channel pool behavior when {@link #enableDynamicChannelPool()} is enabled.
@@ -2211,6 +2238,10 @@ public boolean isGrpcGcpExtensionEnabled() {
22112238
return grpcGcpExtensionEnabled;
22122239
}
22132240

2241+
public boolean isGrpcGcpOtelMetricsEnabled() {
2242+
return enableGrpcGcpOtelMetrics;
2243+
}
2244+
22142245
public GcpManagedChannelOptions getGrpcGcpOptions() {
22152246
return grpcGcpOptions;
22162247
}

google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -622,7 +622,7 @@ private static GcpManagedChannelOptions grpcGcpOptionsWithMetricsAndDcp(SpannerO
622622
metricsOptionsBuilder.withNamePrefix("cloud.google.com/java/spanner/gcp-channel-pool/");
623623
}
624624
// Pass OpenTelemetry meter to grpc-gcp for channel pool metrics
625-
if (metricsOptions.getOpenTelemetryMeter() == null) {
625+
if (metricsOptions.getOpenTelemetryMeter() == null && options.isGrpcGcpOtelMetricsEnabled()) {
626626
metricsOptionsBuilder.withOpenTelemetryMeter(
627627
options.getOpenTelemetry().getMeter("com.google.cloud.spanner"));
628628
}
@@ -655,8 +655,10 @@ private static void maybeEnableGrpcGcpExtension(
655655

656656
ApiFunction<ManagedChannelBuilder, ManagedChannelBuilder> apiFunction =
657657
channelBuilder -> {
658-
if (options.getChannelConfigurator() != null) {
659-
channelBuilder = options.getChannelConfigurator().apply(channelBuilder);
658+
ApiFunction<ManagedChannelBuilder, ManagedChannelBuilder> baseConfigurator =
659+
defaultChannelProviderBuilder.getChannelConfigurator();
660+
if (baseConfigurator != null) {
661+
channelBuilder = baseConfigurator.apply(channelBuilder);
660662
}
661663
return GcpManagedChannelBuilder.forDelegateBuilder(channelBuilder)
662664
.withApiConfigJsonString(jsonApiConfig)

google-cloud-spanner/src/test/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpcTest.java

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,11 @@
2727
import static org.junit.Assert.assertTrue;
2828
import static org.junit.Assume.assumeTrue;
2929

30+
import com.google.api.core.ApiFunction;
3031
import com.google.api.gax.core.GaxProperties;
3132
import com.google.api.gax.grpc.GrpcCallContext;
3233
import com.google.api.gax.grpc.GrpcTransportChannel;
34+
import com.google.api.gax.grpc.InstantiatingGrpcChannelProvider;
3335
import com.google.api.gax.rpc.ApiCallContext;
3436
import com.google.api.gax.rpc.ApiClientHeaderProvider;
3537
import com.google.api.gax.rpc.HeaderProvider;
@@ -38,6 +40,8 @@
3840
import com.google.auth.oauth2.AccessToken;
3941
import com.google.auth.oauth2.OAuth2Credentials;
4042
import com.google.cloud.ServiceOptions;
43+
import com.google.cloud.grpc.GcpManagedChannelOptions;
44+
import com.google.cloud.grpc.GcpManagedChannelOptions.GcpMetricsOptions;
4145
import com.google.cloud.spanner.DatabaseClient;
4246
import com.google.cloud.spanner.DatabaseId;
4347
import com.google.cloud.spanner.Dialect;
@@ -80,6 +84,7 @@
8084
import io.grpc.ServerInterceptor;
8185
import io.grpc.Status;
8286
import io.grpc.auth.MoreCallCredentials;
87+
import io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder;
8388
import io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder;
8489
import io.grpc.protobuf.lite.ProtoLiteUtils;
8590
import io.opentelemetry.api.OpenTelemetry;
@@ -963,6 +968,55 @@ public void testLocationApiDoesNotOverrideExplicitChannelProvider() throws Excep
963968
}
964969
}
965970

971+
@Test
972+
public void testGrpcGcpExtensionPreservesChannelConfigurator() throws Exception {
973+
InstantiatingGrpcChannelProvider.Builder channelProviderBuilder =
974+
InstantiatingGrpcChannelProvider.newBuilder();
975+
AtomicBoolean baseConfiguratorCalled = new AtomicBoolean(false);
976+
channelProviderBuilder.setChannelConfigurator(
977+
builder -> {
978+
baseConfiguratorCalled.set(true);
979+
return builder;
980+
});
981+
982+
SpannerOptions options =
983+
SpannerOptions.newBuilder().setProjectId("[PROJECT]").enableGrpcGcpExtension().build();
984+
985+
java.lang.reflect.Method method =
986+
GapicSpannerRpc.class.getDeclaredMethod(
987+
"maybeEnableGrpcGcpExtension",
988+
InstantiatingGrpcChannelProvider.Builder.class,
989+
SpannerOptions.class);
990+
method.setAccessible(true);
991+
method.invoke(null, channelProviderBuilder, options);
992+
993+
ApiFunction<ManagedChannelBuilder, ManagedChannelBuilder> chainedConfigurator =
994+
channelProviderBuilder.getChannelConfigurator();
995+
chainedConfigurator.apply(NettyChannelBuilder.forAddress("localhost", 1));
996+
997+
assertTrue(baseConfiguratorCalled.get());
998+
}
999+
1000+
@Test
1001+
public void testGrpcGcpOtelMetricsDisabledSkipsMeterInjection() throws Exception {
1002+
SpannerOptions options =
1003+
SpannerOptions.newBuilder()
1004+
.setProjectId("[PROJECT]")
1005+
.setGrpcGcpOtelMetricsEnabled(false)
1006+
.build();
1007+
1008+
java.lang.reflect.Method method =
1009+
GapicSpannerRpc.class.getDeclaredMethod(
1010+
"grpcGcpOptionsWithMetricsAndDcp", SpannerOptions.class);
1011+
method.setAccessible(true);
1012+
GcpManagedChannelOptions grpcGcpOptions =
1013+
(GcpManagedChannelOptions) method.invoke(null, options);
1014+
GcpMetricsOptions metricsOptions = grpcGcpOptions.getMetricsOptions();
1015+
1016+
assertNotNull(metricsOptions);
1017+
assertNull(metricsOptions.getOpenTelemetryMeter());
1018+
}
1019+
9661020
private static final class RecordingTransportChannelProvider implements TransportChannelProvider {
9671021
private final String host;
9681022
private final int port;

0 commit comments

Comments
 (0)