feat(dashboard): request status code and provider latency charts#501
Conversation
Add a "Requests by Status" stacked bar chart (2xx/4xx/5xx, with an overall success-rate summary) and a "Provider Latency" line chart (average duration of successful uncached requests per provider) to the dashboard's Audit Logs page, backed by a new GET /admin/audit/stats endpoint. Storage backends group audit entries by UTC hour and provider in one query; shared Go code folds the hours into hourly buckets (ranges up to 3 days) or timezone-correct daily buckets (longer ranges), zero-filled up to the current time. Latency series align with the status buckets and keep empty buckets as gaps rather than zeros, and exclude local response-cache hits and failed requests so averages reflect real provider round trips. The demo seed now emits 429s alongside 500s and gives each provider a distinct latency profile so the new charts are legible out of the box. Closes #459 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Warning Review limit reached
Next review available in: 10 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (9)
📝 WalkthroughWalkthroughThis PR adds an admin audit request-statistics feature: a new ChangesAudit Stats Feature
OpenAPI and Documentation Updates
Demo Data Seed Script
Estimated code review effort: 4 (Complex) | ~75 minutes Sequence Diagram(s)sequenceDiagram
participant Client
participant Handler as Handler.AuditStats
participant Reader as auditReader.GetRequestStats
participant Store as Storage backend
Client->>Handler: GET /admin/audit/stats
Handler->>Handler: validate date range, compute interval
Handler->>Reader: GetRequestStats(params)
Reader->>Store: query audit_logs
Store-->>Reader: rows
Reader-->>Handler: RequestStats
Handler-->>Client: JSON RequestStats
sequenceDiagram
participant DashboardJS as dashboard.js
participant AuditStatsModule as audit-stats.js
participant API as /admin/audit/stats
participant ChartJS as Chart.js
DashboardJS->>AuditStatsModule: fetchAuditStats()
AuditStatsModule->>API: GET stats query
API-->>AuditStatsModule: RequestStats JSON
AuditStatsModule->>AuditStatsModule: normalizeAuditStats(payload)
AuditStatsModule->>ChartJS: renderAuditStatsCharts()
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
|
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Actionable comments posted: 4
♻️ Duplicate comments (1)
docs/openapi.json (1)
8511-8530: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick winSame nullable-items gap as
docs.go.OpenAPI 3 supports per-item
"nullable": true, butavg_duration_msitems are declared as plain"type": "number"here too, missing thenullentries the endpoint actually returns for buckets with no successful provider requests. Same root-cause fix as noted oncmd/gomodel/docs/docs.go(regenerate from an updated swaggo annotation onProviderLatencySeries.AvgDurationMs).🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/openapi.json` around lines 8511 - 8530, The schema for auditlog.ProviderLatencySeries still declares avg_duration_ms array items as non-nullable numbers, so update the source OpenAPI generation by fixing the swaggo annotation on ProviderLatencySeries.AvgDurationMs and regenerating docs.go/openapi.json. Make sure the generated schema for avg_duration_ms includes nullable item support so the runtime null values for empty provider buckets are reflected consistently in the OpenAPI output.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@cmd/gomodel/docs/docs.go`:
- Around line 6130-6149: The schema for auditlog.ProviderLatencySeries still
models avg_duration_ms as a plain array of numbers, but
ProviderLatencySeries.AvgDurationMs can contain nil entries. Update the nullable
item annotation in internal/auditlog/stats.go for the AvgDurationMs field so the
generated docs/schema reflect nullable array items instead of number[], and
verify the generated auditlog.ProviderLatencySeries definition picks up the
change.
In `@internal/admin/dashboard/static/js/modules/audit-stats.js`:
- Around line 85-104: The audit bucket label and daily tooltip title are using
browser-local date getters, which can drift from the dashboard’s effective
timezone. Update _auditStatsBucketLabel and the daily branch of
_auditStatsTooltipTitle to use the same timezone-aware formatting path as
formatTimestamp(bucket.start), instead of deriving day/hour from new
Date(bucket.start). Keep the midnight marker and short-date behavior, but base
both on the dashboard timezone so labels stay consistent.
In `@internal/admin/handler_audit_stats_test.go`:
- Around line 39-52: Add a test that combines a nil audit reader with an invalid
start_date to verify the documented validation order in AuditStats. Extend the
existing coverage around TestAuditStats_InvalidDate and TestAuditStats_NilReader
by adding a new case that constructs NewHandler without WithAuditReader, calls
h.AuditStats with an invalid query, and asserts a 400 response before any
disabled-reader fast path can short-circuit. Keep the assertions focused on the
bad date validation path so the ordering guarantee in AuditStats stays locked
in.
In `@internal/auditlog/stats_test.go`:
- Around line 75-78: The average-duration assertion in stats_test.go uses an
exact float comparison between a constant-folded expected value and a
runtime-computed value, which can diverge by a last bit. Update the test around
the AvgDurationMs check to use a tolerance-based comparison instead of `!=`, and
keep the existing `stats.Summary.AvgDurationMs` and `wantAvg` references so the
assertion remains clear and stable.
---
Duplicate comments:
In `@docs/openapi.json`:
- Around line 8511-8530: The schema for auditlog.ProviderLatencySeries still
declares avg_duration_ms array items as non-nullable numbers, so update the
source OpenAPI generation by fixing the swaggo annotation on
ProviderLatencySeries.AvgDurationMs and regenerating docs.go/openapi.json. Make
sure the generated schema for avg_duration_ms includes nullable item support so
the runtime null values for empty provider buckets are reflected consistently in
the OpenAPI output.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 802a69e4-17fa-4854-a979-8a2ef7e40309
📒 Files selected for processing (22)
cmd/gomodel/docs/docs.godocs/advanced/admin-endpoints.mdxdocs/openapi.jsoninternal/admin/dashboard/static/css/dashboard.cssinternal/admin/dashboard/static/js/dashboard.jsinternal/admin/dashboard/static/js/modules/audit-stats.jsinternal/admin/dashboard/static/js/modules/audit-stats.test.cjsinternal/admin/dashboard/static/js/modules/usage.jsinternal/admin/dashboard/templates/layout.htmlinternal/admin/dashboard/templates/page-audit-logs.htmlinternal/admin/handler_audit.gointernal/admin/handler_audit_stats_test.gointernal/admin/handler_test.gointernal/admin/routes.gointernal/admin/routes_test.gointernal/auditlog/reader.gointernal/auditlog/stats.gointernal/auditlog/stats_mongodb.gointernal/auditlog/stats_postgresql.gointernal/auditlog/stats_sqlite.gointernal/auditlog/stats_test.gotools/seed-demo-data.sh
…eview Move the "Requests by Status" and "Provider Latency" charts from the Audit Logs page to the Overview page, right before Providers Overview, so error rates, provider latency, and provider availability read as one health block. The audit page keeps its log and filters for drill-down; both pages share the same date picker. Review feedback: - Bucket labels and daily tooltips now format in the dashboard's effective timezone (the same X-GoModel-Timezone the server buckets by) instead of the browser locale. - Lock in validation-before-nil-reader ordering with a dedicated test. - Compare the folded average duration with a tolerance instead of exact float equality. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Activity card only spaces itself upward, so the Requests by Status card sat flush against it. Give the audit-stats sections their own top margin (collapsing between the two charts), scoped so the usage page's 20px filter gap stays untouched. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Closes #459
What
Two new charts on the dashboard's Overview page, placed right before Providers Overview so error rates, provider latency, and provider availability read as one health block (they follow the shared date-range picker):
Both are powered by a new admin endpoint:
GET /admin/audit/stats?days=|start_date=&end_date=— time-bucketed status-class counts, a success-rate summary, and per-provider latency series. Ranges up to 3 days use hourly buckets; longer ranges use daily buckets aligned to the dashboard timezone. Buckets are zero-filled up to the current time.How
foldRequestStats) folds hours into hourly or timezone-correct daily buckets, so daily bucketing stays right across DST without per-backend timezone SQL.LOGGING_ENABLED=falsethe endpoint returns an empty result and the page looks unchanged.tools/seed-demo-data.sh) now emits 429s alongside 500s and gives each provider a distinct latency profile so the charts are legible out of the box.User-visible impact
GET /admin/audit/stats(swagger/openapi regenerated, docs page updated).LOGGING_ENABLED=true) to show data.Tests
foldRequestStatsunit tests (hour/day intervals, DST-safe local-day folding, zero-fill truncation at "now", latency gap semantics, tolerance-based float comparison) and a SQLite reader integration test.🤖 Generated with Claude Code