Skip to content
Open
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 @@ -306,6 +306,17 @@ public DatabaseClient getDatabaseClient(DatabaseId db) {
if (dbClients.containsKey(db)) {
return dbClients.get(db);
} else {
SpannerOptions opts = getOptions();
String metricsProject = opts.resolveMetricsProjectId();
if (opts.isEnableBuiltInMetrics()
&& metricsProject != null
&& !metricsProject.equals(db.getInstanceId().getProject())) {
logger.log(
Level.INFO,
"Built-in metrics project ''{0}'' differs from DatabaseId project ''{1}''."
+ " Use setMetricsProjectId() to override if needed.",
new Object[] {metricsProject, db.getInstanceId().getProject()});
}
if (clientId == null) {
clientId = nextDatabaseClientId(db);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ static GcpChannelPoolOptions mergeWithDefaultChannelPoolOptions(
private final boolean enableExtendedTracing;
private final boolean enableEndToEndTracing;
private final String monitoringHost;
private final String metricsProjectId;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

When adding a new configuration field like metricsProjectId to SpannerOptions, it is essential to update the equals() and hashCode() methods to include it. Failure to do so can cause issues when SpannerOptions instances are used as keys in caches or when comparing configurations for equality.

private final TransactionOptions defaultTransactionOptions;
private final RequestOptions.ClientContext clientContext;

Expand Down Expand Up @@ -991,6 +992,7 @@ protected SpannerOptions(Builder builder) {
}
enableEndToEndTracing = builder.enableEndToEndTracing;
monitoringHost = builder.monitoringHost;
metricsProjectId = builder.metricsProjectId;
defaultTransactionOptions = builder.defaultTransactionOptions;
clientContext = builder.clientContext;
}
Expand Down Expand Up @@ -1251,6 +1253,7 @@ public static class Builder
private boolean enableBuiltInMetrics = SpannerOptions.environment.isEnableBuiltInMetrics();
private boolean enableLocationApi = SpannerOptions.environment.isEnableLocationApi();
private String monitoringHost = SpannerOptions.environment.getMonitoringHost();
private String metricsProjectId;
private SslContext mTLSContext = null;
private String experimentalHost = null;
private boolean usePlainText = false;
Expand Down Expand Up @@ -1360,6 +1363,7 @@ protected Builder() {
this.enableLocationApi = options.enableLocationApi;
this.enableEndToEndTracing = options.enableEndToEndTracing;
this.monitoringHost = options.monitoringHost;
this.metricsProjectId = options.metricsProjectId;
this.defaultTransactionOptions = options.defaultTransactionOptions;
this.clientContext = options.clientContext;
}
Expand Down Expand Up @@ -2033,6 +2037,17 @@ public Builder setMonitoringHost(String monitoringHost) {
return this;
}

/**
* Sets the GCP project ID for exporting client-side built-in metrics. Defaults to {@link
* SpannerOptions#getProjectId()} when not set. On GKE with shared VPC, the default project may
* resolve to the host project instead of the application project; set this explicitly to avoid
* {@code monitoring.metricWriter} permission errors.
*/
public Builder setMetricsProjectId(String metricsProjectId) {
this.metricsProjectId = metricsProjectId;
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:
Expand Down Expand Up @@ -2443,14 +2458,14 @@ public ApiTracerFactory getApiTracerFactory() {
@InternalApi
public OpenTelemetry getBuiltInOpenTelemetry() {
return this.builtInMetricsProvider.getOrCreateOpenTelemetry(
this.getProjectId(), getCredentials(), this.monitoringHost, getUniverseDomain());
this.resolveMetricsProjectId(), getCredentials(), this.monitoringHost, getUniverseDomain());
}

public void enablegRPCMetrics(InstantiatingGrpcChannelProvider.Builder channelProviderBuilder) {
if (isEnableBuiltInMetrics() && SpannerOptions.environment.isEnableGRPCBuiltInMetrics()) {
this.builtInMetricsProvider.enableGrpcMetrics(
channelProviderBuilder,
this.getProjectId(),
this.resolveMetricsProjectId(),
getCredentials(),
this.monitoringHost,
getUniverseDomain());
Expand Down Expand Up @@ -2499,7 +2514,7 @@ private ApiTracerFactory getDefaultApiTracerFactory() {
private ApiTracerFactory createMetricsApiTracerFactory() {
OpenTelemetry openTelemetry =
this.builtInMetricsProvider.getOrCreateOpenTelemetry(
this.getProjectId(), getCredentials(), this.monitoringHost, getUniverseDomain());
this.resolveMetricsProjectId(), getCredentials(), this.monitoringHost, getUniverseDomain());

return openTelemetry != null
? new BuiltInMetricsTracerFactory(
Expand Down Expand Up @@ -2543,6 +2558,19 @@ String getMonitoringHost() {
return monitoringHost;
}

/**
* Returns the GCP project ID for client-side metrics export. Returns the explicit value if set
* via {@link Builder#setMetricsProjectId}, otherwise falls back to {@link #getProjectId()}.
*/
String resolveMetricsProjectId() {
return metricsProjectId != null ? metricsProjectId : getProjectId();
}

/** Returns the explicitly configured metrics project ID, or null if not set. */
public String getMetricsProjectId() {
return metricsProjectId;
}

public TransactionOptions getDefaultTransactionOptions() {
return defaultTransactionOptions;
}
Expand Down
Loading