Kuadrant / Kuadrant/kuadrant-console-plugin
PlanPolicy View: Metrics Tab with Perses Panels
- Dominant language
- TypeScript
- Stars
- 10
- Forks
- 65
- Avg merge
- 2d 8h
- Merged PRs (30d)
- 44
Description
## Context
Add a Metrics tab to the PlanPolicy details page showing per-tier rate limiting metrics using embedded Perses panels. This answers: "Which tiers are hitting limits? Should I adjust tier quotas?"
Depends on the shared Perses infrastructure established in #220.
## Requirements
### New Metrics tab
Add a `console.tab/horizontalNav` on `PlanPolicy` (`extensions.kuadrant.io/v1alpha1`):
- Tab name: "Metrics"
- Tab href: `metrics`
**Panels:**
| Panel | Metric | Panel Type |
|-------|--------|-----------|
| Rejections by Tier | `sum(rate(limited_calls{limitador_namespace="/", limit_name=~"gold\|silver\|bronze"}[5m])) by (limit_name)` | TimeSeriesChart stacked by tier |
| Total Authorized Traffic | `sum(rate(authorized_calls{limitador_namespace="/"}[5m]))` | TimeSeriesChart |
| Overall Rejection Rate | `sum(rate(limited_calls{limitador_namespace="/"}[5m])) / (sum(rate(authorized_calls{limitador_namespace="/"}[5m])) + sum(rate(limited_calls{limitador_namespace="/"}[5m]))) * 100` | GaugeChart |
| Rejections per Tier | `sum(rate(limited_calls{limitador_namespace="/", limit_name=""}[5m]))` per tier | StatChart (one per tier) |
**Controls:**
- Time range selector: 15m, 1h, 6h, 24h, 7d (default: 1h)
### How PlanPolicy maps to Limitador metrics
PlanPolicy generates a child RateLimitPolicy with one limit entry per tier. The tier name becomes the `limit_name` in Limitador (e.g. `gold`, `silver`, `bronze`). This label is only available on `limited_calls` and only when Limitador is configured with `telemetry: exhaustive`:
```bash
kubectl patch limitador limitador -n kuadrant-system --type='merge' -p='{"spec":{"telemetry":"exhaustive"}}'
```
### Limitations
- **Per-tier authorized traffic is not available.** `authorized_calls` aggregates all tiers under the same `limitador_namespace`. Only rejections (`limited_calls`) can be broken down by tier via `limit_name`.
- **No per-consumer metrics.** Consumer-to-tier assignment is not reflected in Limitador metrics unless custom labels are added via TelemetryPolicy.
### Limitador namespace scoping
The `limitador_namespace` label format is `"{k8s_namespace}/{route_name}"`. The target HTTPRoute's namespace and name must be resolved from the PlanPolicy's generated RateLimitPolicy `targetRef`.
Tier names should be dynamically read from the PlanPolicy's `spec.plans[].tier` field rather than hardcoded.
### Empty states
- No plan data: "No plan metrics available. Metrics will appear once traffic flows through tiers defined by this policy."
- Exhaustive telemetry not enabled: "Per-tier breakdown requires Limitador exhaustive telemetry to be enabled."
- Prometheus unavailable: shared `EmptyMetricsState` component from #220
## Notes
- Requires React 18 upgrade (OCP 4.22+ only)
- Extension policies (PlanPolicy) are not tracked by `kuadrant_policies_total` / `kuadrant_policies_enforced`
Contributor guide
Research direction
Start at the PlanPolicy console extension and review the shared Perses infrastructure established in #220. Trace how the generated RateLimitPolicy targetRef resolves the HTTPRoute namespace and name, and how spec.plans[].tier supplies tier names. Done means a Metrics tab renders the specified panels, controls, empty states, and dynamic tier breakdown without hardcoded tiers.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- kubernetes, prometheus, react, typescript
- Domain
- frontend, observability
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100