Documentation
¶
Overview ¶
Package expfmt provides a fast, allocation-light encoder for the Prometheus text exposition format.
It exists for promxy's /federate endpoint (issue #784). The upstream federation handler builds a full dto.MetricFamily tree per request and hands it to github.com/prometheus/common/expfmt, whose text encoder (since common v0.65 / the Prometheus 3.x UTF-8 name support) re-validates every metric and label name on encode. Together that dominates federation CPU and allocations. promxy already has the data as labels.Labels (it just decoded a downstream response), so it can stream the exposition format directly, skipping the dto tree.
The output is byte-for-byte identical to common/expfmt for the subset federation emits: UNTYPED float samples. In particular, name handling (legacy-valid names written bare, otherwise quoted with the metric name moved inside the braces), label-value escaping, and float/timestamp formatting all match common/expfmt exactly, including UTF-8 names. This is verified by byte-equivalence tests against common/expfmt.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func MetricFamilyToText ¶
func MetricFamilyToText(out io.Writer, mf *dto.MetricFamily) error
MetricFamilyToText encodes an UNTYPED metric family to the text format, byte-for-byte compatible with common/expfmt for that type. It exists mainly as a testing/benchmarking surface that shares the exact primitives the federation Encoder uses; the federation handler uses Encoder directly.
Types ¶
type Encoder ¶
type Encoder struct {
// contains filtered or unexported fields
}
Encoder streams federation output (UNTYPED float samples) directly from labels.Labels, without building a dto.MetricFamily. Samples must be supplied grouped by metric name (sorted), matching upstream federation which emits one "# TYPE <name> untyped" line per metric family.
scheme is the name-escaping scheme negotiated from the scrape request's Accept header (model.EscapingScheme), applied to every metric and label name exactly as common/expfmt's encoder does via model.EscapeMetricFamily. For the default (UnderscoreEscaping) and legacy-valid names this is allocation-free.
func NewEncoder ¶
func NewEncoder(w io.Writer, scheme model.EscapingScheme) *Encoder
func (*Encoder) WriteFloatSample ¶
func (e *Encoder) WriteFloatSample(name string, lbls labels.Labels, external []labels.Label, v float64, t int64)
WriteFloatSample writes one untyped sample.
- name is the metric name (the value of the __name__ label).
- lbls is the full label set of the series; the __name__ label and any empty-valued labels are skipped (matching upstream federation).
- external are additional labels (e.g. external_labels) to attach, in the order given, but only when not already present in lbls. Pass them pre-sorted by name to match upstream byte ordering.
A "# TYPE <name> untyped" line is emitted whenever name changes from the previous call, so callers must group samples by name.