|
|
|
@ -19,47 +19,27 @@ |
|
|
|
|
|
|
|
|
|
|
|
| Pattern | Functions | How | |
|
|
|
| Pattern | Functions | How | |
|
|
|
|---------|------------|-----| |
|
|
|
|---------|------------|-----| |
|
|
|
| Streaming | MarkAllAsDeps, MarkAsExplicit, InstallAUR | `io.MultiWriter` to tee to both terminal and log | |
|
|
|
| Captured | All state-modifying functions | capture output, write to log with single timestamp at start, write to terminal | |
|
|
|
| Captured | SyncPackages, CleanupOrphans | capture with `CombinedOutput()`, write to log, write to terminal | |
|
|
|
|
|
|
|
|
|
|
|
### One Timestamp Per Tool Call |
|
|
|
|
|
|
|
Instead of streaming with MultiWriter (multiple timestamps), each state-modifying function: |
|
|
|
|
|
|
|
1. Writes timestamp + operation name to log |
|
|
|
|
|
|
|
2. Runs command, captures output |
|
|
|
|
|
|
|
3. Writes captured output to log |
|
|
|
|
|
|
|
4. Writes output to terminal |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
This ensures exactly 1 timestamp print per tool call. |
|
|
|
|
|
|
|
|
|
|
|
### Error Handling |
|
|
|
### Error Handling |
|
|
|
- Write error to log BEFORE returning from function |
|
|
|
- Write error to log BEFORE returning from function |
|
|
|
- Print error to stderr so user sees it |
|
|
|
- Print error to stderr so user sees it |
|
|
|
|
|
|
|
|
|
|
|
### Dependencies |
|
|
|
### Dependencies |
|
|
|
- Add to imports: `io`, `os`, `path/filepath` |
|
|
|
- Add to imports: `os`, `path/filepath` |
|
|
|
|
|
|
|
|
|
|
|
### Structure |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```go |
|
|
|
|
|
|
|
// pkg/state/state.go |
|
|
|
|
|
|
|
var logFile *os.File |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func OpenLog() error { |
|
|
|
|
|
|
|
logPath := filepath.Join("/var/log", "declpac.log") |
|
|
|
|
|
|
|
f, err := os.OpenFile(logPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
return err |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
logFile = f |
|
|
|
|
|
|
|
return nil |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func GetLogWriter() io.Writer { |
|
|
|
|
|
|
|
return logFile |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func Close() error { |
|
|
|
|
|
|
|
if logFile == nil { |
|
|
|
|
|
|
|
return nil |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return logFile.Close() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Flow in Sync() or main entrypoint |
|
|
|
### Flow in Sync() or main entrypoint |
|
|
|
1. Call `OpenLog()` at program start, defer close |
|
|
|
1. Call `OpenLog()` at program start, defer close |
|
|
|
2. Each state-modifying function uses `state.GetLogWriter()` via MultiWriter |
|
|
|
2. Each state-modifying function calls `state.Write()` with timestamp prefix |
|
|
|
|
|
|
|
|
|
|
|
### Wire into main.go |
|
|
|
### Wire into main.go |
|
|
|
- Open log at start of `run()` |
|
|
|
- Open log at start of `run()` |
|
|
|
|