sync/utils/logger.go

121 lines
3.0 KiB
Go

package utils
import (
"fmt"
"os"
"path/filepath"
"time"
"github.com/wailsapp/wails/v2/pkg/logger"
)
// multiLogger fans every log call out to multiple logger.Logger targets with timestamps.
type multiLogger struct {
targets []logger.Logger
}
// timestamped prefixes each message with a timestamp.
func timestamped(message string) string {
return time.Now().Format("2006-01-02 15:04:05") + " " + message
}
func (m *multiLogger) Print(message string) {
msg := timestamped(message)
for _, l := range m.targets {
l.Print(msg)
}
}
func (m *multiLogger) Trace(message string) {
msg := timestamped(message)
for _, l := range m.targets {
l.Trace(msg)
}
}
func (m *multiLogger) Debug(message string) {
msg := timestamped(message)
for _, l := range m.targets {
l.Debug(msg)
}
}
func (m *multiLogger) Info(message string) {
msg := timestamped(message)
for _, l := range m.targets {
l.Info(msg)
}
}
func (m *multiLogger) Warning(message string) {
msg := timestamped(message)
for _, l := range m.targets {
l.Warning(msg)
}
}
func (m *multiLogger) Error(message string) {
msg := timestamped(message)
for _, l := range m.targets {
l.Error(msg)
}
}
func (m *multiLogger) Fatal(message string) {
msg := timestamped(message)
for _, l := range m.targets {
l.Fatal(msg)
}
}
// NewRuntimeFileLogger returns a logger that writes all output both to
//
// $XDG_CONFIG_HOME/FanslySync/logs/runtime_latest.log
//
// and to a timestamped file
//
// $XDG_CONFIG_HOME/FanslySync/logs/runtime_YYYY-MM-DD_HH-MM-SS.log
//
// It also deletes any timestamped logs older than 14 days.
//
// The returned logger implements github.com/wailsapp/wails/v2/pkg/logger.Logger
// and will be used by Wails for all Go-side logging.
func NewRuntimeFileLogger() (logger.Logger, error) {
// 1) Ensure log directory exists
cfgDir, err := os.UserConfigDir()
if err != nil {
return nil, fmt.Errorf("cannot determine user config dir: %w", err)
}
logDir := filepath.Join(cfgDir, "FanslySync", "logs")
if err := os.MkdirAll(logDir, 0o755); err != nil {
return nil, fmt.Errorf("cannot create log directory: %w", err)
}
// 2) Prune old timestamped logs (>14 days)
cutoff := time.Now().Add(-14 * 24 * time.Hour)
entries, _ := os.ReadDir(logDir)
for _, e := range entries {
if e.IsDir() || e.Name() == "runtime_latest.log" {
continue
}
info, err := e.Info()
if err != nil {
continue
}
if info.ModTime().Before(cutoff) {
_ = os.Remove(filepath.Join(logDir, e.Name()))
}
}
// 3) Build paths for timestamped + latest
ts := time.Now().Format("2006-01-02_15-04-05")
tsPath := filepath.Join(logDir, fmt.Sprintf("runtime_%s.log", ts))
latestPath := filepath.Join(logDir, "runtime_latest.log")
// 4) Create both loggers
tsLogger := logger.NewFileLogger(tsPath)
latestLogger := logger.NewFileLogger(latestPath)
termLogger := logger.NewDefaultLogger()
// 5) Fan-out into a multiLogger
multi := &multiLogger{
targets: []logger.Logger{tsLogger, latestLogger, termLogger},
}
return multi, nil
}