90 lines
2.3 KiB
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)
|
|
}
|