Skip to content

Commit 7625cce

Browse files
feat: TPC support (#4055)
* feat: TPC support * Fix test cases * Address comments --------- Co-authored-by: cloud-java-bot <cloud-java-bot@google.com>
1 parent 5e26596 commit 7625cce

File tree

8 files changed

+201
-20
lines changed

8 files changed

+201
-20
lines changed

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

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,12 +68,16 @@ final class BuiltInMetricsProvider {
6868
private BuiltInMetricsProvider() {}
6969

7070
OpenTelemetry getOrCreateOpenTelemetry(
71-
String projectId, @Nullable Credentials credentials, @Nullable String monitoringHost) {
71+
String projectId,
72+
@Nullable Credentials credentials,
73+
@Nullable String monitoringHost,
74+
String universeDomain) {
7275
try {
7376
if (this.openTelemetry == null) {
7477
SdkMeterProviderBuilder sdkMeterProviderBuilder = SdkMeterProvider.builder();
7578
BuiltInMetricsView.registerBuiltinMetrics(
76-
SpannerCloudMonitoringExporter.create(projectId, credentials, monitoringHost),
79+
SpannerCloudMonitoringExporter.create(
80+
projectId, credentials, monitoringHost, universeDomain),
7781
sdkMeterProviderBuilder);
7882
sdkMeterProviderBuilder.setResource(Resource.create(createResourceAttributes(projectId)));
7983
SdkMeterProvider sdkMeterProvider = sdkMeterProviderBuilder.build();
@@ -95,10 +99,13 @@ void enableGrpcMetrics(
9599
InstantiatingGrpcChannelProvider.Builder channelProviderBuilder,
96100
String projectId,
97101
@Nullable Credentials credentials,
98-
@Nullable String monitoringHost) {
102+
@Nullable String monitoringHost,
103+
String universeDomain) {
99104
GrpcOpenTelemetry grpcOpenTelemetry =
100105
GrpcOpenTelemetry.newBuilder()
101-
.sdk(this.getOrCreateOpenTelemetry(projectId, credentials, monitoringHost))
106+
.sdk(
107+
this.getOrCreateOpenTelemetry(
108+
projectId, credentials, monitoringHost, universeDomain))
102109
.enableMetrics(BuiltInMetricsConstant.GRPC_METRICS_TO_ENABLE)
103110
// Disable gRPCs default metrics as they are not needed for Spanner.
104111
.disableMetrics(BuiltInMetricsConstant.GRPC_METRICS_ENABLED_BY_DEFAULT)

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

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import com.google.cloud.monitoring.v3.MetricServiceClient;
2828
import com.google.cloud.monitoring.v3.MetricServiceSettings;
2929
import com.google.common.annotations.VisibleForTesting;
30+
import com.google.common.base.Strings;
3031
import com.google.common.collect.Iterables;
3132
import com.google.common.util.concurrent.MoreExecutors;
3233
import com.google.monitoring.v3.CreateTimeSeriesRequest;
@@ -71,7 +72,10 @@ class SpannerCloudMonitoringExporter implements MetricExporter {
7172
private final String spannerProjectId;
7273

7374
static SpannerCloudMonitoringExporter create(
74-
String projectId, @Nullable Credentials credentials, @Nullable String monitoringHost)
75+
String projectId,
76+
@Nullable Credentials credentials,
77+
@Nullable String monitoringHost,
78+
String universeDomain)
7579
throws IOException {
7680
MetricServiceSettings.Builder settingsBuilder = MetricServiceSettings.newBuilder();
7781
CredentialsProvider credentialsProvider;
@@ -84,6 +88,9 @@ static SpannerCloudMonitoringExporter create(
8488
if (monitoringHost != null) {
8589
settingsBuilder.setEndpoint(monitoringHost);
8690
}
91+
if (!Strings.isNullOrEmpty(universeDomain)) {
92+
settingsBuilder.setUniverseDomain(universeDomain);
93+
}
8794

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

120+
@VisibleForTesting
121+
MetricServiceClient getMetricServiceClient() {
122+
return client;
123+
}
124+
113125
/** Export client built in metrics */
114126
private CompletableResultCode exportSpannerClientMetrics(Collection<MetricData> collection) {
115127
// Filter spanner metrics. Only include metrics that contain a valid project.

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

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,8 @@ public class SpannerOptions extends ServiceOptions<Spanner, SpannerOptions> {
120120
private static final String PG_ADAPTER_CLIENT_LIB_TOKEN = "pg-adapter";
121121

122122
private static final String API_SHORT_NAME = "Spanner";
123-
private static final String DEFAULT_HOST = "https://spanner.googleapis.com";
123+
private static final String SPANNER_SERVICE_NAME = "spanner";
124+
private static final String GOOGLE_DEFAULT_UNIVERSE = "googleapis.com";
124125
private static final String EXPERIMENTAL_HOST_PROJECT_ID = "default";
125126

126127
private static final ImmutableSet<String> SCOPES =
@@ -780,9 +781,19 @@ protected SpannerOptions(Builder builder) {
780781
databaseRole = builder.databaseRole;
781782
sessionLabels = builder.sessionLabels;
782783
try {
783-
spannerStubSettings = builder.spannerStubSettingsBuilder.build();
784-
instanceAdminStubSettings = builder.instanceAdminStubSettingsBuilder.build();
785-
databaseAdminStubSettings = builder.databaseAdminStubSettingsBuilder.build();
784+
String resolvedUniversalDomain = getResolvedUniverseDomain();
785+
spannerStubSettings =
786+
builder.spannerStubSettingsBuilder.setUniverseDomain(resolvedUniversalDomain).build();
787+
instanceAdminStubSettings =
788+
builder
789+
.instanceAdminStubSettingsBuilder
790+
.setUniverseDomain(resolvedUniversalDomain)
791+
.build();
792+
databaseAdminStubSettings =
793+
builder
794+
.databaseAdminStubSettingsBuilder
795+
.setUniverseDomain(resolvedUniversalDomain)
796+
.build();
786797
} catch (IOException e) {
787798
throw SpannerExceptionFactory.newSpannerException(e);
788799
}
@@ -824,6 +835,11 @@ protected SpannerOptions(Builder builder) {
824835
defaultTransactionOptions = builder.defaultTransactionOptions;
825836
}
826837

838+
private String getResolvedUniverseDomain() {
839+
String universeDomain = getUniverseDomain();
840+
return Strings.isNullOrEmpty(universeDomain) ? GOOGLE_DEFAULT_UNIVERSE : universeDomain;
841+
}
842+
827843
/**
828844
* The environment to read configuration values from. The default implementation uses environment
829845
* variables.
@@ -871,6 +887,10 @@ default boolean isEnableEndToEndTracing() {
871887
return false;
872888
}
873889

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

16671687
/** Sets the monitoring host to be used for Built-in client side metrics */
1688+
@Deprecated
1689+
@ObsoleteApi(
1690+
"This will be removed in an upcoming version without a major version bump. You should use"
1691+
+ " universalDomain to configure the built-in metrics endpoint for a partner universe.")
16681692
public Builder setMonitoringHost(String monitoringHost) {
16691693
this.monitoringHost = monitoringHost;
16701694
return this;
@@ -2035,7 +2059,11 @@ public ApiTracerFactory getApiTracerFactory() {
20352059
public void enablegRPCMetrics(InstantiatingGrpcChannelProvider.Builder channelProviderBuilder) {
20362060
if (SpannerOptions.environment.isEnableGRPCBuiltInMetrics()) {
20372061
this.builtInMetricsProvider.enableGrpcMetrics(
2038-
channelProviderBuilder, this.getProjectId(), getCredentials(), this.monitoringHost);
2062+
channelProviderBuilder,
2063+
this.getProjectId(),
2064+
getCredentials(),
2065+
this.monitoringHost,
2066+
getUniverseDomain());
20392067
}
20402068
}
20412069

@@ -2081,7 +2109,7 @@ private ApiTracerFactory getDefaultApiTracerFactory() {
20812109
private ApiTracerFactory createMetricsApiTracerFactory() {
20822110
OpenTelemetry openTelemetry =
20832111
this.builtInMetricsProvider.getOrCreateOpenTelemetry(
2084-
this.getProjectId(), getCredentials(), this.monitoringHost);
2112+
this.getProjectId(), getCredentials(), this.monitoringHost, getUniverseDomain());
20852113

20862114
return openTelemetry != null
20872115
? new BuiltInMetricsTracerFactory(
@@ -2181,7 +2209,11 @@ public static GrpcTransportOptions getDefaultGrpcTransportOptions() {
21812209

21822210
@Override
21832211
protected String getDefaultHost() {
2184-
return DEFAULT_HOST;
2212+
String universeDomain = getUniverseDomain();
2213+
if (Strings.isNullOrEmpty(universeDomain)) {
2214+
universeDomain = GOOGLE_DEFAULT_UNIVERSE;
2215+
}
2216+
return String.format("https://%s.%s", SPANNER_SERVICE_NAME, universeDomain);
21852217
}
21862218

21872219
private static class SpannerDefaults implements ServiceDefaults<Spanner, SpannerOptions> {

google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
import static com.google.cloud.spanner.connection.ConnectionProperties.TRACING_PREFIX;
5050
import static com.google.cloud.spanner.connection.ConnectionProperties.TRACK_CONNECTION_LEAKS;
5151
import static com.google.cloud.spanner.connection.ConnectionProperties.TRACK_SESSION_LEAKS;
52+
import static com.google.cloud.spanner.connection.ConnectionProperties.UNIVERSE_DOMAIN;
5253
import static com.google.cloud.spanner.connection.ConnectionProperties.USER_AGENT;
5354
import static com.google.cloud.spanner.connection.ConnectionProperties.USE_AUTO_SAVEPOINTS_FOR_EMULATOR;
5455
import static com.google.cloud.spanner.connection.ConnectionProperties.USE_PLAIN_TEXT;
@@ -76,6 +77,7 @@
7677
import com.google.cloud.spanner.SpannerOptions;
7778
import com.google.cloud.spanner.connection.StatementExecutor.StatementExecutorType;
7879
import com.google.common.annotations.VisibleForTesting;
80+
import com.google.common.base.MoreObjects;
7981
import com.google.common.base.Preconditions;
8082
import com.google.common.base.Strings;
8183
import com.google.common.base.Suppliers;
@@ -769,16 +771,14 @@ static String determineHost(
769771
boolean autoConfigEmulator,
770772
boolean usePlainText,
771773
Map<String, String> environment) {
772-
String host;
774+
String host = null;
773775
if (Objects.equals(endpoint, DEFAULT_ENDPOINT) && matcher.group(Builder.HOST_GROUP) == null) {
774776
if (autoConfigEmulator) {
775777
if (Strings.isNullOrEmpty(environment.get(SPANNER_EMULATOR_HOST_ENV_VAR))) {
776778
return DEFAULT_EMULATOR_HOST;
777779
} else {
778780
return PLAIN_TEXT_PROTOCOL + "//" + environment.get(SPANNER_EMULATOR_HOST_ENV_VAR);
779781
}
780-
} else {
781-
return DEFAULT_HOST;
782782
}
783783
} else if (!Objects.equals(endpoint, DEFAULT_ENDPOINT)) {
784784
// Add '//' at the start of the endpoint to conform to the standard URL specification.
@@ -792,6 +792,9 @@ static String determineHost(
792792
host = String.format("%s:15000", host);
793793
}
794794
}
795+
if (host == null) {
796+
return null;
797+
}
795798
if (usePlainText) {
796799
return PLAIN_TEXT_PROTOCOL + host;
797800
}
@@ -968,7 +971,7 @@ public TransportChannelProvider getChannelProvider() {
968971
return null;
969972
}
970973
try {
971-
URL url = new URL(host);
974+
URL url = new URL(MoreObjects.firstNonNull(host, DEFAULT_HOST));
972975
ExternalChannelProvider provider =
973976
ExternalChannelProvider.class.cast(Class.forName(channelProvider).newInstance());
974977
return provider.getChannelProvider(url.getHost(), url.getPort());
@@ -1086,6 +1089,10 @@ Boolean isEnableDirectAccess() {
10861089
return getInitialConnectionPropertyValue(ENABLE_DIRECT_ACCESS);
10871090
}
10881091

1092+
String getUniverseDomain() {
1093+
return getInitialConnectionPropertyValue(UNIVERSE_DOMAIN);
1094+
}
1095+
10891096
String getClientCertificate() {
10901097
return getInitialConnectionPropertyValue(CLIENT_CERTIFICATE);
10911098
}

google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionProperties.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,14 @@ public class ConnectionProperties {
200200
BOOLEANS,
201201
BooleanConverter.INSTANCE,
202202
Context.STARTUP);
203+
static final ConnectionProperty<String> UNIVERSE_DOMAIN =
204+
create(
205+
"universeDomain",
206+
"Configure the connection to try to connect to Spanner using "
207+
+ "a different partner Google Universe than GDU (googleapis.com).",
208+
"googleapis.com",
209+
StringValueConverter.INSTANCE,
210+
Context.STARTUP);
203211
static final ConnectionProperty<Boolean> USE_AUTO_SAVEPOINTS_FOR_EMULATOR =
204212
create(
205213
"useAutoSavepointsForEmulator",

google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/SpannerPool.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ static class SpannerPoolKey {
165165
private final String clientCertificateKey;
166166
private final boolean isExperimentalHost;
167167
private final Boolean enableDirectAccess;
168+
private final String universeDomain;
168169

169170
@VisibleForTesting
170171
static SpannerPoolKey of(ConnectionOptions options) {
@@ -200,6 +201,7 @@ private SpannerPoolKey(ConnectionOptions options) throws IOException {
200201
this.clientCertificateKey = options.getClientCertificateKey();
201202
this.isExperimentalHost = options.isExperimentalHost();
202203
this.enableDirectAccess = options.isEnableDirectAccess();
204+
this.universeDomain = options.getUniverseDomain();
203205
}
204206

205207
@Override
@@ -226,7 +228,8 @@ public boolean equals(Object o) {
226228
&& Objects.equals(this.clientCertificate, other.clientCertificate)
227229
&& Objects.equals(this.clientCertificateKey, other.clientCertificateKey)
228230
&& Objects.equals(this.isExperimentalHost, other.isExperimentalHost)
229-
&& Objects.equals(this.enableDirectAccess, other.enableDirectAccess);
231+
&& Objects.equals(this.enableDirectAccess, other.enableDirectAccess)
232+
&& Objects.equals(this.universeDomain, other.universeDomain);
230233
}
231234

232235
@Override
@@ -249,7 +252,8 @@ public int hashCode() {
249252
this.clientCertificate,
250253
this.clientCertificateKey,
251254
this.isExperimentalHost,
252-
this.enableDirectAccess);
255+
this.enableDirectAccess,
256+
this.universeDomain);
253257
}
254258
}
255259

@@ -419,6 +423,9 @@ Spanner createSpanner(SpannerPoolKey key, ConnectionOptions options) {
419423
if (key.enableDirectAccess != null) {
420424
builder.setEnableDirectAccess(key.enableDirectAccess);
421425
}
426+
if (key.universeDomain != null) {
427+
builder.setUniverseDomain(key.universeDomain);
428+
}
422429
if (options.getConfigurator() != null) {
423430
options.getConfigurator().configure(builder);
424431
}

google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerCloudMonitoringExporterTest.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import static com.google.cloud.spanner.BuiltInMetricsConstant.OPERATION_LATENCIES_NAME;
3131
import static com.google.cloud.spanner.BuiltInMetricsConstant.PROJECT_ID_KEY;
3232
import static com.google.common.truth.Truth.assertThat;
33+
import static org.junit.Assert.assertEquals;
3334
import static org.junit.Assert.assertFalse;
3435
import static org.mockito.Mockito.mock;
3536
import static org.mockito.Mockito.when;
@@ -39,6 +40,7 @@
3940
import com.google.api.core.ApiFutures;
4041
import com.google.api.gax.rpc.UnaryCallable;
4142
import com.google.cloud.monitoring.v3.MetricServiceClient;
43+
import com.google.cloud.monitoring.v3.MetricServiceSettings;
4244
import com.google.cloud.monitoring.v3.stub.MetricServiceStub;
4345
import com.google.common.collect.ImmutableList;
4446
import com.google.monitoring.v3.CreateTimeSeriesRequest;
@@ -454,11 +456,30 @@ public void testExportingHistogramDataWithExemplars() {
454456
@Test
455457
public void getAggregationTemporality() throws IOException {
456458
SpannerCloudMonitoringExporter actualExporter =
457-
SpannerCloudMonitoringExporter.create(projectId, null, null);
459+
SpannerCloudMonitoringExporter.create(projectId, null, null, null);
458460
assertThat(actualExporter.getAggregationTemporality(InstrumentType.COUNTER))
459461
.isEqualTo(AggregationTemporality.CUMULATIVE);
460462
}
461463

464+
@Test
465+
public void testUniverseDomain() throws IOException {
466+
SpannerCloudMonitoringExporter actualExporter =
467+
SpannerCloudMonitoringExporter.create(projectId, null, null, "abc.goog");
468+
MetricServiceSettings metricServiceSettings =
469+
actualExporter.getMetricServiceClient().getSettings();
470+
471+
assertEquals("abc.goog", metricServiceSettings.getUniverseDomain());
472+
assertEquals("monitoring.abc.goog:443", metricServiceSettings.getEndpoint());
473+
474+
actualExporter =
475+
SpannerCloudMonitoringExporter.create(
476+
projectId, null, "monitoringa.abc.goog:443", "abc.goog");
477+
metricServiceSettings = actualExporter.getMetricServiceClient().getSettings();
478+
479+
assertEquals("abc.goog", metricServiceSettings.getUniverseDomain());
480+
assertEquals("monitoringa.abc.goog:443", metricServiceSettings.getEndpoint());
481+
}
482+
462483
private static class FakeMetricServiceClient extends MetricServiceClient {
463484

464485
protected FakeMetricServiceClient(MetricServiceStub stub) {

0 commit comments

Comments
 (0)