Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,16 @@ final class BuiltInMetricsProvider {
private BuiltInMetricsProvider() {}

OpenTelemetry getOrCreateOpenTelemetry(
String projectId, @Nullable Credentials credentials, @Nullable String monitoringHost) {
String projectId,
@Nullable Credentials credentials,
@Nullable String monitoringHost,
String universeDomain) {
try {
if (this.openTelemetry == null) {
SdkMeterProviderBuilder sdkMeterProviderBuilder = SdkMeterProvider.builder();
BuiltInMetricsView.registerBuiltinMetrics(
SpannerCloudMonitoringExporter.create(projectId, credentials, monitoringHost),
SpannerCloudMonitoringExporter.create(
projectId, credentials, monitoringHost, universeDomain),
sdkMeterProviderBuilder);
sdkMeterProviderBuilder.setResource(Resource.create(createResourceAttributes(projectId)));
SdkMeterProvider sdkMeterProvider = sdkMeterProviderBuilder.build();
Expand All @@ -95,10 +99,13 @@ void enableGrpcMetrics(
InstantiatingGrpcChannelProvider.Builder channelProviderBuilder,
String projectId,
@Nullable Credentials credentials,
@Nullable String monitoringHost) {
@Nullable String monitoringHost,
String universeDomain) {
GrpcOpenTelemetry grpcOpenTelemetry =
GrpcOpenTelemetry.newBuilder()
.sdk(this.getOrCreateOpenTelemetry(projectId, credentials, monitoringHost))
.sdk(
this.getOrCreateOpenTelemetry(
projectId, credentials, monitoringHost, universeDomain))
.enableMetrics(BuiltInMetricsConstant.GRPC_METRICS_TO_ENABLE)
// Disable gRPCs default metrics as they are not needed for Spanner.
.disableMetrics(BuiltInMetricsConstant.GRPC_METRICS_ENABLED_BY_DEFAULT)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
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.Strings;
import com.google.common.collect.Iterables;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.monitoring.v3.CreateTimeSeriesRequest;
Expand Down Expand Up @@ -71,7 +72,10 @@ class SpannerCloudMonitoringExporter implements MetricExporter {
private final String spannerProjectId;

static SpannerCloudMonitoringExporter create(
String projectId, @Nullable Credentials credentials, @Nullable String monitoringHost)
String projectId,
@Nullable Credentials credentials,
@Nullable String monitoringHost,
String universeDomain)
throws IOException {
MetricServiceSettings.Builder settingsBuilder = MetricServiceSettings.newBuilder();
CredentialsProvider credentialsProvider;
Expand All @@ -84,6 +88,9 @@ static SpannerCloudMonitoringExporter create(
if (monitoringHost != null) {
settingsBuilder.setEndpoint(monitoringHost);
}
Comment on lines 88 to 90
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If monitoring host is marked as deprecated, we could remove this and have an alternate option for setting a system property to set monitoring host for testing.

Copy link
Collaborator Author

@sakthivelmanii sakthivelmanii Sep 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Deprecated annotation means it will not remove the functionality. That's why I intend to keep this. Will remove it as part of removal.

if (!Strings.isNullOrEmpty(universeDomain)) {
settingsBuilder.setUniverseDomain(universeDomain);
}

Duration timeout = Duration.ofMinutes(1);
// TODO: createServiceTimeSeries needs special handling if the request failed. Leaving
Expand All @@ -110,6 +117,11 @@ public CompletableResultCode export(@Nonnull Collection<MetricData> collection)
return exportSpannerClientMetrics(collection);
}

@VisibleForTesting
MetricServiceClient getMetricServiceClient() {
return client;
}

/** Export client built in metrics */
private CompletableResultCode exportSpannerClientMetrics(Collection<MetricData> collection) {
// Filter spanner metrics. Only include metrics that contain a valid project.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@ public class SpannerOptions extends ServiceOptions<Spanner, SpannerOptions> {
private static final String PG_ADAPTER_CLIENT_LIB_TOKEN = "pg-adapter";

private static final String API_SHORT_NAME = "Spanner";
private static final String DEFAULT_HOST = "https://spanner.googleapis.com";
private static final String SPANNER_SERVICE_NAME = "spanner";
private static final String GOOGLE_DEFAULT_UNIVERSE = "googleapis.com";
private static final String EXPERIMENTAL_HOST_PROJECT_ID = "default";

private static final ImmutableSet<String> SCOPES =
Expand Down Expand Up @@ -780,9 +781,19 @@ protected SpannerOptions(Builder builder) {
databaseRole = builder.databaseRole;
sessionLabels = builder.sessionLabels;
try {
spannerStubSettings = builder.spannerStubSettingsBuilder.build();
instanceAdminStubSettings = builder.instanceAdminStubSettingsBuilder.build();
databaseAdminStubSettings = builder.databaseAdminStubSettingsBuilder.build();
String resolvedUniversalDomain = getResolvedUniverseDomain();
spannerStubSettings =
builder.spannerStubSettingsBuilder.setUniverseDomain(resolvedUniversalDomain).build();
instanceAdminStubSettings =
builder
.instanceAdminStubSettingsBuilder
.setUniverseDomain(resolvedUniversalDomain)
.build();
databaseAdminStubSettings =
builder
.databaseAdminStubSettingsBuilder
.setUniverseDomain(resolvedUniversalDomain)
.build();
} catch (IOException e) {
throw SpannerExceptionFactory.newSpannerException(e);
}
Expand Down Expand Up @@ -824,6 +835,11 @@ protected SpannerOptions(Builder builder) {
defaultTransactionOptions = builder.defaultTransactionOptions;
}

private String getResolvedUniverseDomain() {
String universeDomain = getUniverseDomain();
return Strings.isNullOrEmpty(universeDomain) ? GOOGLE_DEFAULT_UNIVERSE : universeDomain;
}

/**
* The environment to read configuration values from. The default implementation uses environment
* variables.
Expand Down Expand Up @@ -871,6 +887,10 @@ default boolean isEnableEndToEndTracing() {
return false;
}

@Deprecated
@ObsoleteApi(
"This will be removed in an upcoming version without a major version bump. You should use"
+ " universalDomain to configure the built-in metrics endpoint for a partner universe.")
default String getMonitoringHost() {
return null;
}
Expand Down Expand Up @@ -1665,6 +1685,10 @@ public Builder setBuiltInMetricsEnabled(boolean enableBuiltInMetrics) {
}

/** Sets the monitoring host to be used for Built-in client side metrics */
@Deprecated
@ObsoleteApi(
"This will be removed in an upcoming version without a major version bump. You should use"
+ " universalDomain to configure the built-in metrics endpoint for a partner universe.")
public Builder setMonitoringHost(String monitoringHost) {
this.monitoringHost = monitoringHost;
return this;
Expand Down Expand Up @@ -2035,7 +2059,11 @@ public ApiTracerFactory getApiTracerFactory() {
public void enablegRPCMetrics(InstantiatingGrpcChannelProvider.Builder channelProviderBuilder) {
if (SpannerOptions.environment.isEnableGRPCBuiltInMetrics()) {
this.builtInMetricsProvider.enableGrpcMetrics(
channelProviderBuilder, this.getProjectId(), getCredentials(), this.monitoringHost);
channelProviderBuilder,
this.getProjectId(),
getCredentials(),
this.monitoringHost,
getUniverseDomain());
}
}

Expand Down Expand Up @@ -2081,7 +2109,7 @@ private ApiTracerFactory getDefaultApiTracerFactory() {
private ApiTracerFactory createMetricsApiTracerFactory() {
OpenTelemetry openTelemetry =
this.builtInMetricsProvider.getOrCreateOpenTelemetry(
this.getProjectId(), getCredentials(), this.monitoringHost);
this.getProjectId(), getCredentials(), this.monitoringHost, getUniverseDomain());

return openTelemetry != null
? new BuiltInMetricsTracerFactory(
Expand Down Expand Up @@ -2181,7 +2209,11 @@ public static GrpcTransportOptions getDefaultGrpcTransportOptions() {

@Override
protected String getDefaultHost() {
return DEFAULT_HOST;
String universeDomain = getUniverseDomain();
if (Strings.isNullOrEmpty(universeDomain)) {
universeDomain = GOOGLE_DEFAULT_UNIVERSE;
}
return String.format("https://%s.%s", SPANNER_SERVICE_NAME, universeDomain);
}

private static class SpannerDefaults implements ServiceDefaults<Spanner, SpannerOptions> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import static com.google.cloud.spanner.connection.ConnectionProperties.TRACING_PREFIX;
import static com.google.cloud.spanner.connection.ConnectionProperties.TRACK_CONNECTION_LEAKS;
import static com.google.cloud.spanner.connection.ConnectionProperties.TRACK_SESSION_LEAKS;
import static com.google.cloud.spanner.connection.ConnectionProperties.UNIVERSE_DOMAIN;
import static com.google.cloud.spanner.connection.ConnectionProperties.USER_AGENT;
import static com.google.cloud.spanner.connection.ConnectionProperties.USE_AUTO_SAVEPOINTS_FOR_EMULATOR;
import static com.google.cloud.spanner.connection.ConnectionProperties.USE_PLAIN_TEXT;
Expand Down Expand Up @@ -76,6 +77,7 @@
import com.google.cloud.spanner.SpannerOptions;
import com.google.cloud.spanner.connection.StatementExecutor.StatementExecutorType;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.MoreObjects;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.base.Suppliers;
Expand Down Expand Up @@ -769,16 +771,14 @@ static String determineHost(
boolean autoConfigEmulator,
boolean usePlainText,
Map<String, String> environment) {
String host;
String host = null;
if (Objects.equals(endpoint, DEFAULT_ENDPOINT) && matcher.group(Builder.HOST_GROUP) == null) {
if (autoConfigEmulator) {
if (Strings.isNullOrEmpty(environment.get(SPANNER_EMULATOR_HOST_ENV_VAR))) {
return DEFAULT_EMULATOR_HOST;
} else {
return PLAIN_TEXT_PROTOCOL + "//" + environment.get(SPANNER_EMULATOR_HOST_ENV_VAR);
}
} else {
return DEFAULT_HOST;
}
} else if (!Objects.equals(endpoint, DEFAULT_ENDPOINT)) {
// Add '//' at the start of the endpoint to conform to the standard URL specification.
Expand All @@ -792,6 +792,9 @@ static String determineHost(
host = String.format("%s:15000", host);
}
}
if (host == null) {
return null;
}
if (usePlainText) {
return PLAIN_TEXT_PROTOCOL + host;
}
Expand Down Expand Up @@ -968,7 +971,7 @@ public TransportChannelProvider getChannelProvider() {
return null;
}
try {
URL url = new URL(host);
URL url = new URL(MoreObjects.firstNonNull(host, DEFAULT_HOST));
ExternalChannelProvider provider =
ExternalChannelProvider.class.cast(Class.forName(channelProvider).newInstance());
return provider.getChannelProvider(url.getHost(), url.getPort());
Expand Down Expand Up @@ -1086,6 +1089,10 @@ Boolean isEnableDirectAccess() {
return getInitialConnectionPropertyValue(ENABLE_DIRECT_ACCESS);
}

String getUniverseDomain() {
return getInitialConnectionPropertyValue(UNIVERSE_DOMAIN);
}

String getClientCertificate() {
return getInitialConnectionPropertyValue(CLIENT_CERTIFICATE);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,14 @@ public class ConnectionProperties {
BOOLEANS,
BooleanConverter.INSTANCE,
Context.STARTUP);
static final ConnectionProperty<String> UNIVERSE_DOMAIN =
create(
"universeDomain",
"Configure the connection to try to connect to Spanner using "
+ "a different partner Google Universe than GDU (googleapis.com).",
"googleapis.com",
StringValueConverter.INSTANCE,
Context.STARTUP);
static final ConnectionProperty<Boolean> USE_AUTO_SAVEPOINTS_FOR_EMULATOR =
create(
"useAutoSavepointsForEmulator",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ static class SpannerPoolKey {
private final String clientCertificateKey;
private final boolean isExperimentalHost;
private final Boolean enableDirectAccess;
private final String universeDomain;

@VisibleForTesting
static SpannerPoolKey of(ConnectionOptions options) {
Expand Down Expand Up @@ -200,6 +201,7 @@ private SpannerPoolKey(ConnectionOptions options) throws IOException {
this.clientCertificateKey = options.getClientCertificateKey();
this.isExperimentalHost = options.isExperimentalHost();
this.enableDirectAccess = options.isEnableDirectAccess();
this.universeDomain = options.getUniverseDomain();
}

@Override
Expand All @@ -226,7 +228,8 @@ public boolean equals(Object o) {
&& Objects.equals(this.clientCertificate, other.clientCertificate)
&& Objects.equals(this.clientCertificateKey, other.clientCertificateKey)
&& Objects.equals(this.isExperimentalHost, other.isExperimentalHost)
&& Objects.equals(this.enableDirectAccess, other.enableDirectAccess);
&& Objects.equals(this.enableDirectAccess, other.enableDirectAccess)
&& Objects.equals(this.universeDomain, other.universeDomain);
}

@Override
Expand All @@ -249,7 +252,8 @@ public int hashCode() {
this.clientCertificate,
this.clientCertificateKey,
this.isExperimentalHost,
this.enableDirectAccess);
this.enableDirectAccess,
this.universeDomain);
}
}

Expand Down Expand Up @@ -419,6 +423,9 @@ Spanner createSpanner(SpannerPoolKey key, ConnectionOptions options) {
if (key.enableDirectAccess != null) {
builder.setEnableDirectAccess(key.enableDirectAccess);
}
if (key.universeDomain != null) {
builder.setUniverseDomain(key.universeDomain);
}
if (options.getConfigurator() != null) {
options.getConfigurator().configure(builder);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import static com.google.cloud.spanner.BuiltInMetricsConstant.OPERATION_LATENCIES_NAME;
import static com.google.cloud.spanner.BuiltInMetricsConstant.PROJECT_ID_KEY;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
Expand All @@ -39,6 +40,7 @@
import com.google.api.core.ApiFutures;
import com.google.api.gax.rpc.UnaryCallable;
import com.google.cloud.monitoring.v3.MetricServiceClient;
import com.google.cloud.monitoring.v3.MetricServiceSettings;
import com.google.cloud.monitoring.v3.stub.MetricServiceStub;
import com.google.common.collect.ImmutableList;
import com.google.monitoring.v3.CreateTimeSeriesRequest;
Expand Down Expand Up @@ -454,11 +456,30 @@ public void testExportingHistogramDataWithExemplars() {
@Test
public void getAggregationTemporality() throws IOException {
SpannerCloudMonitoringExporter actualExporter =
SpannerCloudMonitoringExporter.create(projectId, null, null);
SpannerCloudMonitoringExporter.create(projectId, null, null, null);
assertThat(actualExporter.getAggregationTemporality(InstrumentType.COUNTER))
.isEqualTo(AggregationTemporality.CUMULATIVE);
}

@Test
public void testUniverseDomain() throws IOException {
SpannerCloudMonitoringExporter actualExporter =
SpannerCloudMonitoringExporter.create(projectId, null, null, "abc.goog");
MetricServiceSettings metricServiceSettings =
actualExporter.getMetricServiceClient().getSettings();

assertEquals("abc.goog", metricServiceSettings.getUniverseDomain());
assertEquals("monitoring.abc.goog:443", metricServiceSettings.getEndpoint());

actualExporter =
SpannerCloudMonitoringExporter.create(
projectId, null, "monitoringa.abc.goog:443", "abc.goog");
metricServiceSettings = actualExporter.getMetricServiceClient().getSettings();

assertEquals("abc.goog", metricServiceSettings.getUniverseDomain());
assertEquals("monitoringa.abc.goog:443", metricServiceSettings.getEndpoint());
}

private static class FakeMetricServiceClient extends MetricServiceClient {

protected FakeMetricServiceClient(MetricServiceStub stub) {
Expand Down
Loading
Loading