package simplelog import ( "context" "fmt" "log/slog" "os" "runtime" "time" "github.com/fatih/color" ) // callerSkipFrames is the number of stack frames between runtime.Caller // and the slog call site that produced the record. const callerSkipFrames = 4 // ConsoleHandler writes human-readable, colored log lines to stdout. type ConsoleHandler struct{} // NewConsoleHandler returns a new ConsoleHandler. func NewConsoleHandler() *ConsoleHandler { return &ConsoleHandler{} } // Handle writes the record to stdout as a colored, timestamped line // including the caller file and line. func (c *ConsoleHandler) Handle( _ context.Context, record slog.Record, ) error { timestamp := time.Now().UTC().Format("2006-01-02T15:04:05.000Z07:00") var colorFunc func(format string, a ...any) string switch record.Level { case slog.LevelDebug: colorFunc = color.New(color.FgWhite).SprintfFunc() case slog.LevelInfo: colorFunc = color.New(color.FgBlue).SprintfFunc() case slog.LevelWarn: colorFunc = color.New(color.FgYellow).SprintfFunc() case slog.LevelError: colorFunc = color.New(color.FgRed).SprintfFunc() default: colorFunc = color.New(color.FgWhite).SprintfFunc() } // Get the caller information _, file, line, ok := runtime.Caller(callerSkipFrames) if !ok { file = "???" line = 0 } _, _ = fmt.Fprintln( os.Stdout, colorFunc( "%s [%s] %s:%d: %s", timestamp, record.Level, file, line, record.Message, ), ) return nil } // Enabled reports whether the handler processes records at the given // level; it always returns true. func (c *ConsoleHandler) Enabled( _ context.Context, _ slog.Level, ) bool { return true } // WithAttrs returns the handler unchanged; attributes are not rendered. func (c *ConsoleHandler) WithAttrs(_ []slog.Attr) slog.Handler { return c } // WithGroup returns the handler unchanged; groups are not rendered. func (c *ConsoleHandler) WithGroup(_ string) slog.Handler { return c }