Emit Prometheus 0.0.4 format version in /metrics Content-Type - #29
Merged
jantman merged 1 commit intoSep 20, 2026
Merged
Conversation
The /metrics endpoint returned `Content-Type: text/plain; charset=utf-8`, with no exposition format version. Prometheus v2 tolerated that and fell back to the 0.0.4 text format, but Prometheus v3 fails the scrape outright when the Content-Type carries no recognized format version. This surfaced during the DecaturMakers monitoring stack's v2 -> v3 upgrade, where the `kiosk` scrape job needed a `fallback_scrape_protocol` shim to keep working. The endpoint now sets `text/plain; version=0.0.4; charset=utf-8`, matching prometheus_client's CONTENT_TYPE_LATEST, as a new module-level PROMETHEUS_CONTENT_TYPE constant. Two notes on the implementation: - The issue suggested importing CONTENT_TYPE_LATEST from prometheus_client. This module hand-builds its exposition text and has no prometheus_client registry, so `generate_latest(registry)` does not apply without rewriting the whole collector. Rather than add a runtime dependency solely for a string constant, the value is defined locally with a comment recording that it is the same value. - The response is now built with `content_type=` instead of `mimetype=`. Werkzeug appends its own charset to a mimetype, so passing the full value as a mimetype produced a duplicated parameter -- the previous code was in fact emitting `text/plain; charset=utf-8; charset=utf-8`. Adds a test asserting the exact Content-Type header. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XAhg2bNjxS9PMFUtTVT1J
There was a problem hiding this comment.
Claude Code review
From Claude, via the Claude PR Review workflow -- hence github-actions[bot].
This PR fixes /metrics to emit Content-Type: text/plain; version=0.0.4; charset=utf-8 (via a new PROMETHEUS_CONTENT_TYPE constant and content_type= instead of mimetype=) so Prometheus v3 accepts the scrape, and adds a unit test asserting the exact header value. Four independent review passes (two CLAUDE.md compliance, two bug/security/logic) found no issues — the change is small, correct, and well-tested.
No issues found. Checked for bugs and CLAUDE.md compliance.
🔎 2m 17s · 11 turns · $0.6320 · run log
jantman
deleted the
robot-army/issue-26-metrics-endpoint-should-set-content
branch
September 20, 2026 15:25
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #26.
Problem
/metricsreturnedContent-Type: text/plain; charset=utf-8, with no exposition format version. Prometheus v2 tolerated that and silently fell back to the 0.0.4 text format; Prometheus v3 fails the scrape outright when the Content-Type names no recognized format version.Change
kiosk_show_replacement/metrics.pynow responds withtext/plain; version=0.0.4; charset=utf-8, held in a new module-levelPROMETHEUS_CONTENT_TYPEconstant.Two deviations from the fix sketched in the issue, both deliberate:
prometheus_clientdependency. The issue suggestedResponse(generate_latest(registry), mimetype=CONTENT_TYPE_LATEST). This module hand-builds its exposition text and has noprometheus_clientregistry at all, sogenerate_latest()does not apply without rewriting the whole collector — well beyond what the issue asks for. Adding a runtime dependency solely to import a string constant did not seem worth it, so the value is defined locally with a comment recording that it is identical toCONTENT_TYPE_LATEST.content_type=instead ofmimetype=. Werkzeug appends its own charset to amimetype, so passing the full value there duplicates the parameter. Worth noting: the previous code hit this too and was actually emittingtext/plain; charset=utf-8; charset=utf-8.Verification
New unit test asserts the exact header value.
Full backend suite: 687 passed, 1 skipped.
nox -s format/lint/type_checkall clean (mypy: no issues in 36 files).Checked against a running dev server:
Not covered here
The issue's remaining two checkboxes are dm-puppet changes and live-infrastructure steps that belong in that repository, not this one:
dmpuppet::internals::kiosk_showtagfallback_scrape_protocol: PrometheusText0.0.4from thekioskjob inprometheus.yml, then confirm the target still scrapes on Prometheus v3Those should follow once this merges and an image is cut.
🤖 Generated with Claude Code
https://claude.ai/code/session_019XAhg2bNjxS9PMFUtTVT1J