76 lines
2.4 KiB
Go
76 lines
2.4 KiB
Go
package cat
|
|
|
|
import (
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"sync"
|
|
)
|
|
|
|
// LogSink, when set by the host app at startup, receives every CAT debug
|
|
// line so they land in the unified app log (opslog.log) alongside the rest
|
|
// of OpsLog's diagnostics. Until it's wired we fall back to a dedicated
|
|
// cat.log file so early-startup lines aren't lost.
|
|
var LogSink func(format string, args ...any)
|
|
|
|
// catLogger forwards Printf either to the host LogSink (preferred) or to a
|
|
// local file/stderr fallback. Keeps the call sites (debugLog.Printf(...))
|
|
// unchanged.
|
|
type catLogger struct {
|
|
once sync.Once
|
|
fallback *log.Logger
|
|
}
|
|
|
|
func (c *catLogger) Printf(format string, args ...any) {
|
|
if LogSink != nil {
|
|
LogSink("cat: "+format, args...)
|
|
return
|
|
}
|
|
// Only now, on a line that genuinely has nowhere else to go, is the fallback
|
|
// file opened. It used to be created at package init, so every installation
|
|
// grew an %APPDATA%\OpsLog\cat.log that nothing ever wrote to once the app
|
|
// wired LogSink — a decoy for anyone told to "check the CAT log".
|
|
c.once.Do(func() { c.fallback = openFallbackLog() })
|
|
if c.fallback != nil {
|
|
c.fallback.Printf(format, args...)
|
|
}
|
|
}
|
|
|
|
// debugLog writes CAT debug events so users can diagnose mode/freq mismatches
|
|
// without rebuilding with a console. Once LogSink is set, lines flow into the
|
|
// main opslog.log.
|
|
var debugLog = &catLogger{}
|
|
|
|
func openFallbackLog() *log.Logger {
|
|
base, err := os.UserConfigDir()
|
|
if err != nil {
|
|
return log.Default()
|
|
}
|
|
dir := filepath.Join(base, "OpsLog")
|
|
if err := os.MkdirAll(dir, 0o755); err != nil {
|
|
return log.Default()
|
|
}
|
|
f, err := os.OpenFile(filepath.Join(dir, "cat.log"),
|
|
os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644)
|
|
if err != nil {
|
|
return log.Default()
|
|
}
|
|
return log.New(f, "", log.LstdFlags|log.Lmicroseconds)
|
|
}
|
|
|
|
// DebugLogPath returns where the fallback cat.log lives, or "" when CAT lines are
|
|
// going to the app log instead — which is the normal case, and the answer callers
|
|
// actually need. It previously returned the path unconditionally, so the one place
|
|
// that displayed it sent operators to an empty file in %APPDATA% while their CAT
|
|
// diagnostics sat in data\opslog.log.
|
|
func DebugLogPath() string {
|
|
if LogSink != nil {
|
|
return "" // lines go to the unified app log; there is no separate cat.log
|
|
}
|
|
base, err := os.UserConfigDir()
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
return filepath.Join(base, "OpsLog", "cat.log")
|
|
}
|