Skip to content

feat(storage): add OpenTelemetry standard metrics for HTTP JSON and Veneer APIs - #18898

Draft
shradhakatyal wants to merge 7 commits into
googleapis:mainfrom
shradhakatyal:feat/gcs-otel-http-json-metrics
Draft

shradhakatyal wants to merge 7 commits into
googleapis:mainfrom
shradhakatyal:feat/gcs-otel-http-json-metrics

Conversation

@shradhakatyal

Copy link
Copy Markdown
Contributor

Summary

Adds experimental OpenTelemetry standard metrics support for the HTTP JSON transport and logical Veneer APIs in google-cloud-storage, aligned with the unified 10-metric GCS client schema.

Note: Stacked on #18753 (feat/gcs-otel-standard-metrics). Commit 48e02c13309 contains the isolated changes for this PR.

Key Changes

  • Client Lifecycle (client.py): Adds enable_metrics, enable_debug_metrics, and meter_provider parameters to Client.__init__, wires _MetricsRecorder initialization, and calls _metrics_recorder.shutdown() in Client.close().
  • HTTP JSON Transport (_http.py): Instruments _StorageConnection.api_request for per-attempt http.client.request.duration, gcp.storage.client.attempts, gcp.storage.client.ttfb, gcp.storage.client.retries, and gcp.storage.client.errors with bounded url.template normalization.
  • Logical Veneer Operations (_helpers.py, client.py, bucket.py, blob.py, acl.py, hmac_key.py, notification.py): Instruments user-facing Veneer methods to emit outermost gcp.client.request.duration and gcp.storage.client.operations while normalizing expected 404 existence/lookup checks to OK.
  • Batch & Lazy Pagination (batch.py, client.py, bucket.py, blob.py): Defers Batch sub-request logical operation metrics until Batch.finish() and tracks per-page lazy HTTPIterator fetches (ListBuckets, ListObjects, ListHmacKeys, ListNotifications).
  • Internal Metadata Cache Suppression (_bucket_metadata_cache.py): Suppresses background bucket metadata cache lookups used for tracing attributes from emitting user-facing metrics.

…d helpers

Implement core OpenTelemetry standard metrics infrastructure for GCS:
- Add _MetricsRecorder with the 9 standard metric instruments
- Add custom latency (165 buckets) and byte-size (45 buckets) histogram views
- Add classify_error_type for low-cardinality error.type mapping
- Add normalize_url_template for bounded HTTP url.template routing
- Add start_operation ContextVar for outermost logical operation tracking and nested call suppression

[Generated-by: AI]
- Add gcp.storage.client.retries counter and rename TTFB metric to gcp.storage.client.ttfb
- Remove gcp.client.repo from _COMMON_ATTRIBUTES
- Update _build_size_buckets to generate 48 buckets matching Go and Java SDKs
- Align per-metric attributes across logical operation, RPC/HTTP attempt, error, retry, and TTFB recorders

[Generated-by: AI]
…fy CONNECTION_ERROR

- Scope histogram View registrations to meter_name="google.cloud.storage"
- Guard normalize_url_template and _extract_server_address against malformed URIs and gRPC authority schemes
- Consolidate CONNECTION_REFUSED, CONNECTION_RESET, and CONNECTIVITY error labels into CONNECTION_ERROR

[Generated-by: AI]
…eneer APIs

- Wire _MetricsRecorder lifecycle and meter_provider configuration into Client
- Instrument _StorageConnection.api_request for per-attempt HTTP duration, TTFB, retries, and errors
- Add logical operation instrumentation across Client, Bucket, Blob, ACL, Batch, HMACKeyMetadata, and BucketNotification
- Defer Batch sub-request operations until Batch.finish() and track lazy HTTPIterator page metrics
- Suppress internal background bucket metadata cache lookups from emitting user-facing metrics

@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 implements OpenTelemetry standard metrics across the Google Cloud Storage Python client, introducing metrics instrumentation, custom histogram views, canonical error classification, and route normalization. It integrates metrics recording into HTTP transport, logical operations (such as Bucket, Blob, ACL, and Batch), and background tasks, backed by comprehensive unit tests. The review feedback suggests falling back to self._client in Connection.api_request when the client argument is None to ensure metrics are consistently recorded, along with adding corresponding test cases.

Comment on lines +173 to +180
recorder = (
None
if (
getattr(self, "_IS_BATCH", False) is True
or _helpers._SUPPRESS_INTERNAL_METRICS.get()
)
else _opentelemetry_metrics.get_active_recorder(client)
)

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

In Connection.api_request, if the client argument is None, get_active_recorder(client) will return None and metrics will not be recorded, even if self._client has an active recorder. Consider falling back to self._client when client is None to ensure metrics are consistently recorded. Additionally, ensure there are test cases covering both when the client is explicitly provided and when it is omitted.

Suggested change
recorder = (
None
if (
getattr(self, "_IS_BATCH", False) is True
or _helpers._SUPPRESS_INTERNAL_METRICS.get()
)
else _opentelemetry_metrics.get_active_recorder(client)
)
recorder = (
None
if (
getattr(self, "_IS_BATCH", False) is True
or _helpers._SUPPRESS_INTERNAL_METRICS.get()
)
else _opentelemetry_metrics.get_active_recorder(client or self._client)
)
References
  1. When testing functions that accept an optional client or resource parameter, ensure there are test cases covering both when the client is explicitly provided and when it is omitted (defaulting to None).

This branch has not been deployed

No deployments
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.

1 participant