ObolNetwork / ObolNetwork/obol-stack
refactor: introduce slog for operational logging, keep ui.UI for presentation
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 11
- Forks
- 1
- PR merge metrics
- No merged PRs in 30d
Description
Context
The codebase currently has two output channels:
ui.UI(356 calls) — CLI presentation layer with colors, spinners, prompts, JSON mode, TTY detection (34 methods)log.*(99 calls) — server binaries (x402-verifier, x402-buyer) using stdlib log
These work well for their respective contexts. The gap appears when internal helpers (e.g., fixVolumeOwnership) need to report operational warnings — they currently require threading *ui.UI through the entire call chain even though they have no presentation concerns.
Problem
There's a semantic mismatch between two types of output:
| Type | Example | Right channel |
|---|---|---|
| Presentation | "Wallet generated ✓", spinner, prompt | ui.UI |
| Operational | "chown failed for /data/x: permission denied" | Should be slog |
Today both go through ui.UI, which means:
- Presentation layer leaks into deep internals
- Every function in the chain needs
*ui.UIeven if it only warns on failure - Server binaries can't share internal packages that use
ui.UI
Proposal
Introduce log/slog (stdlib since Go 1.21, project requires 1.25+) as the operational logging backbone:
CLI (cmd/obol/main.go)
// Pretty handler for human-friendly terminal output
slog.SetDefault(slog.New(newPrettyHandler(os.Stderr, verbose)))
Server binaries (cmd/x402-verifier/, cmd/x402-buyer/)
// Structured JSON handler for container logs
slog.SetDefault(slog.New(slog.NewJSONHandler(os.Stderr, nil)))
Internal helpers
// No *ui.UI threading needed — just call slog
func fixVolumeOwnership(cfg *config.Config, hostPath string) {
if err := cmd.Run(); err != nil {
slog.Warn("chown failed", "path", hostPath, "err", err)
}
}
Keep ui.UI for
u.Success(),u.Info()— user-facing status messagesu.RunWithSpinner()— progress indicatorsu.Confirm(),u.Select()— interactive promptsu.JSON()— structured output mode
When to do this
This becomes important when:
- The ServiceOffer controller (#296) lands and shares internal packages with CLI code
- Server binaries need to share code from
internal/that currently requires*ui.UI - Observability requirements grow (structured log aggregation, field-based filtering)
Not urgent today — the ui.UI threading approach works. This is a future improvement.
Scope
- Add
internal/logging/with pretty handler (CLI) and JSON handler (servers) - Migrate
log.Printfin server binaries →slog.* - Migrate operational warnings in internals (e.g.,
fixVolumeOwnership) →slog.Warn - Keep all 356+
u.*calls for presentation output - Document "when to use slog vs ui.UI" in CLAUDE.md
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with cmd/obol/main.go, cmd/x402-verifier/, cmd/x402-buyer/, and the proposed internal/logging/ package. Review existing log.Printf calls, operational warnings such as fixVolumeOwnership, and the ui.UI usage before defining handler setup. Done means server logs use slog, internal operational warnings no longer require *ui.UI, presentation calls remain unchanged, and the slog-versus-ui.UI guidance is documented in CLAUDE.md.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- observability
- Issue type
- Refactor
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100