Logging strategy: unify output and execution logging #76
Copy link
Copy link
Closed
Labels
Area:ArchitectureSystem architecture and designSystem architecture and designClaudeJudgmentError:DesignDefectArchitectural issues that should have been caughtArchitectural issues that should have been caught
Description
Summary
The codebase has multiple logging/output mechanisms that need a unified strategy.
Current State
1. CLI Output Functions (internal/cli/output.go)
User-facing messages to stderr, respects --silent:
cli.Note("message") // [program] [+] message
cli.Warn("message") // [program] [△] message
cli.Error("message") // [program] [✖] message
cli.Success("message") // [program] [✔] message
cli.Failure("message") // [program] [✖] message + returns error2. Execution Logger (ctx.Logger io.Writer)
Operations log to an injected writer during graph execution:
fmt.Fprintf(ctx.Logger, "[dry-run] %s install %s\n", pm.Name(), pkg)
fmt.Fprintf(ctx.Logger, "[package] %s install %s\n", pm.Name(), pkg)
fmt.Fprintf(ctx.Logger, "[service] launchctl start %s\n", service)Files: internal/execution/ops_package.go, internal/execution/ops_service.go
3. Starlark Bindings Output (b.output io.Writer)
Starlark phases log to an output writer:
fmt.Fprintf(b.output, " [package] Installing %s\n", name)
fmt.Fprintf(b.output, " [shell] %s\n", command)
fmt.Fprintf(b.output, " [note] %s\n", msg)
fmt.Fprintf(b.output, " [warn] %s\n", msg)File: internal/starlark/bindings.go
4. Audit Logs (s.audit io.Writer)
Security-sensitive operations logged as JSON:
fmt.Fprintln(s.audit, result.JSON())Files: internal/shell/shell.go, internal/pwsh/pwsh.go
Problems
- No log levels - Can't filter by debug/info/warn/error
- Inconsistent format -
[dry-run],[package],[service],[shell]prefixes vary - No structured option - Can't output JSON logs for machine parsing
- Starlark duplicates cli -
[note],[warn],[ERROR]in starlark vs cli.Note/Warn/Error - Execution logs bypass cli - ctx.Logger writes don't respect
--silent - No verbosity control -
-vflag doesn't affect execution logs
Strategy Options
Option A: Minimal - Standardize Format Only
- Keep current architecture
- Standardize all log prefixes to
[category]format - Ensure execution logger respects
--silent - Lowest effort, doesn't solve log levels
Option B: Log Levels via Interface
- Define a Logger interface with Debug/Info/Warn/Error methods
- Replace
ctx.Logger io.Writerwithctx.Logger Logger - CLI commands set log level based on
-vand--silent - Medium effort, solves verbosity control
Option C: Unified Logger Abstraction
- Create a central Logger that wraps cli.Note/Warn/Error/Success
- All logging goes through this abstraction
- Supports log levels, respects --silent, consistent format
- Higher effort, cleanest architecture
Option D: Structured Logging (slog)
- Use Go 1.21+
log/slogpackage - Supports both text and JSON output
- Built-in log levels
- Can emit structured logs for observability
- Highest effort, best for long-term
Recommendation
Option B (Log Levels via Interface) balances effort vs benefit:
- Solves verbosity control (
-v,--silent) - Doesn't require rewriting all logging calls
- Can evolve to Option C or D later
Files to Consider
internal/cli/output.go- existing CLI output functionsinternal/execution/operation.go- Context with Loggerinternal/execution/ops_package.go- package operation logsinternal/execution/ops_service.go- service operation logsinternal/starlark/bindings.go- starlark output
Acceptance Criteria
- Decide on logging strategy
- Implement chosen approach
- All execution logs respect
--silent - Verbose mode (
-v) shows more detail - Format is consistent across all log sources
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
Area:ArchitectureSystem architecture and designSystem architecture and designClaudeJudgmentError:DesignDefectArchitectural issues that should have been caughtArchitectural issues that should have been caught
Activity
David-Noble-at-work commentedon Feb 6, 2026
Additional Finding: Config/CLI Verbosity Mismatch
The config schema defines a shared
verbosityoption that is never read by the code.Config Schema (
devlore-config.json)What Code Actually Reads
What's Missing
verbosity: quietshould setcli.SetSilent(true)verbosity: verboseshould enable verbose modeRecommendation
Connect the config
verbosityoption to the CLI behavior ininitConfig():This is an error in judgment - we defined a config option but never implemented it.
David-Noble-at-work commentedon Mar 11, 2026
Closing — logging is now unified through cli.Note/Warn/Error/Success. The separate ctx.Logger, b.output, and s.audit mechanisms described in this issue no longer exist. Remaining work (log levels, --verbosity control, structured logging) is blocked by #77 and can be tracked there.
chore(docs): Architecture status audit, bug triage, GitHub issue anal…