// Package slogtime provides an alternative [slog.Logger] implementation that // allows using custom [time.Now] function for log records. // // It also has a smaller API surface that requires using explicit [slog.Level], // [context.Context] and [slog.Attr]s.
package slogtime import ( ) // Logger is an alternative implementation of [slog.Logger] that allows // customizing the time source for log records. // // Unlike [slog.Logger], Logger does not provide convenience methods like // Info, Debug, Warn, or Error. Instead, all logging is done through the // Log method with explicit level, context, and attributes. type Logger struct { handler slog.Handler now func() time.Time } // New creates a new [Logger] that uses the given handler and time function. // If now is nil, [time.Now] will be used when logging. func ( slog.Handler, func() time.Time) *Logger { if == nil { = time.Now } return &Logger{ handler: , now: , } } // clone returns a copy of the Logger. func ( *Logger) () *Logger { := * return & } // Handler returns the underlying [slog.Handler]. func ( *Logger) () slog.Handler { return .handler } // Enabled reports whether l emits log records at the given context and level. func ( *Logger) ( context.Context, slog.Level) bool { return .handler.Enabled(, ) } // With returns a [Logger] that includes the given attributes in each output // operation. Arguments are converted to attributes as if by [Logger.Log]. func ( *Logger) ( ...slog.Attr) *Logger { if len() == 0 { return } := .clone() .handler = .handler.WithAttrs() return } // WithGroup returns a [Logger] that starts a group. The keys of all attributes // added to the [Logger] will be qualified by the given name. func ( *Logger) ( string) *Logger { if == "" { return } := .clone() .handler = .handler.WithGroup() return } // WithTime returns a [Logger] that uses the given time function. // If now is nil, [time.Now] will be used. func ( *Logger) ( func() time.Time) *Logger { if == nil { = time.Now } := .clone() .now = return } // Log emits a log record with the given level, message, and attributes. // The record includes a source location obtained from the call stack. func ( *Logger) ( context.Context, slog.Level, string, ...slog.Attr, ) { if !.Enabled(, ) { return } var [1]uintptr runtime.Callers(3, [:]) := slog.NewRecord(.now(), , , [0]) .AddAttrs(...) _ = .handler.Handle(, ) }