// Package logger provides structured logging with slog. package logger import ( "log/slog" "os" "go.uber.org/fx" "git.eeqj.de/sneak/upaas/internal/globals" ) // Params contains dependencies for Logger. type Params struct { fx.In Globals *globals.Globals } // Logger wraps slog.Logger with level control. type Logger struct { log *slog.Logger level *slog.LevelVar params Params } // New creates a new Logger with TTY detection for output format. func New(_ fx.Lifecycle, params Params) (*Logger, error) { loggerInstance := &Logger{ level: new(slog.LevelVar), params: params, } loggerInstance.level.Set(slog.LevelInfo) // TTY detection for dev vs prod output isTTY := detectTTY() var handler slog.Handler if isTTY { // Text output for development handler = slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{ Level: loggerInstance.level, AddSource: true, }) } else { // JSON output for production handler = slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ Level: loggerInstance.level, AddSource: true, }) } loggerInstance.log = slog.New(handler) return loggerInstance, nil } func detectTTY() bool { fileInfo, err := os.Stdout.Stat() if err != nil { return false } return (fileInfo.Mode() & os.ModeCharDevice) != 0 } // Get returns the underlying slog.Logger. func (l *Logger) Get() *slog.Logger { return l.log } // EnableDebugLogging sets the log level to debug. func (l *Logger) EnableDebugLogging() { l.level.Set(slog.LevelDebug) l.log.Debug("debug logging enabled", "debug", true) } // Identify logs application startup information. func (l *Logger) Identify() { l.log.Info("starting", "appname", l.params.Globals.Appname, "version", l.params.Globals.Version, "buildarch", l.params.Globals.Buildarch, ) }