package logging import ( "fmt" "io" "os" "strings" "github.com/sirupsen/logrus" "git.wxccs.org/iceking2nd/winauth-go/internal/global" ) // Options controls logger initialization from CLI flags. type Options struct { // Level is one of: panic, fatal, error, warn, info, debug, trace. // Numeric forms (0..6) are also accepted to mirror the legacy convention // used in CLAUDE.local.md ("Trace(6)", "Debug(5)"). Level string // File, if non-empty, enables file logging in addition to console output. // The file is opened with append + create semantics. File string // Console forces console output to be visible. On Windows this is the // signal used by the cobra entry point to allocate / show a console // window for a GUI build. The logger itself always writes to stderr; this // field is kept here so that the entry point can read it through the // same Options struct. Console bool } // Init configures the global.Log logger according to opts. // Returns the opened file handle (or nil) so the caller can close it on exit. func Init(opts Options) (io.Closer, error) { const fn = "internal.logging.Init" lvl, err := parseLevel(opts.Level) if err != nil { return nil, err } global.Log.SetLevel(lvl) global.Log.SetFormatter(&logrus.TextFormatter{ FullTimestamp: true, TimestampFormat: "2006-01-02 15:04:05.000", DisableQuote: false, }) var closer io.Closer if strings.TrimSpace(opts.File) != "" { f, ferr := os.OpenFile(opts.File, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644) if ferr != nil { return nil, fmt.Errorf("open log file %q: %w", opts.File, ferr) } global.Log.SetOutput(io.MultiWriter(os.Stderr, f)) closer = f } else { global.Log.SetOutput(os.Stderr) } global.Log.WithField("func", fn). WithField("level", lvl.String()). WithField("file", opts.File). Debug("logger initialized") return closer, nil } // parseLevel accepts either the textual logrus level names or the numeric // 0..6 form used in CLAUDE.local.md. func parseLevel(s string) (logrus.Level, error) { s = strings.TrimSpace(strings.ToLower(s)) if s == "" { return logrus.InfoLevel, nil } switch s { case "0", "panic": return logrus.PanicLevel, nil case "1", "fatal": return logrus.FatalLevel, nil case "2", "error": return logrus.ErrorLevel, nil case "3", "warn", "warning": return logrus.WarnLevel, nil case "4", "info": return logrus.InfoLevel, nil case "5", "debug": return logrus.DebugLevel, nil case "6", "trace": return logrus.TraceLevel, nil } return logrus.InfoLevel, fmt.Errorf("unknown log level %q", s) }