Spaces:
Paused
Paused
Peng Ding commited on
Commit ·
dfb4f0e
1
Parent(s): 12e389a
fix: address metrics review — real p50, seconds, _sum/_count
Browse files- Add p50_ms to EndpointStats via shared _percentile() helper
- Use real p50 instead of avg for quantile="0.5" (avg ≠ median)
- Rename metric to _seconds with values in seconds (Prometheus convention)
- Add _sum and _count lines to summary for rate() query support
- Rename cache_total → cache_lookups_total for clarity
- src/veilrender/routes/metrics.py +16 -9
- src/veilrender/stats.py +13 -4
src/veilrender/routes/metrics.py
CHANGED
|
@@ -55,29 +55,36 @@ def _build_metrics() -> str:
|
|
| 55 |
|
| 56 |
# Counters — cache
|
| 57 |
lines = [
|
| 58 |
-
"# HELP
|
| 59 |
-
"# TYPE
|
| 60 |
]
|
| 61 |
for name, ep in _ENDPOINTS:
|
| 62 |
lines.append(
|
| 63 |
-
f'
|
| 64 |
)
|
| 65 |
lines.append(
|
| 66 |
-
f'
|
| 67 |
)
|
| 68 |
parts.append("".join(lines))
|
| 69 |
|
| 70 |
-
# Latency
|
| 71 |
lines = [
|
| 72 |
-
"# HELP
|
| 73 |
-
"# TYPE
|
| 74 |
]
|
| 75 |
for name, ep in _ENDPOINTS:
|
|
|
|
| 76 |
lines.append(
|
| 77 |
-
f'
|
| 78 |
)
|
| 79 |
lines.append(
|
| 80 |
-
f'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 81 |
)
|
| 82 |
parts.append("".join(lines))
|
| 83 |
|
|
|
|
| 55 |
|
| 56 |
# Counters — cache
|
| 57 |
lines = [
|
| 58 |
+
"# HELP veilrender_cache_lookups_total Cache lookups by endpoint and result.\n",
|
| 59 |
+
"# TYPE veilrender_cache_lookups_total counter\n",
|
| 60 |
]
|
| 61 |
for name, ep in _ENDPOINTS:
|
| 62 |
lines.append(
|
| 63 |
+
f'veilrender_cache_lookups_total{{endpoint="{name}",result="hit"}} {ep.cache_hits}\n'
|
| 64 |
)
|
| 65 |
lines.append(
|
| 66 |
+
f'veilrender_cache_lookups_total{{endpoint="{name}",result="miss"}} {ep.cache_misses}\n'
|
| 67 |
)
|
| 68 |
parts.append("".join(lines))
|
| 69 |
|
| 70 |
+
# Latency — summary with quantiles, _sum, _count
|
| 71 |
lines = [
|
| 72 |
+
"# HELP veilrender_request_duration_seconds Request latency in seconds.\n",
|
| 73 |
+
"# TYPE veilrender_request_duration_seconds summary\n",
|
| 74 |
]
|
| 75 |
for name, ep in _ENDPOINTS:
|
| 76 |
+
count = ep.successes + ep.failures
|
| 77 |
lines.append(
|
| 78 |
+
f'veilrender_request_duration_seconds{{endpoint="{name}",quantile="0.5"}} {ep.p50_ms / 1000:.6f}\n'
|
| 79 |
)
|
| 80 |
lines.append(
|
| 81 |
+
f'veilrender_request_duration_seconds{{endpoint="{name}",quantile="0.95"}} {ep.p95_ms / 1000:.6f}\n'
|
| 82 |
+
)
|
| 83 |
+
lines.append(
|
| 84 |
+
f'veilrender_request_duration_seconds_sum{{endpoint="{name}"}} {ep.total_ms / 1000:.6f}\n'
|
| 85 |
+
)
|
| 86 |
+
lines.append(
|
| 87 |
+
f'veilrender_request_duration_seconds_count{{endpoint="{name}"}} {count}\n'
|
| 88 |
)
|
| 89 |
parts.append("".join(lines))
|
| 90 |
|
src/veilrender/stats.py
CHANGED
|
@@ -43,15 +43,24 @@ class EndpointStats:
|
|
| 43 |
total = self.successes + self.failures
|
| 44 |
return self.total_ms / total if total > 0 else 0.0
|
| 45 |
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
"""95th percentile latency in milliseconds."""
|
| 49 |
if not self._latencies:
|
| 50 |
return 0.0
|
| 51 |
sorted_lat = sorted(self._latencies)
|
| 52 |
-
idx = int(len(sorted_lat) *
|
| 53 |
return sorted_lat[min(idx, len(sorted_lat) - 1)]
|
| 54 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 55 |
@property
|
| 56 |
def success_rate(self) -> float:
|
| 57 |
"""Success rate as a percentage."""
|
|
|
|
| 43 |
total = self.successes + self.failures
|
| 44 |
return self.total_ms / total if total > 0 else 0.0
|
| 45 |
|
| 46 |
+
def _percentile(self, q: float) -> float:
|
| 47 |
+
"""Compute a percentile from the latency window."""
|
|
|
|
| 48 |
if not self._latencies:
|
| 49 |
return 0.0
|
| 50 |
sorted_lat = sorted(self._latencies)
|
| 51 |
+
idx = int(len(sorted_lat) * q)
|
| 52 |
return sorted_lat[min(idx, len(sorted_lat) - 1)]
|
| 53 |
|
| 54 |
+
@property
|
| 55 |
+
def p50_ms(self) -> float:
|
| 56 |
+
"""50th percentile (median) latency in milliseconds."""
|
| 57 |
+
return self._percentile(0.50)
|
| 58 |
+
|
| 59 |
+
@property
|
| 60 |
+
def p95_ms(self) -> float:
|
| 61 |
+
"""95th percentile latency in milliseconds."""
|
| 62 |
+
return self._percentile(0.95)
|
| 63 |
+
|
| 64 |
@property
|
| 65 |
def success_rate(self) -> float:
|
| 66 |
"""Success rate as a percentage."""
|