feat(#13): expose Prometheus metrics via /metrics endpoint - #14
feat(#13): expose Prometheus metrics via /metrics endpoint#14fullsend-ai-coder[bot] wants to merge 3 commits into
Conversation
Add prometheus_client instrumentation to the Flask app with before_request/after_request hooks that track: - http_requests_total (Counter): request count per method, endpoint, and HTTP status code - http_request_duration_seconds (Histogram): request duration per method and endpoint, enabling average calculation via sum/count - http_request_duration_max_seconds (Gauge): maximum observed request duration per method and endpoint - http_request_duration_min_seconds (Gauge): minimum observed request duration per method and endpoint The /metrics endpoint itself is excluded from instrumentation to avoid recursive inflation of counters. Added prometheus_client>=0.20 to requirements.txt and pyproject.toml. Added 7 new tests covering the metrics endpoint response, request counting, duration tracking, status code labels, min/max gauges, and the /metrics exclusion behavior. Closes #13
ReviewFindingsLow
Previous runReviewFindingsMedium
Low
Previous run (2)ReviewFindingsLow
Previous run (3)ReviewFindingsHigh
Medium
Low
|
|
/fs-fix |
- Fix race condition in min/max gauge updates by using a threading lock and a separate dict for tracking extremes instead of reading private Gauge._value API - Fix unbounded cardinality by using request.url_rule (route template) instead of request.path for the endpoint label - Use a custom CollectorRegistry to avoid exposing process-level collectors via /metrics - Add /metrics endpoint to README endpoints table - Improve min/max test to verify values are positive and min <= max - Replace REGISTRY._names_to_collectors access in test reset with direct metric object references Addresses review feedback on #14 Signed-off-by: fullsend-fix <fullsend-code@users.noreply.github.com>
🔧 Fix agent — iteration 1 (human-triggered)Addressed 7 of 8 review findings. Fixed race condition with threading lock, bounded cardinality via url_rule, isolated metrics via custom registry, added README docs, improved test assertions. Disagreed with /metrics auth requirement as out of scope for this PR. Fixed (7):
Disagreed (1):
Tests: passed Updated by fullsend fix agent |
|
Please move the Prometheus-related code into a separate Python module. |
|
/fs-fix |
Move all Prometheus-related code (registry, metric objects, request hooks, /metrics endpoint) from app.py into a new metrics.py module. The app.py now calls init_metrics(app) to register the instrumentation. Test imports updated accordingly. Addresses human feedback on #14 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: fullsend-fix <fullsend-code@users.noreply.github.com>
🔧 Fix agent — iteration 2 (human-triggered)Moved all Prometheus-related code into a dedicated metrics.py module per human request. All 15 tests pass, lint clean. Fixed (1):
Tests: passed Updated by fullsend fix agent |
|
/fs-review |
|
🤖 Finished Review · ✅ Success · Started 11:50 AM UTC · Completed 12:04 PM UTC Commit: |
Superseded by updated review
| """Clear all prometheus metric values between tests.""" | ||
| for metric in _ALL_METRICS: | ||
| metric._metrics.clear() | ||
| _extremes.clear() |
There was a problem hiding this comment.
[low] edge-case
The _reset_collectors function clears metric state by accessing the private _metrics attribute of prometheus_client collector objects (metric._metrics.clear()) and directly imports/clears the private _extremes dict. This internal API is not part of the prometheus_client public contract and could break with a future library version, silently breaking test isolation.
Suggested fix: Consider adding a public reset_metrics() function in metrics.py that encapsulates clearing both the prometheus collectors and _extremes, similar to how reset_items() exists in app.py.
|
|
||
|
|
||
| def _reset_collectors(): | ||
| """Clear all prometheus metric values between tests.""" |
There was a problem hiding this comment.
[low] naming-convention
The _reset_collectors helper function uses an underscore prefix, which is marginally inconsistent with the reset_items() pattern in app.py.
Suggested fix: Consider removing the underscore prefix for consistency, or adding a comment explaining the convention.
| | POST | `/items` | Create an item (`{"name": "..."}`) | | ||
| | PATCH | `/items/:id` | Update an item (`{"done": true}`) | | ||
| | DELETE | `/items/:id` | Delete an item | | ||
| | GET | `/metrics` | Prometheus metrics | |
There was a problem hiding this comment.
[low] missing-doc
The /metrics endpoint is listed in the endpoints table but the README does not describe what specific Prometheus metrics are exposed (http_requests_total, http_request_duration_seconds, etc.) or the new prometheus_client dependency.
Suggested fix: Consider adding a brief note about the available metrics, either inline in the endpoint description or in a short section.
Add prometheus_client instrumentation to the Flask app with before_request/after_request hooks that track:
endpoint, and HTTP status code
per method and endpoint, enabling average calculation via
sum/count
request duration per method and endpoint
request duration per method and endpoint
The /metrics endpoint itself is excluded from instrumentation to avoid recursive inflation of counters.
Added prometheus_client>=0.20 to requirements.txt and pyproject.toml. Added 7 new tests covering the metrics endpoint response, request counting, duration tracking, status code labels, min/max gauges, and the /metrics exclusion behavior.
Closes #13
Post-script verification
agent/13-prometheus-metrics)47f7f1511df8ad7036c082d9b2179085cd9ec107..HEAD)