package utils import ( "io" "log/slog" "os" "time" ) // Logger provides structured logging capabilities type Logger struct { *slog.Logger } // NewLogger creates a new structured logger func NewLogger() *Logger { return NewLoggerWithOutput(os.Stdout) } // NewDebugLogger creates a new logger with debug level enabled func NewDebugLogger() *Logger { opts := &slog.HandlerOptions{ Level: slog.LevelDebug, ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr { // Customize timestamp format if a.Key == slog.TimeKey { return slog.Attr{ Key: a.Key, Value: slog.StringValue(time.Now().Format("2006-01-02 15:04:05")), } } return a }, } handler := slog.NewTextHandler(os.Stdout, opts) logger := slog.New(handler) return &Logger{Logger: logger} } // NewLoggerWithOutput creates a new logger with custom output func NewLoggerWithOutput(w io.Writer) *Logger { opts := &slog.HandlerOptions{ Level: slog.LevelInfo, ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr { // Customize timestamp format if a.Key == slog.TimeKey { return slog.Attr{ Key: a.Key, Value: slog.StringValue(time.Now().Format("2006-01-02 15:04:05")), } } return a }, } handler := slog.NewTextHandler(w, opts) logger := slog.New(handler) return &Logger{Logger: logger} } // NewSilentLogger creates a logger that discards all output func NewSilentLogger() *Logger { return NewLoggerWithOutput(io.Discard) } // WithComponent adds a component context to the logger func (l *Logger) WithComponent(component string) *Logger { return &Logger{Logger: l.Logger.With("component", component)} } // WithRequestID adds a request ID context to the logger func (l *Logger) WithRequestID(requestID string) *Logger { return &Logger{Logger: l.Logger.With("request_id", requestID)} } // Fatal logs a fatal error and exits the program func (l *Logger) Fatal(msg string, args ...interface{}) { l.Error(msg, args...) os.Exit(1) }