Skip to content

feat(metrics): add support for metric families and label serialisation#234

Open
ethanolchik wants to merge 4 commits into
cloudflare:mainfrom
ethanolchik:metrics/family-n-labels
Open

feat(metrics): add support for metric families and label serialisation#234
ethanolchik wants to merge 4 commits into
cloudflare:mainfrom
ethanolchik:metrics/family-n-labels

Conversation

@ethanolchik

@ethanolchik ethanolchik commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Overview

This PR builds on the already-merged scalar metrics #232 (Counter, Gauge) to add labelled metrics. It introduces a serde-based system for serialising metric label sets into the Prometheus protobuf data model, and adds a Family abstraction for grouping metrics by their label values.

Label serialisation and error handling

  • Introduced a new labels module with:
    • to_label_pairs: serialises any serde::Serialize label set into protobuf LabelPair values.
    • A serde Serializer implementation that flattens a label struct into name/value pairs, rejecting unsupported compound types (sequences, maps, nested structs, byte arrays) with clear errors.
    • LabelError: a dedicated error type implementing serde::ser::Error.
  • Preserves the scalar formatting behaviour of the existing metrics backend: ryu-based float formatting, serde renames, enum variants, optional values, and Display adapters.
  • Validates label names against [a-zA-Z_:][a-zA-Z0-9_:]*.
  • Stores label values as raw strings - OpenMetrics escaping is deliberately deferred to the text encoder, keeping the protobuf model format-independent.
  • Added serde (with derive), ryu, and parking_lot dependencies to support label serialisation and efficient concurrent metric storage.

Metrics API enhancements

  • Added Family<S, M, C>: shared, labelled metric storage with:
    • get_or_create, remove, and clear lifecycle operations; clones share the same underlying metrics.
    • A MetricConstructor trait (with a blanket Fn() -> M impl) for metrics that need configuration at creation time.
  • Fail-soft collection: when encoding, invalid label sets and metric groups with inconsistent metadata are skipped (with a diagnostic) rather than failing the entire scrape; multi-series metrics (e.g. RangeGauge) are grouped correctly by suffix.
  • Re-exported Family, MetricConstructor, LabelError, to_label_pairs, and set_collect_error_hook from the crate root for downstream use.

Decoupling logging from metrics

  • Collection diagnostics are emitted through an installable hook (set_collect_error_hook) rather than a hard-coded logger, defaulting to stderr when none is set.
  • Follow-up (for when foundations adopts this crate): install a collect_error hook that forwards these diagnostics to the telemetry logging pipeline (at warning level), matching the legacy backend's behaviour.

Protobuf model adjustments

  • Re-exported LabelPair from the registry proto module so downstream code can construct/consume label pairs.

Attribution

  • The label serialiser and Family are adapted from prometools (MIT OR Apache-2.0); per-definition // Adapted from ... notes were added, per the discussion with @TheJokr. (prometheus-client-derived code remains covered by the existing module-level # License disclaimer.)

Add a serde serialiser that converts metric label structs into Prometheus protobuf LabelPair values.

Preserve the legacy backend's scalar formatting behaviour, including ryu-based float formatting, serde renames, enum variants, optional values, and display adapters. Validate label names and reject unsupported compound values.

Store label values without OpenMetrics escaping so the protobuf model remains format-independent and text escaping can be applied later by the text encoder.
Add shared labeled metric storage with custom constructors and lifecycle operations. Group encoded metrics by suffix and skip invalid label sets or inconsistent metadata without failing collection.
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