Skip to content

feat(spanner): support user-provided OpenTelemetry for built-in client metrics and endpoint attribute for location-aware routing#13679

Open
rahul2393 wants to merge 2 commits into
googleapis:mainfrom
rahul2393:feat/spanner-custom-otel-metrics
Open

feat(spanner): support user-provided OpenTelemetry for built-in client metrics and endpoint attribute for location-aware routing#13679
rahul2393 wants to merge 2 commits into
googleapis:mainfrom
rahul2393:feat/spanner-custom-otel-metrics

Conversation

@rahul2393

@rahul2393 rahul2393 commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds Client Metrics: a new, independent opt-in feature that exports Spanner's client-side metrics to a caller-provided OpenTelemetry pipeline (OTLP, Prometheus, any exporter), including on Spanner Omni where the existing Cloud Monitoring metrics are unavailable. Also adds an optional endpoint attribute on the metrics for the location-aware routing path.

Fully opt-in and fully decoupled from the existing built-in (Cloud Monitoring) metrics. Default behavior is unchanged: without a client-metrics provider, nothing new happens, and built-in metrics continue to export to Cloud Monitoring exactly as before.

Two independent features

  • Built-in metrics (existing, unchanged): export to Google Cloud Monitoring. Controlled by setBuiltInMetricsEnabled and the SPANNER_DISABLE_BUILTIN_METRICS environment variable, exactly as today. Not available on Spanner Omni.
  • Client metrics (new): export the client instruments to a caller-owned OpenTelemetry. Controlled solely by setClientMetricsProvider(...) — a CustomOpenTelemetryMetricsProvider turns it on; NoopMetricsProvider (or no provider) turns it off. Works on all instance types, Omni included.

The two are decoupled: setBuiltInMetricsEnabled and the env var affect only the built-in Cloud Monitoring sink and have no effect on client metrics; the client-metrics provider affects only the caller-owned sink and has no effect on built-in metrics. Under the hood these are the same client instruments, exported under the distinct spanner/client namespace — the difference is the export path, not the metrics.

Motivation

Client metrics currently export only to Cloud Monitoring, which is unavailable on Spanner Omni. Customers running on Omni (or who standardize on their own observability stack) had no way to receive these metrics. This lets them route the metrics to any OpenTelemetry exporter, independently of the built-in Cloud Monitoring configuration.

API

SdkMeterProviderBuilder meterProviderBuilder =
    SdkMeterProvider.builder()
        .registerMetricReader(PeriodicMetricReader.create(myExporter));

// Apply Spanner's client-metric views to your own builder (recommended):
// correct metric names, histogram buckets, and attribute filtering.
SpannerMetrics.configureMeterProviderBuilder(meterProviderBuilder);

OpenTelemetry otel =
    OpenTelemetrySdk.builder().setMeterProvider(meterProviderBuilder.build()).build();

SpannerOptions options =
    SpannerOptions.newBuilder()
        .setClientMetricsProvider(CustomOpenTelemetryMetricsProvider.create(otel))
        .build();
  • setClientMetricsProvider(MetricsProvider) — controls the client-metrics export destination only.
    • CustomOpenTelemetryMetricsProvider — export client metrics to a caller-provided OpenTelemetry.
    • NoopMetricsProvider — disable client-metrics export.
    • DefaultMetricsProvider (default) — no client-metrics export.
  • SpannerMetrics.configureMeterProviderBuilder(SdkMeterProviderBuilder) — registers the client-metric views on the caller's meter-provider builder (metric names under spanner/client, histogram buckets, attribute filtering). Optional but recommended; without it, metrics record with raw instrument names, default buckets, and unfiltered attributes.

Behavior

  • Client metrics are controlled solely by the provider. Setting a custom provider records the client instruments to your OpenTelemetry regardless of setBuiltInMetricsEnabled or the env var; NoopMetricsProvider/no provider disables it.
  • Built-in (Cloud Monitoring) metrics are unchanged: on non-Omni they are gated by setBuiltInMetricsEnabled/env as today; on Omni they never run.
  • The client-metrics sink uses a distinct namespace (spanner/client), separate from the reserved Cloud Monitoring namespace (spanner.googleapis.com/...), so re-exporting these metrics to Cloud Monitoring yourself cannot collide with the reserved Spanner metrics.
  • On Spanner Omni, Cloud Monitoring export is never available, and the built-in flags/env have no effect on client metrics. Setting a custom provider is the way to receive client metrics there — a bare custom provider on an Omni host records to your OpenTelemetry with no further configuration.
  • The endpoint attribute is added to client attempt metrics only on the Omni location-aware routing path, carrying the resolved endpoint host. It never appears on operation metrics or on the default path, so standard deployments see no new cardinality.

Notes

  • gRPC-layer client metrics record only when the supplied OpenTelemetry is an OpenTelemetrySdk instance; all other client metrics work with any OpenTelemetry implementation.

@rahul2393 rahul2393 requested review from a team as code owners July 7, 2026 17:32

@gemini-code-assist gemini-code-assist Bot left a comment

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.

Code Review

This pull request introduces the MetricsProvider interface and its implementations (DefaultMetricsProvider, NoopMetricsProvider, and CustomOpenTelemetryMetricsProvider) to allow customization of how built-in client-side metrics are collected and exported in the Cloud Spanner Java client. This enables recording metrics on a caller-provided OpenTelemetry instance rather than exporting them directly to Google Cloud Monitoring, which is particularly useful for Spanner Omni clients. Additionally, the changes add support for registering built-in metric views on a custom meter provider, introduce an endpoint attribute for location-aware routing, and include comprehensive integration and unit tests to validate these new features. There are no review comments, so I have no feedback to provide.

@rahul2393 rahul2393 force-pushed the feat/spanner-custom-otel-metrics branch from 124a9c7 to 383daa2 Compare July 8, 2026 07:18
@rahul2393

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

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.

Code Review

This pull request introduces a customizable MetricsProvider interface for the Cloud Spanner Java client, allowing users to configure how built-in metrics are collected and exported. It adds support for a CustomOpenTelemetryMetricsProvider to record metrics on a user-provided OpenTelemetry instance, alongside the default Google Cloud Monitoring export and a NoopMetricsProvider to disable metrics entirely. The changes also include labeling attempt metrics with routed endpoints on the location-aware fastpath, and extensive integration tests verifying the dual-sink and gRPC-layer metrics behavior. Feedback on the code changes highlights a potential UnsupportedOperationException in BuiltInMetricsConstant.java due to mutating a set returned by Collectors.toSet(), with a suggestion to use Collectors.toCollection(HashSet::new) to guarantee mutability.

@rahul2393 rahul2393 force-pushed the feat/spanner-custom-otel-metrics branch from f7bd207 to 5a63c9e Compare July 8, 2026 09:17
@rahul2393

Copy link
Copy Markdown
Contributor Author

Current failures in CI pipeline are because of #13584
cc: @lqiu96

@rahul2393 rahul2393 force-pushed the feat/spanner-custom-otel-metrics branch from 72b0be7 to 03c7825 Compare July 8, 2026 14:56
@lqiu96

lqiu96 commented Jul 8, 2026

Copy link
Copy Markdown
Member

Current failures in CI pipeline are because of #13584 cc: @lqiu96

Sorry, we will fix this upstream. I think you should be able to proceed without this check if you want

…t metrics and endpoint attribute for location-aware routing
@rahul2393 rahul2393 force-pushed the feat/spanner-custom-otel-metrics branch from b5fa19a to 1add8f1 Compare July 8, 2026 17:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants