Skip to content

Migrate Vigilante logging to log/slog #321

@nicobistolfi

Description

@nicobistolfi

Summary

Vigilante currently implements daemon logging through custom printf-style helpers such as state.AppendDaemonLog and environment.LoggingRunner.Logf instead of Go's standard log/slog package. Replace the custom daemon logging path with log/slog so new logging code uses the standard Go logging model while preserving the current local operator workflows and log outputs that Vigilante already depends on.

Problem

  • The daemon log path is built around ad hoc string formatting and file append helpers rather than Go's standard structured logging API.
  • Logging behavior is spread across internal/app/app.go, internal/environment/environment.go, and internal/state/state.go, which makes logging semantics harder to evolve consistently.
  • The current approach makes it harder to attach structured fields, centralize formatting decisions, and align new code with standard Go logging practices.
  • This matters now because logging is an operational surface for Vigilante, and continuing to expand a custom logging abstraction will increase maintenance cost and inconsistency.

Context

  • The current daemon logger is wired in New() by passing store.AppendDaemonLog into environment.LoggingRunner.Logf.
  • Daemon logs are written to ~/.vigilante/logs/vigilante.log.
  • Vigilante also writes a structured subprocess access log to ~/.vigilante/logs/access.jsonl; that existing access-log workflow should remain usable after this change.
  • vigilante logs is already documented and used as the operator entry point for reading daemon, access, and per-issue logs.
  • Existing tests assert against current logging behavior in internal/environment/environment_test.go, internal/state/state_test.go, and multiple internal/app/app_test.go cases.

Desired Outcome

  • Replace the custom daemon logging capability with a log/slog-based implementation that becomes the standard logging path inside the codebase.
  • Keep the current local log destinations and operator workflows working:
    • daemon log remains available through ~/.vigilante/logs/vigilante.log
    • access log remains available through ~/.vigilante/logs/access.jsonl
    • vigilante logs continues to surface the expected files
  • Preserve the practical diagnostic value of current log events such as command start, command success, command failure, scan lifecycle, dispatch lifecycle, and recovery actions.
  • Do not expand this issue into a broader telemetry redesign, analytics schema change, or a rewrite of unrelated session state persistence.

Implementation Notes

  • Introduce a repository-level logging abstraction around *slog.Logger instead of passing raw func(format string, args ...any) callbacks.
  • Update environment.LoggingRunner to emit log records through slog with structured attributes rather than preformatted strings.
  • Replace state.AppendDaemonLog as the primary daemon logging entry point with a slog-compatible handler/writer that still targets ~/.vigilante/logs/vigilante.log.
  • Preserve human-readable daemon logs for operators. Using slog does not require switching the daemon log file to JSON if a text handler is the better fit for local troubleshooting.
  • Keep the access log behavior explicit. If access logging remains JSONL and separate from the daemon logger, document that boundary clearly in code and tests.
  • Minimize churn in higher-level app logic by centralizing compatibility shims where necessary instead of scattering one-off formatting glue throughout the codebase.
  • Required: standardize new daemon logging on log/slog.
  • Flexible: whether the final daemon log format uses slog.TextHandler directly or a custom handler layered on slog, as long as the result is coherent and preserves operator usefulness.

Acceptance Criteria

  • Vigilante's main daemon logging path uses Go's log/slog instead of the current custom printf-style logging callback pattern.
  • Command lifecycle logging in environment.LoggingRunner is emitted through slog with structured fields for at least command, directory, outcome, and error state where applicable.
  • ~/.vigilante/logs/vigilante.log is still produced and remains readable for operators using vigilante logs.
  • The structured access log at ~/.vigilante/logs/access.jsonl continues to work, or any intentional format change is explicitly justified, implemented consistently, and reflected in docs and tests.
  • Existing tests covering logging are updated to assert the new slog-based behavior without losing coverage for failure and success cases.
  • Documentation that describes local logging behavior is updated if user-visible log format or guarantees change.

Testing Expectations

  • Update unit tests for internal/environment/environment.go to validate slog-based command logging behavior.
  • Update state/logging tests to cover the new daemon log writer or handler implementation.
  • Run the relevant Go test suites at minimum for ./internal/environment, ./internal/state, and any impacted ./internal/app coverage.
  • Cover regressions where logs silently stop being written, command failures lose useful context, or vigilante logs no longer surfaces the expected daemon or access log files.

Operational / UX Considerations

  • Preserve backward-compatible local troubleshooting workflows as much as possible; operators should not need a different command just because the implementation moved to slog.
  • Be deliberate about timestamp format, field naming, and readability so the new logger improves consistency without making daemon logs harder to scan.
  • If the daemon log output format changes materially, note that clearly in the README and avoid mixing multiple incompatible formats without a transition plan.

Metadata

Metadata

Assignees

Labels

claudevigilante:doneVigilante completed its work on the issue and no further automation is expected.

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions