Six declared Prometheus metrics are never observed and publish a permanent zero
- Dominant language
- Go
- Stars
- 28
- Forks
- 11
- Avg merge
- 1d 8h
- Merged PRs (30d)
- 55
Description
Found while working #670. Not a dead-code deletion: these are a reporting gap.
Six `promauto` variables are declared, self-register at package `init`, and are never observed anywhere in the tree. Each one publishes a series that is permanently zero for every scrape, which reads as "measured, and the answer is none" rather than "not measured".
| Variable | Series | Declared at |
|---|---|---|
| `GatewayPoolRoutesGauge` | `unbounded_cni_controller_gateway_pool_routes_total{pool}` | `internal/net/controller/metrics.go:87` |
| `CRDEnsureDuration` | `unbounded_cni_controller_crd_ensure_duration_seconds{crd}` | `internal/net/controller/metrics.go:96` |
| `CRDEnsureErrors` | `unbounded_cni_controller_crd_ensure_errors_total{crd}` | `internal/net/controller/metrics.go:103` |
| `ECMPRoutesInstalled` | `unbounded_cni_node_ecmp_routes_installed` | `internal/net/netlink/metrics.go:82` |
| `MasqueradeRules` | `unbounded_cni_node_masquerade_rules{family}` | `internal/net/netlink/metrics.go:91` |
| `MasqueradeSyncErrors` | `unbounded_cni_node_masquerade_sync_errors_total` | `internal/net/netlink/metrics.go:104` |
## Why this is worse than an unused variable
`promauto.New*` registers with the default registerer as a side effect of the package's `init`. The variable having no reader does not make the metric absent; it makes it present and wrong. A dashboard panel or an alert expression built against `unbounded_cni_node_masquerade_sync_errors_total` gets a clean zero forever, which is indistinguishable from a healthy node and is the failure mode you would least want from an errors counter.
The Help strings describe measurements that would be genuinely useful: masquerade rule counts by address family, masquerade sync errors, installed ECMP route counts, CRD ensure latency and errors, routes per gateway pool.
## Why they are not in #670
`make deadcode` reports all six under `unreferenced`, and the obvious reading is "delete them". Deleting is the wrong fix twice over: it removes names from the published scrape surface that external dashboards may already reference, and it discards the intent rather than completing it. The dead-code sweep therefore left them alone deliberately, and they are the whole of what that report still flags outside documented keeps.
## The work
For each metric, either add the observation at the site the Help string describes, or delete it as a deliberate reduction of the metric surface with a note in the release notes. The two paths differ per metric and should be decided per metric:
- The masquerade pair has an obvious home in `internal/net/netlink/masquerade_manager.go`, which already does the sync whose rules and errors these count.
- `ECMPRoutesInstalled` has one in `UnifiedRouteManager` alongside the existing route accounting.
- The CRD pair belongs wherever the controller ensures CRDs at startup.
- `GatewayPoolRoutesGauge` belongs in the gateway pool controller.
Whichever way each goes, `make deadcode` should end up clean for these six.
Contributor guide
Research direction
Start with the six declarations in internal/net/controller/metrics.go and internal/net/netlink/metrics.go, then trace the indicated sites: masquerade_manager.go, UnifiedRouteManager, CRD startup ensuring, and the gateway pool controller. For each metric, determine whether its Help string can be observed there or whether it should be deliberately removed with a release-note entry. Run make deadcode and verify these six are no longer reported.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go, prometheus
- Domain
- observability
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100