Skip to content

expfmt: NegotiateIncludingOpenMetrics makes it hard to select the first supported format when a server supports only a subset of formats #928

Description

@adziauho

NegotiateIncludingOpenMetrics (in https://github.com/prometheus/common/blob/main/expfmt/encode.go) returns the single highest-quality format from the Accept header. If a server does not support that format, there is no straightforward way to fall back to the next
recognised format from the client's preference list — the caller would have to reimplement the entire negotiation loop manually.

Example

A server that supports OpenMetrics and text/plain but not protobuf receives:

Accept: application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=delimited;q=0.6,                                                                                                                                                                  
          application/openmetrics-text;version=1.0.0;escaping=allow-utf-8;q=0.5,                                                                                                                                                                                             
          text/plain;version=0.0.4;q=0.2                   

NegotiateIncludingOpenMetrics returns FmtProtoDelim. The server cannot serve it, but has no API to ask "what is the next format the client accepts that I can serve?" — the only escape hatch today is an unconditional fallback to FmtText, ignoring
application/openmetrics-text which both sides support.

Suggested fix

Add a companion function to expfmt/encode.go, leaving NegotiateIncludingOpenMetrics unchanged:

// NegotiateFormatsIncludingOpenMetrics works like NegotiateIncludingOpenMetrics                                                                                                                                                                                           
// but returns all recognised formats from the Accept header in descending                                                                                                                                                                                                 
// preference order instead of stopping at the first match. If no recognised                                                                                                                                                                                               
// formats are found, the slice contains FmtText as the default fallback.                                                                                                                                                                                                  
func NegotiateFormatsIncludingOpenMetrics(h http.Header) []Format      

The caller can then iterate and pick the first format it supports, without reimplementing the negotiation loop.

This is useful fix to a content negotiation bug in kube-state-metrics (kubernetes/kube-state-metrics#3010).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions