restructured logger from budigt
This commit is contained in:
parent
358ee6acc0
commit
b2fd12b1c8
11 changed files with 1227 additions and 1 deletions
124
logger.go
Normal file
124
logger.go
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
package splinter
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"maps"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Logger fans out log records to one or more Streams. Streams are fixed at
|
||||
// construction time; child loggers from With share the same streams.
|
||||
type Logger struct {
|
||||
streams []Stream
|
||||
baseAttrs map[string]any
|
||||
onError func(stream string, rec Record, err error)
|
||||
}
|
||||
|
||||
// Option configures a Logger.
|
||||
type Option func(*Logger)
|
||||
|
||||
// WithStream adds a Stream to the logger.
|
||||
func WithStream(s Stream) Option {
|
||||
return func(l *Logger) { l.streams = append(l.streams, s) }
|
||||
}
|
||||
|
||||
// WithAttrs pre-populates attributes on every record produced by this logger.
|
||||
func WithAttrs(attrs map[string]any) Option {
|
||||
return func(l *Logger) { maps.Copy(l.baseAttrs, attrs) }
|
||||
}
|
||||
|
||||
// WithErrorHandler sets a callback invoked when a stream's Write fails.
|
||||
// The default handler prints to stderr.
|
||||
func WithErrorHandler(fn func(stream string, rec Record, err error)) Option {
|
||||
return func(l *Logger) { l.onError = fn }
|
||||
}
|
||||
|
||||
// New creates a Logger. With no streams supplied, a JSON ConsoleStream at
|
||||
// LevelInfo writing to stderr is used.
|
||||
func New(opts ...Option) *Logger {
|
||||
l := &Logger{
|
||||
baseAttrs: make(map[string]any),
|
||||
onError: defaultOnError,
|
||||
}
|
||||
for _, o := range opts {
|
||||
o(l)
|
||||
}
|
||||
if len(l.streams) == 0 {
|
||||
l.streams = append(l.streams, NewConsoleStream(ConsoleJSON, LevelInfo))
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// With returns a child Logger with additional attributes merged onto the
|
||||
// base. The child shares streams and the error handler with the parent.
|
||||
func (l *Logger) With(attrs map[string]any) *Logger {
|
||||
merged := make(map[string]any, len(l.baseAttrs)+len(attrs))
|
||||
maps.Copy(merged, l.baseAttrs)
|
||||
maps.Copy(merged, attrs)
|
||||
return &Logger{
|
||||
streams: l.streams,
|
||||
baseAttrs: merged,
|
||||
onError: l.onError,
|
||||
}
|
||||
}
|
||||
|
||||
// Debug logs at LevelDebug.
|
||||
func (l *Logger) Debug(msg string, args ...any) { l.log(LevelDebug, msg, args...) }
|
||||
|
||||
// Info logs at LevelInfo.
|
||||
func (l *Logger) Info(msg string, args ...any) { l.log(LevelInfo, msg, args...) }
|
||||
|
||||
// Warn logs at LevelWarn.
|
||||
func (l *Logger) Warn(msg string, args ...any) { l.log(LevelWarn, msg, args...) }
|
||||
|
||||
// Error logs at LevelError.
|
||||
func (l *Logger) Error(msg string, args ...any) { l.log(LevelError, msg, args...) }
|
||||
|
||||
// Close shuts down all streams. Returns the first error encountered, but
|
||||
// always attempts to close every stream.
|
||||
func (l *Logger) Close() error {
|
||||
var firstErr error
|
||||
for _, s := range l.streams {
|
||||
if err := s.Close(); err != nil && firstErr == nil {
|
||||
firstErr = err
|
||||
}
|
||||
}
|
||||
return firstErr
|
||||
}
|
||||
|
||||
func (l *Logger) log(level Level, msg string, args ...any) {
|
||||
rec := Record{
|
||||
Time: time.Now(),
|
||||
Level: level,
|
||||
Message: msg,
|
||||
Attrs: l.buildAttrs(args),
|
||||
}
|
||||
ctx := context.Background()
|
||||
for _, s := range l.streams {
|
||||
if !s.Enabled(level) {
|
||||
continue
|
||||
}
|
||||
if err := s.Write(ctx, rec); err != nil {
|
||||
l.onError(s.Name(), rec, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger) buildAttrs(args []any) map[string]any {
|
||||
attrs := make(map[string]any, len(l.baseAttrs)+len(args)/2)
|
||||
maps.Copy(attrs, l.baseAttrs)
|
||||
for i := 0; i+1 < len(args); i += 2 {
|
||||
key, ok := args[i].(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
attrs[key] = args[i+1]
|
||||
}
|
||||
return attrs
|
||||
}
|
||||
|
||||
func defaultOnError(stream string, _ Record, err error) {
|
||||
fmt.Fprintf(os.Stderr, "splinter: stream %q write failed: %v\n", stream, err)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue