operator: quiet BootstrapMaintainer per-tick log churn (follow-up to #530)
- Dominant language
- Go
- Stars
- 28
- Forks
- 11
- Avg merge
- 1d 8h
- Merged PRs (30d)
- 55
Description
### Summary
The unbounded-operator's `BootstrapMaintainer` reapplies its owned resources every tick (default 1 minute) and logs each apply at `Info`, producing steady log churn even when nothing changes. Surfaced during review of #530 (PR comment on `internal/operator/namespace.go`).
Per tick the maintainer currently emits ~14 `Info` lines:
- `bootstrap.go` `applyCRDsFromFS`: `"applied CRD"` once per CRD = 12 (`RequiredCRDNames`),
- `bootstrap.go` `bootstrapCRDs`: `"CRDs installed and established"` = 1 (`appliedCount` is always > 0),
- `namespace.go` `BootstrapNamespace`: `"applied system namespace"` = 1 (added in #530).
### Why the obvious fix does not work as-is
Lowering these to `V(1)` does **not** quiet them today. `cmd/unbounded-operator/main.go:143` hard-codes `zap.New(zap.UseDevMode(true))`, and dev mode sets the effective zap level to Debug. controller-runtime maps logr `V(n)` to zap level `-n`, so `V(1)` (level `-1`) is still enabled; only `V(2)+` is suppressed. The existing `internal/operator/migrate.go` `V(1)` "routine" logs (`"ensured secret copied"`, `"reaped legacy component resources"`, etc.) print for the same reason.
### Options
1. **Startup vs maintenance.** Thread a signal through `BootstrapAll` -> `BootstrapNamespace`/`bootstrapCRDs` so the startup call logs applies at `Info` while the `BootstrapMaintainer` tick is quiet (suppress, or use `V(2)` which is suppressed under dev mode). Config-independent; keeps first-install/startup visibility; covers CRDs and namespace.
2. **Make the operator log level configurable.** Bind `zap.Options` flags / default to production `Info` so `V(1)` becomes a real quiet lever operator-wide, then lower routine logs (bootstrap + `migrate.go`) to `V(1)`. Broader: changes default encoder (console -> JSON) and level; affects log parsing/ops. Likely its own PR / a "new default behavior" decision.
3. **Change-aware logging.** Log at `Info` only when an apply actually creates/mutates the object. Cleanest semantics; easy for the namespace (compare the 4 labels), awkward for the 12 CRDs (per-CRD `Get`/resourceVersion compare each tick).
### Acceptance criteria
- [ ] A steady-state `BootstrapMaintainer` tick (nothing changed) produces no per-apply `Info` churn.
- [ ] Startup / first install still logs a clear confirmation at `Info`.
- [ ] The chosen approach is consistent across the namespace and CRD bootstrap paths (and, if the logger is touched, the `migrate.go` routine logs).
- [ ] `make fmt`, `make lint`, `go test ./internal/operator/... ./cmd/unbounded-operator/...` pass.
### References
- #530 (introduced the namespace bootstrap log; review comment raised the churn).
- `internal/operator/bootstrap.go` (`applyCRDsFromFS`, `bootstrapCRDs`), `internal/operator/namespace.go` (`BootstrapNamespace`), `cmd/unbounded-operator/main.go:143` (hard-coded dev-mode logger).
Contributor guide
Research direction
Read internal/operator/bootstrap.go and namespace.go, then inspect cmd/unbounded-operator/main.go:143 and the routine logs in internal/operator/migrate.go. Compare the startup and BootstrapMaintainer paths and choose a consistent way to avoid steady-state per-apply Info churn while retaining startup confirmation. Run make fmt, make lint, and go test ./internal/operator/... ./cmd/unbounded-operator/... to verify the acceptance criteria.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go, kubernetes
- Domain
- infrastructure, observability
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100