Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion kiosk_show_replacement/metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@

metrics_bp = Blueprint("metrics", __name__)

# Content type for the Prometheus text exposition format, version 0.0.4.
# The ``version`` parameter is required: Prometheus v3 fails a scrape whose
# Content-Type carries no recognized format version, where v2 silently fell
# back to this format. This is the same value as prometheus_client's
# ``CONTENT_TYPE_LATEST``.
PROMETHEUS_CONTENT_TYPE = "text/plain; version=0.0.4; charset=utf-8"


class MetricsCollector:
"""Thread-safe metrics collector for Prometheus-style metrics."""
Expand Down Expand Up @@ -504,7 +511,9 @@ def metrics_endpoint() -> Response:
# Add summary metrics
output += "\n" + get_summary_metrics()

return Response(output, mimetype="text/plain; charset=utf-8")
# Use content_type rather than mimetype: Werkzeug appends its own
# charset to a mimetype, which would duplicate the parameter here.
return Response(output, content_type=PROMETHEUS_CONTENT_TYPE)


# Convenience functions for recording metrics from other modules
Expand Down
13 changes: 13 additions & 0 deletions tests/unit/test_metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"""

from kiosk_show_replacement.metrics import (
PROMETHEUS_CONTENT_TYPE,
MetricsCollector,
metrics_collector,
record_database_error,
Expand All @@ -28,6 +29,18 @@ def test_metrics_endpoint_returns_text_plain(self, app, client):
response = client.get("/metrics")
assert "text/plain" in response.content_type

def test_metrics_endpoint_declares_exposition_format_version(self, app, client):
"""Test the Content-Type names the Prometheus 0.0.4 text format.

Prometheus v3 fails a scrape whose Content-Type carries no recognized
format version, so the ``version`` parameter must be present, and the
header must not repeat ``charset``.
"""
response = client.get("/metrics")

assert response.content_type == "text/plain; version=0.0.4; charset=utf-8"
assert response.content_type == PROMETHEUS_CONTENT_TYPE

def test_metrics_contains_http_requests_help(self, app, client):
"""Test metrics output contains HTTP requests metric definition."""
response = client.get("/metrics")
Expand Down
Loading