verstak/cmd/verstak-gui/bindings_logging.go

90 lines
2.3 KiB
Go

package main
import (
"fmt"
"log"
"os"
"path/filepath"
"time"
"verstak/internal/core/config"
)
// appLogPath returns the path to the application log file.
// Uses ~/.local/state/verstak/logs/verstak.log on Linux,
// or falls back to ~/.config/verstak/logs/verstak.log.
func appLogPath() string {
// Prefer XDG_STATE_HOME, then fallback to config dir
stateDir := os.Getenv("XDG_STATE_HOME")
if stateDir == "" {
home, err := os.UserHomeDir()
if err == nil {
stateDir = filepath.Join(home, ".local", "state")
}
}
if stateDir != "" {
dir := filepath.Join(stateDir, "verstak", "logs")
if err := os.MkdirAll(dir, 0o755); err == nil {
return filepath.Join(dir, "verstak.log")
}
}
// Fallback to config dir
cfgDir, err := config.EnsureConfigDir()
if err != nil {
return ""
}
dir := filepath.Join(cfgDir, "logs")
if err := os.MkdirAll(dir, 0o755); err != nil {
return ""
}
return filepath.Join(dir, "verstak.log")
}
// appLog writes a timestamped line to the application log file.
func appLog(level, msg string) {
logPath := appLogPath()
if logPath == "" {
log.Printf("[%s] %s", level, msg)
return
}
line := fmt.Sprintf("[%s] [%s] %s\n", time.Now().Format("2006-01-02T15:04:05"), level, msg)
f, err := os.OpenFile(logPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644)
if err != nil {
log.Printf("[%s] %s", level, msg)
return
}
defer f.Close()
f.WriteString(line)
}
// FrontendLog receives log messages from the frontend runtime.
// Called from JS via Wails binding. Works even if vault is not open.
// level: "info", "warn", "error"
// message: human-readable message
// stack: JS stack trace (optional, only for errors)
func (a *App) FrontendLog(level, message, stack string) {
msg := "[frontend] " + message
if stack != "" {
msg += "\n stack: " + stack
}
// Always log to Go's standard logger (visible in dev mode console)
log.Printf("[frontend][%s] %s", level, message)
// Persist to log file
appLog("frontend-"+level, msg)
}
// LogStartupStep logs a startup diagnostic step.
// Called from Go side to trace initialization progress.
func (a *App) LogStartupStep(step string, success bool, detail string) {
status := "ok"
if !success {
status = "fail"
}
msg := fmt.Sprintf("[startup] %s: %s", step, status)
if detail != "" {
msg += " — " + detail
}
log.Print(msg)
appLog("startup", msg)
}