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).
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:
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:
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).