@@ -306,6 +306,7 @@ static GcpChannelPoolOptions mergeWithDefaultChannelPoolOptions(
306306 private final boolean enableExtendedTracing ;
307307 private final boolean enableEndToEndTracing ;
308308 private final String monitoringHost ;
309+ private final String metricsProjectId ;
309310 private final TransactionOptions defaultTransactionOptions ;
310311 private final RequestOptions .ClientContext clientContext ;
311312
@@ -991,6 +992,7 @@ protected SpannerOptions(Builder builder) {
991992 }
992993 enableEndToEndTracing = builder .enableEndToEndTracing ;
993994 monitoringHost = builder .monitoringHost ;
995+ metricsProjectId = builder .metricsProjectId ;
994996 defaultTransactionOptions = builder .defaultTransactionOptions ;
995997 clientContext = builder .clientContext ;
996998 }
@@ -1251,6 +1253,7 @@ public static class Builder
12511253 private boolean enableBuiltInMetrics = SpannerOptions .environment .isEnableBuiltInMetrics ();
12521254 private boolean enableLocationApi = SpannerOptions .environment .isEnableLocationApi ();
12531255 private String monitoringHost = SpannerOptions .environment .getMonitoringHost ();
1256+ private String metricsProjectId ;
12541257 private SslContext mTLSContext = null ;
12551258 private String experimentalHost = null ;
12561259 private boolean usePlainText = false ;
@@ -1360,6 +1363,7 @@ protected Builder() {
13601363 this .enableLocationApi = options .enableLocationApi ;
13611364 this .enableEndToEndTracing = options .enableEndToEndTracing ;
13621365 this .monitoringHost = options .monitoringHost ;
1366+ this .metricsProjectId = options .metricsProjectId ;
13631367 this .defaultTransactionOptions = options .defaultTransactionOptions ;
13641368 this .clientContext = options .clientContext ;
13651369 }
@@ -2033,6 +2037,17 @@ public Builder setMonitoringHost(String monitoringHost) {
20332037 return this ;
20342038 }
20352039
2040+ /**
2041+ * Sets the GCP project ID for exporting client-side built-in metrics. Defaults to {@link
2042+ * SpannerOptions#getProjectId()} when not set. On GKE with shared VPC, the default project may
2043+ * resolve to the host project instead of the application project; set this explicitly to avoid
2044+ * {@code monitoring.metricWriter} permission errors.
2045+ */
2046+ public Builder setMetricsProjectId (String metricsProjectId ) {
2047+ this .metricsProjectId = metricsProjectId ;
2048+ return this ;
2049+ }
2050+
20362051 /**
20372052 * Sets whether to enable extended OpenTelemetry tracing. Enabling this option will add the
20382053 * following additional attributes to the traces that are generated by the client:
@@ -2443,14 +2458,14 @@ public ApiTracerFactory getApiTracerFactory() {
24432458 @ InternalApi
24442459 public OpenTelemetry getBuiltInOpenTelemetry () {
24452460 return this .builtInMetricsProvider .getOrCreateOpenTelemetry (
2446- this .getProjectId (), getCredentials (), this .monitoringHost , getUniverseDomain ());
2461+ this .resolveMetricsProjectId (), getCredentials (), this .monitoringHost , getUniverseDomain ());
24472462 }
24482463
24492464 public void enablegRPCMetrics (InstantiatingGrpcChannelProvider .Builder channelProviderBuilder ) {
24502465 if (isEnableBuiltInMetrics () && SpannerOptions .environment .isEnableGRPCBuiltInMetrics ()) {
24512466 this .builtInMetricsProvider .enableGrpcMetrics (
24522467 channelProviderBuilder ,
2453- this .getProjectId (),
2468+ this .resolveMetricsProjectId (),
24542469 getCredentials (),
24552470 this .monitoringHost ,
24562471 getUniverseDomain ());
@@ -2499,7 +2514,7 @@ private ApiTracerFactory getDefaultApiTracerFactory() {
24992514 private ApiTracerFactory createMetricsApiTracerFactory () {
25002515 OpenTelemetry openTelemetry =
25012516 this .builtInMetricsProvider .getOrCreateOpenTelemetry (
2502- this .getProjectId (), getCredentials (), this .monitoringHost , getUniverseDomain ());
2517+ this .resolveMetricsProjectId (), getCredentials (), this .monitoringHost , getUniverseDomain ());
25032518
25042519 return openTelemetry != null
25052520 ? new BuiltInMetricsTracerFactory (
@@ -2543,6 +2558,14 @@ String getMonitoringHost() {
25432558 return monitoringHost ;
25442559 }
25452560
2561+ /**
2562+ * Returns the GCP project ID for client-side metrics export. Returns the explicit value if set
2563+ * via {@link Builder#setMetricsProjectId}, otherwise falls back to {@link #getProjectId()}.
2564+ */
2565+ String resolveMetricsProjectId () {
2566+ return metricsProjectId != null ? metricsProjectId : getProjectId ();
2567+ }
2568+
25462569 public TransactionOptions getDefaultTransactionOptions () {
25472570 return defaultTransactionOptions ;
25482571 }
0 commit comments