or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

assets.mdconfig.mdexpfmt.mdhelpers-templates.mdindex.mdmodel.mdpromslog-flag.mdpromslog.mdroute.mdserver.mdversion.md
tile.json

expfmt.mddocs/

Expfmt Package

The expfmt package provides tools for reading and writing Prometheus metrics in various exposition formats including text format, protocol buffers, and OpenMetrics.

Import

import "github.com/prometheus/common/expfmt"

Overview

This package handles the encoding and decoding of Prometheus metrics across multiple format versions. It supports content negotiation, format detection, and streaming parsing of metrics data. The package is used throughout the Prometheus ecosystem for metrics exposition and scraping.

Constants

Format Version Constants

const (
    TextVersion            = "0.0.4"
    ProtoType              = `application/vnd.google.protobuf`
    ProtoProtocol          = `io.prometheus.client.MetricFamily`
    ProtoFmt               = ProtoType + "; proto=" + ProtoProtocol + ";"  // Deprecated
    OpenMetricsType        = `application/openmetrics-text`
    OpenMetricsVersion_0_0_1 = "0.0.1"
    OpenMetricsVersion_1_0_0 = "1.0.0"
)

Constants defining version strings and media types for different exposition formats.

Core Types

Format

type Format string

Represents a Prometheus exposition format with content type and optional parameters.

Format Constants

const (
    FmtUnknown             Format = `<unknown>`  // Deprecated
    FmtText                Format = `text/plain; version=0.0.4; charset=utf-8`  // Deprecated
    FmtProtoDelim          Format = ProtoFmt + ` encoding=delimited`  // Deprecated
    FmtProtoText           Format = ProtoFmt + ` encoding=text`  // Deprecated
    FmtProtoCompact        Format = ProtoFmt + ` encoding=compact-text`  // Deprecated
    FmtOpenMetrics_1_0_0   Format = OpenMetricsType + `; version=1.0.0; charset=utf-8`  // Deprecated
    FmtOpenMetrics_0_0_1   Format = OpenMetricsType + `; version=0.0.1; charset=utf-8`  // Deprecated
)

Pre-defined format constants. Deprecated in favor of using NewFormat and NewOpenMetricsFormat.

Methods

func (f Format) WithEscapingScheme(s model.EscapingScheme) Format

Returns a copy of the format with the specified escaping scheme parameter.

Parameters:

  • s - Escaping scheme to apply

Returns: New Format with escaping scheme

func (f Format) FormatType() FormatType

Deduces the FormatType from the format string.

Returns: The FormatType

func (f Format) ToEscapingScheme() model.EscapingScheme

Returns the EscapingScheme encoded in the Format, or NoEscaping if not specified.

Returns: The escaping scheme

FormatType

type FormatType int

Represents the type of exposition format.

const (
    TypeUnknown FormatType = iota
    TypeProtoCompact
    TypeProtoDelim
    TypeProtoText
    TypeTextPlain
    TypeOpenMetrics
)

FormatType Values

  • TypeUnknown - Unknown or unsupported format
  • TypeProtoCompact - Protocol buffer compact text encoding
  • TypeProtoDelim - Protocol buffer delimited encoding
  • TypeProtoText - Protocol buffer text encoding
  • TypeTextPlain - Text format (0.0.4)
  • TypeOpenMetrics - OpenMetrics text format

Decoding Types

DecodeOptions

type DecodeOptions struct {
    Timestamp model.Time
}

Options for decoding metrics.

Fields:

  • Timestamp - Timestamp added to each sample that doesn't have an explicit timestamp

SampleDecoder

type SampleDecoder struct {
    Dec  Decoder
    Opts *DecodeOptions
}

Decoder that extracts samples from metric families.

Fields:

  • Dec - The underlying decoder
  • Opts - Decode options

Methods

func (sd *SampleDecoder) Decode(s *model.Vector) error

Decodes metric families and extracts samples into the provided vector.

Parameters:

  • s - Vector to append samples to

Returns: Error if decoding fails

ParseError

type ParseError struct {
    Line int
    Msg  string
}

Error type for parse errors with line number information.

Fields:

  • Line - Line number where error occurred
  • Msg - Error message

Methods

func (e ParseError) Error() string

Returns formatted error message with line number.

TextParser

type TextParser struct {
    // Parser for text format metrics
}

Parser for text format metrics.

Methods

func (p *TextParser) TextToMetricFamilies(in io.Reader) (map[string]*dto.MetricFamily, error)

Parses text format metrics into metric families.

Parameters:

  • in - Reader containing text format metrics

Returns: Map of metric family names to MetricFamily, error

Interfaces

Decoder

type Decoder interface {
    Decode(*dto.MetricFamily) error
}

Interface for decoding Prometheus metrics. Implementations decode one metric family per call.

Methods:

  • Decode(*dto.MetricFamily) error - Decodes the next metric family

Encoder

type Encoder interface {
    Encode(*dto.MetricFamily) error
}

Interface for encoding Prometheus metrics. Implementations encode one metric family per call.

Methods:

  • Encode(*dto.MetricFamily) error - Encodes a metric family

Closer

type Closer interface {
    Close() error
}

Interface for closeable encoders. Some encoders need to write finalization data (like OpenMetrics EOF marker).

Methods:

  • Close() error - Closes the encoder and writes any finalization data

Format Functions

NewFormat

func NewFormat(t FormatType) Format

Generates a new Format from FormatType.

Parameters:

  • t - The format type

Returns: Format string

Example:

format := expfmt.NewFormat(expfmt.TypeTextPlain)
// Returns: "text/plain; version=0.0.4; charset=utf-8"

NewOpenMetricsFormat

func NewOpenMetricsFormat(version string) (Format, error)

Generates an OpenMetrics format with the specified version.

Parameters:

  • version - OpenMetrics version (e.g., "1.0.0" or "0.0.1")

Returns: (Format, error)

Example:

format, err := expfmt.NewOpenMetricsFormat("1.0.0")
// Returns: "application/openmetrics-text; version=1.0.0; charset=utf-8"

ResponseFormat

func ResponseFormat(h http.Header) Format

Extracts format from HTTP response Content-Type header.

Parameters:

  • h - HTTP response headers

Returns: Detected Format

Negotiate

func Negotiate(h http.Header) Format

Negotiates format from Accept header, excluding OpenMetrics formats. This is the standard negotiation function for compatibility.

Parameters:

  • h - HTTP headers containing Accept header

Returns: Best matching Format

NegotiateIncludingOpenMetrics

func NegotiateIncludingOpenMetrics(h http.Header) Format

Negotiates format from Accept header, including OpenMetrics formats.

Parameters:

  • h - HTTP headers containing Accept header

Returns: Best matching Format including OpenMetrics

Decoder Functions

NewDecoder

func NewDecoder(r io.Reader, format Format) Decoder

Returns a decoder for the specified format.

Parameters:

  • r - Reader to decode from
  • format - Format to decode

Returns: Decoder instance

Note: For unsupported or unknown formats, the decoder falls back to text format parsing for backward compatibility. This fallback behavior exists for historical reasons and may not fully support OpenMetrics or the latest features of Prometheus text format.

Example:

decoder := expfmt.NewDecoder(reader, expfmt.NewFormat(expfmt.TypeTextPlain))
for {
    var mf dto.MetricFamily
    if err := decoder.Decode(&mf); err != nil {
        if err == io.EOF {
            break
        }
        // handle error
    }
    // process metric family
}

Encoder Functions

NewEncoder

func NewEncoder(w io.Writer, format Format, options ...EncoderOption) Encoder

Returns an encoder for the specified format.

Parameters:

  • w - Writer to encode to
  • format - Format to encode
  • options - Optional encoder options

Returns: Encoder instance

Example:

encoder := expfmt.NewEncoder(writer, expfmt.NewFormat(expfmt.TypeTextPlain))
err := encoder.Encode(metricFamily)

EncoderOption

type EncoderOption func(*encoderOption)

Function type for encoder options.

WithCreatedLines

func WithCreatedLines() EncoderOption

Configures OpenMetrics encoder to include _created lines for counters and histograms.

Returns: EncoderOption

WithUnit

func WithUnit() EncoderOption

Enables unit to be written and added to metric name suffix in OpenMetrics format.

Returns: EncoderOption

Text Format Functions

MetricFamilyToText

func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (written int, err error)

Writes a metric family in text format (0.0.4).

Parameters:

  • out - Output writer
  • in - Metric family to write

Returns: (int, error) - Bytes written, error

Example:

written, err := expfmt.MetricFamilyToText(os.Stdout, metricFamily)

MetricFamilyToOpenMetrics

func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily, options ...EncoderOption) (written int, err error)

Writes a metric family in OpenMetrics format.

Parameters:

  • out - Output writer
  • in - Metric family to write
  • options - Encoder options

Returns: (int, error) - Bytes written, error

Example:

written, err := expfmt.MetricFamilyToOpenMetrics(os.Stdout, metricFamily, expfmt.WithCreatedLines())

FinalizeOpenMetrics

func FinalizeOpenMetrics(w io.Writer) (written int, err error)

Writes the OpenMetrics EOF marker ("# EOF\n") to finalize the output.

Parameters:

  • w - Output writer

Returns: (int, error) - Bytes written, error

Example:

// After writing all metric families
expfmt.FinalizeOpenMetrics(writer)

Sample Extraction Functions

ExtractSamples

func ExtractSamples(o *DecodeOptions, fams ...*dto.MetricFamily) (model.Vector, error)

Extracts samples from metric families into a model.Vector.

Parameters:

  • o - Decode options (can be nil)
  • fams - Metric families to extract from

Returns: (model.Vector, error) - Samples, error

Example:

samples, err := expfmt.ExtractSamples(nil, metricFamily1, metricFamily2)

Text Parser Functions

NewTextParser

func NewTextParser(nameValidationScheme model.ValidationScheme) TextParser

Creates a new text format parser with the specified name validation scheme.

Parameters:

  • nameValidationScheme - Validation scheme for metric names

Returns: TextParser

Example:

parser := expfmt.NewTextParser(model.UTF8Validation)
families, err := parser.TextToMetricFamilies(reader)

Usage Examples

Parsing Text Format Metrics

package main

import (
    "fmt"
    "strings"

    "github.com/prometheus/common/expfmt"
    "github.com/prometheus/common/model"
)

const metrics = `
# HELP http_requests_total Total HTTP requests
# TYPE http_requests_total counter
http_requests_total{method="GET",status="200"} 1234
http_requests_total{method="POST",status="200"} 567
`

func main() {
    parser := expfmt.NewTextParser(model.UTF8Validation)
    families, err := parser.TextToMetricFamilies(strings.NewReader(metrics))
    if err != nil {
        panic(err)
    }

    for name, family := range families {
        fmt.Printf("Metric: %s\n", name)
        fmt.Printf("  Type: %s\n", family.GetType())
        fmt.Printf("  Help: %s\n", family.GetHelp())
        fmt.Printf("  Metrics: %d\n", len(family.GetMetric()))
    }
}

Decoding with Decoder Interface

package main

import (
    "fmt"
    "io"
    "os"

    dto "github.com/prometheus/client_model/go"
    "github.com/prometheus/common/expfmt"
)

func main() {
    file, err := os.Open("metrics.txt")
    if err != nil {
        panic(err)
    }
    defer file.Close()

    format := expfmt.NewFormat(expfmt.TypeTextPlain)
    decoder := expfmt.NewDecoder(file, format)

    for {
        var mf dto.MetricFamily
        if err := decoder.Decode(&mf); err != nil {
            if err == io.EOF {
                break
            }
            panic(err)
        }

        fmt.Printf("Family: %s (%s)\n", mf.GetName(), mf.GetType())
        for _, m := range mf.GetMetric() {
            fmt.Printf("  Metric: %v\n", m)
        }
    }
}

Encoding Metrics

package main

import (
    "os"

    dto "github.com/prometheus/client_model/go"
    "github.com/prometheus/common/expfmt"
)

func main() {
    // Create a metric family
    metricFamily := &dto.MetricFamily{
        Name: strPtr("example_metric"),
        Type: metricTypePtr(dto.MetricType_GAUGE),
        Help: strPtr("An example metric"),
        Metric: []*dto.Metric{
            {
                Label: []*dto.LabelPair{
                    {Name: strPtr("label"), Value: strPtr("value")},
                },
                Gauge: &dto.Gauge{Value: float64Ptr(42.0)},
            },
        },
    }

    // Encode as text format
    format := expfmt.NewFormat(expfmt.TypeTextPlain)
    encoder := expfmt.NewEncoder(os.Stdout, format)
    encoder.Encode(metricFamily)
}

func strPtr(s string) *string                  { return &s }
func float64Ptr(f float64) *float64            { return &f }
func metricTypePtr(t dto.MetricType) *dto.MetricType { return &t }

Content Negotiation

package main

import (
    "fmt"
    "net/http"

    "github.com/prometheus/common/expfmt"
)

func metricsHandler(w http.ResponseWriter, r *http.Request) {
    // Negotiate format based on Accept header
    format := expfmt.Negotiate(r.Header)

    // Set response content type
    w.Header().Set("Content-Type", string(format))

    // Create encoder
    encoder := expfmt.NewEncoder(w, format)

    // Encode metrics...
    // encoder.Encode(metricFamily)
}

func main() {
    http.HandleFunc("/metrics", metricsHandler)
    http.ListenAndServe(":9090", nil)
}

OpenMetrics with Options

package main

import (
    "os"

    dto "github.com/prometheus/client_model/go"
    "github.com/prometheus/common/expfmt"
)

func main() {
    format, _ := expfmt.NewOpenMetricsFormat("1.0.0")

    encoder := expfmt.NewEncoder(
        os.Stdout,
        format,
        expfmt.WithCreatedLines(),
        expfmt.WithUnit(),
    )

    // Encode metric families
    // encoder.Encode(metricFamily)

    // Finalize OpenMetrics output
    if closer, ok := encoder.(expfmt.Closer); ok {
        closer.Close()
    }
}

Extracting Samples

package main

import (
    "fmt"
    "strings"

    "github.com/prometheus/common/expfmt"
    "github.com/prometheus/common/model"
)

func main() {
    parser := expfmt.NewTextParser(model.UTF8Validation)
    families, err := parser.TextToMetricFamilies(strings.NewReader(metricsText))
    if err != nil {
        panic(err)
    }

    // Convert map to slice
    var familySlice []*dto.MetricFamily
    for _, family := range families {
        familySlice = append(familySlice, family)
    }

    // Extract samples
    opts := &expfmt.DecodeOptions{
        Timestamp: model.Now(),
    }
    samples, err := expfmt.ExtractSamples(opts, familySlice...)
    if err != nil {
        panic(err)
    }

    for _, sample := range samples {
        fmt.Printf("%s %v @ %v\n", sample.Metric, sample.Value, sample.Timestamp)
    }
}

HTTP Client with Format Detection

package main

import (
    "fmt"
    "io"
    "net/http"

    dto "github.com/prometheus/client_model/go"
    "github.com/prometheus/common/expfmt"
)

func scrapeMetrics(url string) error {
    resp, err := http.Get(url)
    if err != nil {
        return err
    }
    defer resp.Body.Close()

    // Detect format from response headers
    format := expfmt.ResponseFormat(resp.Header)
    fmt.Printf("Detected format: %s\n", format)

    // Decode metrics
    decoder := expfmt.NewDecoder(resp.Body, format)

    for {
        var mf dto.MetricFamily
        if err := decoder.Decode(&mf); err != nil {
            if err == io.EOF {
                break
            }
            return err
        }

        fmt.Printf("Scraped: %s\n", mf.GetName())
    }

    return nil
}

func main() {
    scrapeMetrics("http://localhost:9090/metrics")
}

Writing OpenMetrics with EOF

package main

import (
    "os"

    dto "github.com/prometheus/client_model/go"
    "github.com/prometheus/common/expfmt"
)

func main() {
    format, _ := expfmt.NewOpenMetricsFormat("1.0.0")
    encoder := expfmt.NewEncoder(os.Stdout, format)

    // Write multiple metric families
    for _, mf := range getMetricFamilies() {
        encoder.Encode(mf)
    }

    // Write EOF marker
    expfmt.FinalizeOpenMetrics(os.Stdout)
}

func getMetricFamilies() []*dto.MetricFamily {
    // Return your metric families
    return nil
}

SampleDecoder Usage

package main

import (
    "fmt"
    "strings"

    dto "github.com/prometheus/client_model/go"
    "github.com/prometheus/common/expfmt"
    "github.com/prometheus/common/model"
)

func main() {
    format := expfmt.NewFormat(expfmt.TypeTextPlain)
    decoder := expfmt.NewDecoder(strings.NewReader(metricsText), format)

    sampleDecoder := &expfmt.SampleDecoder{
        Dec: decoder,
        Opts: &expfmt.DecodeOptions{
            Timestamp: model.Now(),
        },
    }

    var samples model.Vector
    if err := sampleDecoder.Decode(&samples); err != nil {
        panic(err)
    }

    for _, sample := range samples {
        fmt.Printf("%s{%s} => %v\n",
            sample.Metric[model.MetricNameLabel],
            sample.Metric,
            sample.Value)
    }
}

Format Types Summary

Text Format (0.0.4)

  • Content-Type: text/plain; version=0.0.4; charset=utf-8
  • Human-readable text format
  • Line-based protocol
  • Most widely supported

Protocol Buffer Formats

  • Delimited: application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited
  • Compact: Binary protobuf format
  • More efficient than text format
  • Requires protobuf library

OpenMetrics

  • Content-Type: application/openmetrics-text; version=1.0.0; charset=utf-8
  • Standardized evolution of Prometheus text format
  • Supports additional metadata (_created, exemplars, etc.)
  • Version 1.0.0 is current standard

Notes

Format Negotiation

When implementing a metrics endpoint, use Negotiate or NegotiateIncludingOpenMetrics to automatically select the best format based on the client's Accept header.

EOF Marker for OpenMetrics

OpenMetrics format requires an EOF marker. Always call FinalizeOpenMetrics or use the encoder's Close method after writing all metrics.

Streaming

Decoders and encoders support streaming - they process one metric family at a time, which is memory-efficient for large metric sets.

Thread Safety

Encoders and decoders are not thread-safe. Create separate instances for concurrent use.