Skip to content

prometheus: expose descriptor metadata via Desc.Info - #2094

Draft
nicolastakashi wants to merge 3 commits into
prometheus:mainfrom
nicolastakashi:desc-introspection
Draft

prometheus: expose descriptor metadata via Desc.Info#2094
nicolastakashi wants to merge 3 commits into
prometheus:mainfrom
nicolastakashi:desc-introspection

Conversation

@nicolastakashi

@nicolastakashi nicolastakashi commented Aug 25, 2026

Copy link
Copy Markdown

What

Adds a way to ask a Collector what it declares, without parsing Desc.String().

  • Desc.Info() DescInfo returns name, help, unit, variable label names, const labels, and the metric type.
  • Desc now records the metric type. Typed constructors set it; a Desc from NewDesc reports UNTYPED.
  • Registry.DescribeAll() returns the descriptors of every registered checked Collector.
  • testutil.CollectAndDescribe() does the same for a single Collector.

Purely additive. No exported symbol changes signature or behaviour.

Why

There is no structured way to read a descriptor. Anything that wants a metric's declared name, help, unit, or labels has to parse Desc.String(). That format is not an API and it has changed: one release renders variableLabels: [a] with no unit, another renders unit: "..." and variableLabels: {a}. A test built on it breaks on a client_golang bump.

Gather cannot see a metric that has not produced a sample. A CounterVec with no children reports nothing, so you cannot check its type, its labels, or its help. One Prometheus package declares 8 metrics, and 2 of them show up in a scrape of an idle instance. Anything checking metric compatibility against gathered output covers a quarter of that package.

Describe already reaches all 8, but nothing could inspect a descriptor, and a descriptor could not say what type the metric was anyway, because the type lived only on the concrete metric. That is why Desc now carries one.

#2004 asks for this directly: compatibility tests for renamed metrics, removed metrics, and changed labels or types. The blocker in that thread is not being able to ask a Registry what is registered. The breaking change it cites, FluentBit's fluentbit_hot_reloaded_times changing from gauge to counter, is a type change.

There is a working consumer at prometheus/prometheus#19523. It holds a package's metrics to a declared schema and catches renames, removals, added and removed labels, and type changes, including on metrics that never produce a sample.

A Desc keeps its metadata unexported and offers only Err and String, so
code that wants to know what a Collector declares has to parse the output
of String. That format is not an API and has changed between releases.

Add DescInfo and Desc.Info returning a structured, read-only view of the
name, help, unit, variable label names and const labels.

Also record the metric type on the Desc. The type is otherwise only
observable through Gather, which skips any metric that has not produced a
sample, so the type of a vector without children cannot be checked at all
today. The typed constructors set it; a Desc built with NewDesc reports
UNTYPED, which is accurate because a const metric carries its type per
sample rather than on the descriptor.

The metric type deliberately stays out of the id and dimHash calculations
so that registration consistency is unchanged.

Signed-off-by: Nicolas Takashi <nicolas.takashi@dash0.com>
Registry already implements Describe, but draining a channel is awkward
in a test. Add Registry.DescribeAll for a slice of the descriptors of
every registered checked Collector, and testutil.CollectAndDescribe for
the same over a single Collector.

There is no GatherAndDescribe counterpart because the Gatherer interface
does not expose descriptors.

Signed-off-by: Nicolas Takashi <nicolas.takashi@dash0.com>
Signed-off-by: Nicolas Takashi <nicolas.takashi@dash0.com>
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