Skip to content

KSM 2.8.0 can't be scraped by Prometheus if Native Histograms is enabled #2022

@Joseph-Irving

Description

@Joseph-Irving

What happened:
Starting from version 2.8.0, if Prometheus is started with --enable-feature=native-histograms flag it fails to scrape KSM, instead erroring with the error:

proto: wrong wireType = 0 for field Metric

What you expected to happen:
KSM should be able to be scraped by Prometheus

How to reproduce it (as minimally and precisely as possible):
I can reproduce this just on minikube with the standard helm prometheus, chart https://github.com/prometheus-community/helm-charts/tree/main/charts/prometheus

helm install prometheus prometheus-community/prometheus --set server.extraFlags={"enable-feature=native-histograms"\,"log.level=debug"} --version=19.7.2

This deploys kube-state-metrics version: registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.8.0
And Prometheus version: quay.io/prometheus/prometheus:v2.41.0
With the --enable-feature=native-histograms set.

Anything else we need to know?:
The problem was introduced in this PR #1974

I think the issue, is that when you enable Native Histograms, Prometheus is sending headers with a content type of:

content type: %v application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited

Which we're then mirroring in our headers:

resHeader.Set("Content-Type", string(contentType))

But we're not actually changing our response so we're replying with invalid protobuf hence the error from Prometheus.

I did this as a simple workaround and it fixed the issue:

if contentType == expfmt.FmtProtoDelim {
    resHeader.Set("Content-Type", `text/plain; version=`+"0.0.4")
} else {
    resHeader.Set("Content-Type", string(contentType))
}

However I'm not sure this is the right approach, is it intended that kube-state-metrics always responds with content headers that match the request? Or was this just a change for Open Metrics? In which case perhaps the header should only get changed if the contentType == expfmt.FmtOpenMetric? e.g reverse the logic, only change the headers if we detect open metrics headers:

if contentType == expfmt.FmtOpenMetrics {
   resHeader.Set("Content-Type", string(contentType))
} else {
   resHeader.Set("Content-Type", `text/plain; version=`+"0.0.4")
}

That way the code would behave the same as it did prior to 2.8.0 if the open metrics headers are not present.

Environment:

  • kube-state-metrics version: 2.8.0
  • Kubernetes version (use kubectl version): 1.26.1
  • Cloud provider or hardware configuration: n/a
  • Other info:

Metadata

Metadata

Assignees

No one assigned

    Labels

    kind/bugCategorizes issue or PR as related to a bug.needs-triageIndicates an issue or PR lacks a `triage/foo` label and requires one.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions