diff --git a/src/s5p/metrics.py b/src/s5p/metrics.py index b2bf400..0e019aa 100644 --- a/src/s5p/metrics.py +++ b/src/s5p/metrics.py @@ -67,6 +67,23 @@ class LatencyTracker: "p99": round(ms[min(int(n * 0.99), n - 1)], 1), } + def quantiles(self) -> dict | None: + """Return ``{count, sum, 0.5, 0.95, 0.99}`` in seconds, or None. + + Designed for Prometheus/OpenMetrics summary exposition. + """ + n = len(self._samples) + if n == 0: + return None + s = sorted(self._samples) + return { + "count": n, + "sum": sum(s), + "0.5": s[int(n * 0.50)], + "0.95": s[min(int(n * 0.95), n - 1)], + "0.99": s[min(int(n * 0.99), n - 1)], + } + class Metrics: """Connection metrics. diff --git a/tests/test_metrics.py b/tests/test_metrics.py index e942e6e..dae8e6e 100644 --- a/tests/test_metrics.py +++ b/tests/test_metrics.py @@ -52,6 +52,23 @@ class TestLatencyTracker: assert s["min"] == 500.0 assert s["max"] == 500.0 + def test_quantiles_empty(self): + lt = LatencyTracker() + assert lt.quantiles() is None + + def test_quantiles_seconds(self): + lt = LatencyTracker() + for i in range(1, 101): + lt.record(i / 1000) + q = lt.quantiles() + assert q is not None + assert q["count"] == 100 + assert 0.050 <= q["0.5"] <= 0.052 + assert 0.095 <= q["0.95"] <= 0.097 + assert 0.099 <= q["0.99"] <= 0.101 + assert "sum" in q + assert q["sum"] > 0 + # -- RateTracker -------------------------------------------------------------