diff --git a/google-cloud-spanner/clirr-ignored-differences.xml b/google-cloud-spanner/clirr-ignored-differences.xml index bae308f2b5..5b84cb4ebc 100644 --- a/google-cloud-spanner/clirr-ignored-differences.xml +++ b/google-cloud-spanner/clirr-ignored-differences.xml @@ -709,6 +709,13 @@ boolean isEnableBuiltInMetrics() + + + 7012 + com/google/cloud/spanner/SpannerOptions$SpannerEnvironment + java.lang.String getMonitoringHost() + + 7012 diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInOpenTelemetryMetricsProvider.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInOpenTelemetryMetricsProvider.java index 8f4ada6ae5..4aeb98987d 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInOpenTelemetryMetricsProvider.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInOpenTelemetryMetricsProvider.java @@ -59,12 +59,14 @@ final class BuiltInOpenTelemetryMetricsProvider { private BuiltInOpenTelemetryMetricsProvider() {} - OpenTelemetry getOrCreateOpenTelemetry(String projectId, @Nullable Credentials credentials) { + OpenTelemetry getOrCreateOpenTelemetry( + String projectId, @Nullable Credentials credentials, @Nullable String monitoringHost) { try { if (this.openTelemetry == null) { SdkMeterProviderBuilder sdkMeterProviderBuilder = SdkMeterProvider.builder(); BuiltInOpenTelemetryMetricsView.registerBuiltinMetrics( - SpannerCloudMonitoringExporter.create(projectId, credentials), sdkMeterProviderBuilder); + SpannerCloudMonitoringExporter.create(projectId, credentials, monitoringHost), + sdkMeterProviderBuilder); SdkMeterProvider sdkMeterProvider = sdkMeterProviderBuilder.build(); this.openTelemetry = OpenTelemetrySdk.builder().setMeterProvider(sdkMeterProvider).build(); Runtime.getRuntime().addShutdownHook(new Thread(sdkMeterProvider::close)); diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerCloudMonitoringExporter.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerCloudMonitoringExporter.java index 3577c9f7b4..fc101fbcfc 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerCloudMonitoringExporter.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerCloudMonitoringExporter.java @@ -29,7 +29,6 @@ import com.google.cloud.monitoring.v3.MetricServiceClient; import com.google.cloud.monitoring.v3.MetricServiceSettings; import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.MoreObjects; import com.google.common.collect.Iterables; import com.google.common.util.concurrent.MoreExecutors; import com.google.monitoring.v3.CreateTimeSeriesRequest; @@ -63,13 +62,6 @@ class SpannerCloudMonitoringExporter implements MetricExporter { private static final Logger logger = Logger.getLogger(SpannerCloudMonitoringExporter.class.getName()); - // This system property can be used to override the monitoring endpoint - // to a different environment. It's meant for internal testing only. - private static final String MONITORING_ENDPOINT = - MoreObjects.firstNonNull( - System.getProperty("spanner.test-monitoring-endpoint"), - MetricServiceSettings.getDefaultEndpoint()); - // This the quota limit from Cloud Monitoring. More details in // https://cloud.google.com/monitoring/quotas#custom_metrics_quotas. private static final int EXPORT_BATCH_SIZE_LIMIT = 200; @@ -78,7 +70,8 @@ class SpannerCloudMonitoringExporter implements MetricExporter { private final MetricServiceClient client; private final String spannerProjectId; - static SpannerCloudMonitoringExporter create(String projectId, @Nullable Credentials credentials) + static SpannerCloudMonitoringExporter create( + String projectId, @Nullable Credentials credentials, @Nullable String monitoringHost) throws IOException { MetricServiceSettings.Builder settingsBuilder = MetricServiceSettings.newBuilder(); CredentialsProvider credentialsProvider; @@ -88,7 +81,9 @@ static SpannerCloudMonitoringExporter create(String projectId, @Nullable Credent credentialsProvider = FixedCredentialsProvider.create(credentials); } settingsBuilder.setCredentialsProvider(credentialsProvider); - settingsBuilder.setEndpoint(MONITORING_ENDPOINT); + if (monitoringHost != null) { + settingsBuilder.setEndpoint(monitoringHost); + } org.threeten.bp.Duration timeout = Duration.ofMinutes(1); // TODO: createServiceTimeSeries needs special handling if the request failed. Leaving diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java index af54515e7c..d85b39c125 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java @@ -164,6 +164,7 @@ public class SpannerOptions extends ServiceOptions { private final boolean enableBuiltInMetrics; private final boolean enableExtendedTracing; private final boolean enableEndToEndTracing; + private final String monitoringHost; enum TracingFramework { OPEN_CENSUS, @@ -672,6 +673,7 @@ protected SpannerOptions(Builder builder) { enableExtendedTracing = builder.enableExtendedTracing; enableBuiltInMetrics = builder.enableBuiltInMetrics; enableEndToEndTracing = builder.enableEndToEndTracing; + monitoringHost = builder.monitoringHost; } /** @@ -712,6 +714,10 @@ default boolean isEnableBuiltInMetrics() { default boolean isEnableEndToEndTracing() { return false; } + + default String getMonitoringHost() { + return null; + } } /** @@ -728,6 +734,7 @@ private static class SpannerEnvironmentImpl implements SpannerEnvironment { private static final String SPANNER_ENABLE_END_TO_END_TRACING = "SPANNER_ENABLE_END_TO_END_TRACING"; private static final String SPANNER_DISABLE_BUILTIN_METRICS = "SPANNER_DISABLE_BUILTIN_METRICS"; + private static final String SPANNER_MONITORING_HOST = "SPANNER_MONITORING_HOST"; private SpannerEnvironmentImpl() {} @@ -763,6 +770,11 @@ public boolean isEnableBuiltInMetrics() { public boolean isEnableEndToEndTracing() { return Boolean.parseBoolean(System.getenv(SPANNER_ENABLE_END_TO_END_TRACING)); } + + @Override + public String getMonitoringHost() { + return System.getenv(SPANNER_MONITORING_HOST); + } } /** Builder for {@link SpannerOptions} instances. */ @@ -828,6 +840,7 @@ public static class Builder private boolean enableExtendedTracing = SpannerOptions.environment.isEnableExtendedTracing(); private boolean enableEndToEndTracing = SpannerOptions.environment.isEnableEndToEndTracing(); private boolean enableBuiltInMetrics = SpannerOptions.environment.isEnableBuiltInMetrics(); + private String monitoringHost = SpannerOptions.environment.getMonitoringHost(); private static String createCustomClientLibToken(String token) { return token + " " + ServiceOptions.getGoogApiClientLibName(); @@ -895,6 +908,7 @@ protected Builder() { this.enableExtendedTracing = options.enableExtendedTracing; this.enableBuiltInMetrics = options.enableBuiltInMetrics; this.enableEndToEndTracing = options.enableEndToEndTracing; + this.monitoringHost = options.monitoringHost; } @Override @@ -1417,6 +1431,12 @@ public Builder setBuiltInMetricsEnabled(boolean enableBuiltInMetrics) { return this; } + /** Sets the monitoring host to be used for Built-in client side metrics */ + public Builder setMonitoringHost(String monitoringHost) { + this.monitoringHost = monitoringHost; + return this; + } + /** * Sets whether to enable extended OpenTelemetry tracing. Enabling this option will add the * following additional attributes to the traces that are generated by the client: @@ -1727,7 +1747,7 @@ private ApiTracerFactory getDefaultApiTracerFactory() { private ApiTracerFactory createMetricsApiTracerFactory() { OpenTelemetry openTelemetry = this.builtInOpenTelemetryMetricsProvider.getOrCreateOpenTelemetry( - this.getProjectId(), getCredentials()); + this.getProjectId(), getCredentials(), this.monitoringHost); return openTelemetry != null ? new MetricsTracerFactory( @@ -1754,6 +1774,11 @@ public boolean isEnableBuiltInMetrics() { return enableBuiltInMetrics; } + /** Returns the override metrics Host. */ + String getMonitoringHost() { + return monitoringHost; + } + @BetaApi public boolean isUseVirtualThreads() { return useVirtualThreads; diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerCloudMonitoringExporterTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerCloudMonitoringExporterTest.java index acb7ae9fa1..ab30de1ade 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerCloudMonitoringExporterTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerCloudMonitoringExporterTest.java @@ -337,7 +337,7 @@ public void testExportingSumDataInBatches() { @Test public void getAggregationTemporality() throws IOException { SpannerCloudMonitoringExporter actualExporter = - SpannerCloudMonitoringExporter.create(projectId, null); + SpannerCloudMonitoringExporter.create(projectId, null, null); assertThat(actualExporter.getAggregationTemporality(InstrumentType.COUNTER)) .isEqualTo(AggregationTemporality.CUMULATIVE); } @@ -348,7 +348,7 @@ public void testSkipExportingDataIfMissingInstanceId() throws IOException { Attributes.builder().putAll(attributes).remove(INSTANCE_ID_KEY).build(); SpannerCloudMonitoringExporter actualExporter = - SpannerCloudMonitoringExporter.create(projectId, null); + SpannerCloudMonitoringExporter.create(projectId, null, null); assertThat(actualExporter.getAggregationTemporality(InstrumentType.COUNTER)) .isEqualTo(AggregationTemporality.CUMULATIVE); ArgumentCaptor argumentCaptor = diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerOptionsTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerOptionsTest.java index e8421cd235..7b891fdb7a 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerOptionsTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerOptionsTest.java @@ -754,6 +754,19 @@ public void testEndToEndTracingEnablement() { .isEndToEndTracingEnabled()); } + @Test + public void testmonitoringHost() { + String metricsEndpoint = "test-endpoint:443"; + assertNull(SpannerOptions.newBuilder().setProjectId("p").build().getMonitoringHost()); + assertThat( + SpannerOptions.newBuilder() + .setProjectId("p") + .setMonitoringHost(metricsEndpoint) + .build() + .getMonitoringHost()) + .isEqualTo(metricsEndpoint); + } + @Test public void testSetDirectedReadOptions() { final DirectedReadOptions directedReadOptions =