From e7796d4d9af049df02bc34ee7d0ed7104f72e23b Mon Sep 17 00:00:00 2001 From: Quentin Burgess Date: Tue, 8 Oct 2024 17:21:01 +0200 Subject: [PATCH 1/7] allow to specify custom string values for level --- slogor.go | 43 +++++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/slogor.go b/slogor.go index af448ae..946c307 100644 --- a/slogor.go +++ b/slogor.go @@ -24,6 +24,8 @@ type Options struct { ShowSource bool // Disable colored output. NoColor bool + + strLvl map[slog.Level]string } type GroupOrAttrs struct { @@ -40,14 +42,35 @@ type Handler struct { goa []GroupOrAttrs // goa for handling group or attributes. } +var defaultLevelStr = map[slog.Level]string{ + slog.LevelDebug: slog.LevelDebug.Level().String() + " ", + slog.LevelInfo: slog.LevelInfo.Level().String(), + slog.LevelWarn: slog.LevelWarn.Level().String() + " ", + slog.LevelError: slog.LevelError.Level().String(), +} + +type OptionFn func(*Options) + +// SetLevelStr set the handler "level to string" map. +// The default one is used if none specified. +func SetLevelStr(strLvl map[slog.Level]string) OptionFn { + return func(options *Options) { options.strLvl = strLvl } +} + // NewHandler creates a Handler that writes to w with the provided options. -func NewHandler(writer io.Writer, options Options) *Handler { - fn := func(buf []byte, color string) []byte { +func NewHandler(writer io.Writer, options Options, fns ...OptionFn) *Handler { + options.strLvl = defaultLevelStr + + clr := func(buf []byte, color string) []byte { return append(buf, color...) } if options.NoColor { - fn = func(buf []byte, color string) []byte { return buf } + clr = func(buf []byte, color string) []byte { return buf } + } + + for _, fn := range fns { + fn(&options) } // Return a new Handler with the provided writer and options. @@ -56,7 +79,7 @@ func NewHandler(writer io.Writer, options Options) *Handler { Writer: writer, Options: options, goa: []GroupOrAttrs{}, - addColorToBuf: fn, + addColorToBuf: clr, } } @@ -118,18 +141,18 @@ func (h *Handler) Handle(_ context.Context, record slog.Record) error { switch record.Level { case slog.LevelInfo: buf = h.addColorToBuf(buf, fgGreen) - buf = append(buf, record.Level.String()...) - buf = append(buf, " "...) case slog.LevelError: buf = h.addColorToBuf(buf, fgRed) - buf = append(buf, record.Level.String()...) case slog.LevelWarn: buf = h.addColorToBuf(buf, fgYellow) - buf = append(buf, record.Level.String()...) - buf = append(buf, " "...) case slog.LevelDebug: buf = h.addColorToBuf(buf, fgMagenta) - buf = append(buf, record.Level.String()...) + } + + if str, ok := h.Options.strLvl[record.Level]; ok { + buf = append(buf, str...) + } else { + buf = append(buf, "-----"...) } buf = append(buf, reset...) -- GitLab From 7894ef7105c87c490b7cd4f5afac4e498f9be1a9 Mon Sep 17 00:00:00 2001 From: Quentin Burgess Date: Mon, 14 Oct 2024 11:36:51 +0200 Subject: [PATCH 2/7] feat(builder): add remeaning methods --- slogor.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/slogor.go b/slogor.go index 946c307..2611885 100644 --- a/slogor.go +++ b/slogor.go @@ -57,6 +57,21 @@ func SetLevelStr(strLvl map[slog.Level]string) OptionFn { return func(options *Options) { options.strLvl = strLvl } } +// SetLevel set the handler logging level to lvl. +// The default one is used if none specified. +func SetLevel(lvl slog.Level) OptionFn { return func(options *Options) { options.Level = lvl } } + +// SetTimeFormat set the output timestamp to fmt. +// By default, no timestamp's output. +func SetTimeFormat(fmt string) OptionFn { return func(options *Options) { options.TimeFormat = fmt } } + +// ShowSource append the log line to the log message. +// Nothing is reported by default. +func ShowSource() OptionFn { return func(options *Options) { options.ShowSource = true } } + +// DisableColor. +func DisableColor() OptionFn { return func(options *Options) { options.NoColor = true } } + // NewHandler creates a Handler that writes to w with the provided options. func NewHandler(writer io.Writer, options Options, fns ...OptionFn) *Handler { options.strLvl = defaultLevelStr -- GitLab From 452a9dcf592e61c7dca65f7d626a872dbc1cc9a7 Mon Sep 17 00:00:00 2001 From: Quentin Burgess Date: Mon, 14 Oct 2024 11:45:18 +0200 Subject: [PATCH 3/7] refactor(options): "privatise" in favore of functional options --- slogor.go | 91 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 46 insertions(+), 45 deletions(-) diff --git a/slogor.go b/slogor.go index 2611885..a8b67cb 100644 --- a/slogor.go +++ b/slogor.go @@ -14,17 +14,17 @@ import ( ) // Options defines the options for configuring the Handler. -type Options struct { - // Level is the minimum log level to handle. - Level slog.Leveler - // TimeFormat specifies the time format for log records. +type options struct { + // level is the minimum log level to handle. + level slog.Leveler + // timeFormat specifies the time format for log records. // Empty string will remove the time in records. - TimeFormat string - // ShowSource indicates whether to display the source of log records. - ShowSource bool - // Disable colored output. - NoColor bool - + timeFormat string + // showSource indicates whether to display the source of log records. + showSource bool + // noColor Disable colored output. + noColor bool + // strLvl allow custom string to log level conversion. strLvl map[slog.Level]string } @@ -37,11 +37,12 @@ type GroupOrAttrs struct { type Handler struct { Writer io.Writer // Writer is the destination for the log records. Mutex *sync.Mutex // Mutex for handling concurrent access to the handler. - Options Options // Options is the configuration for the log handler. + options options // Options is the configuration for the log handler. addColorToBuf func([]byte, string) []byte // addColorToBuf conditionally add color to the output buffer. goa []GroupOrAttrs // goa for handling group or attributes. } +// Map for STD log level conversion. var defaultLevelStr = map[slog.Level]string{ slog.LevelDebug: slog.LevelDebug.Level().String() + " ", slog.LevelInfo: slog.LevelInfo.Level().String(), @@ -49,50 +50,52 @@ var defaultLevelStr = map[slog.Level]string{ slog.LevelError: slog.LevelError.Level().String(), } -type OptionFn func(*Options) +type OptionFn func(*options) // SetLevelStr set the handler "level to string" map. // The default one is used if none specified. func SetLevelStr(strLvl map[slog.Level]string) OptionFn { - return func(options *Options) { options.strLvl = strLvl } + return func(options *options) { options.strLvl = strLvl } } -// SetLevel set the handler logging level to lvl. -// The default one is used if none specified. -func SetLevel(lvl slog.Level) OptionFn { return func(options *Options) { options.Level = lvl } } +// SetLevel set the minmum log level to handle. +// The STD default one is used if none specified. +func SetLevel(lvl slog.Level) OptionFn { return func(options *options) { options.level = lvl } } -// SetTimeFormat set the output timestamp to fmt. -// By default, no timestamp's output. -func SetTimeFormat(fmt string) OptionFn { return func(options *Options) { options.TimeFormat = fmt } } +// SetTimeFormat specifies the time format for the log records. +// By default, nothing is reported. +func SetTimeFormat(fmt string) OptionFn { return func(options *options) { options.timeFormat = fmt } } -// ShowSource append the log line to the log message. -// Nothing is reported by default. -func ShowSource() OptionFn { return func(options *Options) { options.ShowSource = true } } +// ShowSource indicates whether to display the source of the log records. +// By default, nothing is reported. +func ShowSource() OptionFn { return func(options *options) { options.showSource = true } } // DisableColor. -func DisableColor() OptionFn { return func(options *Options) { options.NoColor = true } } +func DisableColor() OptionFn { return func(options *options) { options.noColor = true } } // NewHandler creates a Handler that writes to w with the provided options. -func NewHandler(writer io.Writer, options Options, fns ...OptionFn) *Handler { - options.strLvl = defaultLevelStr +func NewHandler(writer io.Writer, fns ...OptionFn) *Handler { + opt := options{ + strLvl: defaultLevelStr, + } clr := func(buf []byte, color string) []byte { return append(buf, color...) } - if options.NoColor { - clr = func(buf []byte, color string) []byte { return buf } + for _, fn := range fns { + fn(&opt) } - for _, fn := range fns { - fn(&options) + if opt.noColor { + clr = func(buf []byte, color string) []byte { return buf } } // Return a new Handler with the provided writer and options. return &Handler{ Mutex: &sync.Mutex{}, Writer: writer, - Options: options, + options: opt, goa: []GroupOrAttrs{}, addColorToBuf: clr, } @@ -101,17 +104,16 @@ func NewHandler(writer io.Writer, options Options, fns ...OptionFn) *Handler { // Enabled reports whether the handler handles records at the given level. // The handler ignores records whose level is lower. func (h *Handler) Enabled(_ context.Context, level slog.Level) bool { - return level >= h.Options.Level.Level() + return level >= h.options.level.Level() } // WithGroup returns a new handler with the new group attached to it. func (h *Handler) WithGroup(group string) slog.Handler { return &Handler{ - Mutex: h.Mutex, // we share the mutex from the parent handler - Writer: h.Writer, - Options: h.Options, - goa: append(h.goa, GroupOrAttrs{group: group}), - addColorToBuf: h.addColorToBuf, + Mutex: h.Mutex, // we share the mutex from the parent handler + Writer: h.Writer, + options: h.options, + goa: append(h.goa, GroupOrAttrs{group: group}), } } @@ -124,11 +126,10 @@ func (h *Handler) WithAttrs(attrs []slog.Attr) slog.Handler { } return &Handler{ - Mutex: h.Mutex, // we share the mutex from the parent handler - Writer: h.Writer, - Options: h.Options, - goa: append(h.goa, newAttrs...), - addColorToBuf: h.addColorToBuf, + Mutex: h.Mutex, // we share the mutex from the parent handler + Writer: h.Writer, + Options: h.Options, + goa: append(h.goa, newAttrs...), } } @@ -143,10 +144,10 @@ func (h *Handler) Handle(_ context.Context, record slog.Record) error { }() // Write time if the record has a valid time and TimeFormat is specified. - if h.Options.TimeFormat != "" && !record.Time.IsZero() { + if h.options.timeFormat != "" && !record.Time.IsZero() { // Format and append time information to the buffer. buf = h.addColorToBuf(buf, faint) - buf = append(buf, record.Time.Format(h.Options.TimeFormat)...) + buf = append(buf, record.Time.Format(h.options.timeFormat)...) buf = h.addColorToBuf(buf, normalIntensity) buf = append(buf, " "...) } @@ -164,7 +165,7 @@ func (h *Handler) Handle(_ context.Context, record slog.Record) error { buf = h.addColorToBuf(buf, fgMagenta) } - if str, ok := h.Options.strLvl[record.Level]; ok { + if str, ok := h.options.strLvl[record.Level]; ok { buf = append(buf, str...) } else { buf = append(buf, "-----"...) @@ -176,7 +177,7 @@ func (h *Handler) Handle(_ context.Context, record slog.Record) error { var senti error // If configured, write the source file and line information. - for h.Options.ShowSource { + for h.options.showSource { buf = h.addColorToBuf(buf, fgBlue) buf = append(buf, underline...) -- GitLab From 7270ecf4d7eb64a4c36e62f703c4842322832796 Mon Sep 17 00:00:00 2001 From: Quentin Burgess Date: Mon, 14 Oct 2024 11:47:12 +0200 Subject: [PATCH 4/7] test(main): update examples --- main/main.go | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/main/main.go b/main/main.go index fabfc87..f5df370 100644 --- a/main/main.go +++ b/main/main.go @@ -11,11 +11,10 @@ import ( ) func main() { - slog.SetDefault(slog.New(slogor.NewHandler(os.Stderr, slogor.Options{ - TimeFormat: time.Stamp, - Level: slog.LevelDebug, - ShowSource: false, - }))) + slog.SetDefault(slog.New(slogor.NewHandler(os.Stderr, + slogor.SetTimeFormat(time.Stamp), + slogor.SetLevel(slog.LevelDebug), + ))) slog.Info("I'm an information message, everything's fine") slog.Warn("I'm a warning, that's ok.") @@ -23,28 +22,26 @@ func main() { slog.Debug("Useful debug message.") fmt.Println("") - slog.SetDefault(slog.New(slogor.NewHandler(os.Stderr, slogor.Options{ - TimeFormat: time.Kitchen, - Level: slog.LevelDebug, - ShowSource: false, - }))) + slog.SetDefault(slog.New(slogor.NewHandler(os.Stderr, + slogor.SetTimeFormat(time.Kitchen), + slogor.SetLevel(slog.LevelDebug), + ))) slog.Info("Example with kitchen time.") slog.Debug("Example with kitchen time.") fmt.Println("") - slog.SetDefault(slog.New(slogor.NewHandler(os.Stderr, slogor.Options{ - TimeFormat: time.RFC3339Nano, - Level: slog.LevelDebug, - ShowSource: true, - }))) + slog.SetDefault(slog.New(slogor.NewHandler(os.Stderr, + slogor.SetTimeFormat(time.RFC3339Nano), + slogor.SetLevel(slog.LevelDebug), + slogor.ShowSource(), + ))) slog.Info("Example with RFC 3339 time and source path") fmt.Println("") - slog.SetDefault(slog.New(slogor.NewHandler(os.Stderr, slogor.Options{ - TimeFormat: time.Stamp, - Level: slog.LevelDebug, - ShowSource: false, - }))) + slog.SetDefault(slog.New(slogor.NewHandler(os.Stderr, + slogor.SetTimeFormat(time.Stamp), + slogor.SetLevel(slog.LevelDebug), + ))) slog.Error("Error with args", slogor.Err(errors.New("i'm an error"))) slog.Warn("Warn with args", slog.Int("the_answer", 42)) -- GitLab From 089508269493cb81068105098ba821dc89668c8c Mon Sep 17 00:00:00 2001 From: Quentin Burgess Date: Mon, 14 Oct 2024 11:51:37 +0200 Subject: [PATCH 5/7] refactor(handler): move log level logic to dedicated function --- slogor.go | 81 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 43 insertions(+), 38 deletions(-) diff --git a/slogor.go b/slogor.go index a8b67cb..b74e6c0 100644 --- a/slogor.go +++ b/slogor.go @@ -13,6 +13,22 @@ import ( "sync" ) +type GroupOrAttrs struct { + attr slog.Attr + group string +} + +// Handler is a slog.Handler that writes Records to an io.Writer as a sequence of colorful time, message, and pairs separated by spaces and followed by a newline. +type Handler struct { + Writer io.Writer // Writer is the destination for the log records. + Mutex *sync.Mutex // Mutex for handling concurrent access to the handler. + options options // Options is the configuration for the log handler. + addColorToBuf func([]byte, string) []byte // addColorToBuf conditionally add color to the output buffer. + goa []GroupOrAttrs // goa for handling group or attributes. +} + +type OptionFn func(*options) + // Options defines the options for configuring the Handler. type options struct { // level is the minimum log level to handle. @@ -28,20 +44,6 @@ type options struct { strLvl map[slog.Level]string } -type GroupOrAttrs struct { - attr slog.Attr - group string -} - -// Handler is a slog.Handler that writes Records to an io.Writer as a sequence of colorful time, message, and pairs separated by spaces and followed by a newline. -type Handler struct { - Writer io.Writer // Writer is the destination for the log records. - Mutex *sync.Mutex // Mutex for handling concurrent access to the handler. - options options // Options is the configuration for the log handler. - addColorToBuf func([]byte, string) []byte // addColorToBuf conditionally add color to the output buffer. - goa []GroupOrAttrs // goa for handling group or attributes. -} - // Map for STD log level conversion. var defaultLevelStr = map[slog.Level]string{ slog.LevelDebug: slog.LevelDebug.Level().String() + " ", @@ -50,8 +52,6 @@ var defaultLevelStr = map[slog.Level]string{ slog.LevelError: slog.LevelError.Level().String(), } -type OptionFn func(*options) - // SetLevelStr set the handler "level to string" map. // The default one is used if none specified. func SetLevelStr(strLvl map[slog.Level]string) OptionFn { @@ -133,7 +133,7 @@ func (h *Handler) WithAttrs(attrs []slog.Attr) slog.Handler { } } -// Handle processes the log record and writes it to the writer with appropriate formatting. +// Handle processes the log record and writes it to the writer with appropriat formatting. func (h *Handler) Handle(_ context.Context, record slog.Record) error { bufp := allocBuf() // Allocate a buffer for writing the log record. buf := *bufp @@ -152,27 +152,7 @@ func (h *Handler) Handle(_ context.Context, record slog.Record) error { buf = append(buf, " "...) } - // Write level with appropriate formatting and color. - // Also append right padding depending on the log level. - switch record.Level { - case slog.LevelInfo: - buf = h.addColorToBuf(buf, fgGreen) - case slog.LevelError: - buf = h.addColorToBuf(buf, fgRed) - case slog.LevelWarn: - buf = h.addColorToBuf(buf, fgYellow) - case slog.LevelDebug: - buf = h.addColorToBuf(buf, fgMagenta) - } - - if str, ok := h.options.strLvl[record.Level]; ok { - buf = append(buf, str...) - } else { - buf = append(buf, "-----"...) - } - - buf = append(buf, reset...) - buf = append(buf, " "...) + buf = h.addLogLevel(buf, record) var senti error @@ -262,6 +242,31 @@ func (h *Handler) Handle(_ context.Context, record slog.Record) error { return senti } +func (h *Handler) addLogLevel(buf []byte, record slog.Record) []byte { + // Write level with appropriate formatting and color. + // Also append right padding depending on the log level. + switch record.Level { + case slog.LevelInfo: + buf = h.addColorToBuf(buf, fgGreen) + case slog.LevelError: + buf = h.addColorToBuf(buf, fgRed) + case slog.LevelWarn: + buf = h.addColorToBuf(buf, fgYellow) + case slog.LevelDebug: + buf = h.addColorToBuf(buf, fgMagenta) + } + + if str, ok := h.options.strLvl[record.Level]; ok { + buf = append(buf, str...) + } else { + buf = append(buf, "-----"...) + } + + buf = append(buf, reset...) + + return append(buf, " "...) +} + // appendAttr appends the attribute to the buffer. func appendAttr(buf []byte, attr slog.Attr, addColor func([]byte, string) []byte) []byte { // Resolve the Attr's value before doing anything else. -- GitLab From 484e0df4ba65287015ae49c8580bc45099f286dc Mon Sep 17 00:00:00 2001 From: Quentin Burgess Date: Mon, 14 Oct 2024 12:09:53 +0200 Subject: [PATCH 6/7] refactor(options): move to dedicated file --- option.go | 65 ++++++++++++++++++++++++++++++++++++++++++ slogor.go | 84 ++++++++++++------------------------------------------- 2 files changed, 83 insertions(+), 66 deletions(-) create mode 100644 option.go diff --git a/option.go b/option.go new file mode 100644 index 0000000..7996c80 --- /dev/null +++ b/option.go @@ -0,0 +1,65 @@ +package slogor + +import "log/slog" + +type OptionFn func(*options) + +// Options defines the options for configuring the Handler. +type options struct { + // level is the minimum log level to handle. + level slog.Leveler + // timeFormat specifies the time format for log records. + // Empty string will remove the time in records. + timeFormat string + // showSource indicates whether to display the source of log records. + showSource bool + // noColor Disable colored output. + noColor bool + // strLvl allow custom string to log level conversion. + strLvl map[slog.Level]string +} + +type MapOfLevel = map[slog.Level]string + +// Map for STD log level conversion. +var mapOfLevel = MapOfLevel{ + slog.LevelDebug: slog.LevelDebug.Level().String() + " ", + slog.LevelInfo: slog.LevelInfo.Level().String(), + slog.LevelWarn: slog.LevelWarn.Level().String() + " ", + slog.LevelError: slog.LevelError.Level().String(), +} + +// SetLevelStr set the handler "level to string" map. +// The default one is used if none specified. +func SetLevelStr(strLvl MapOfLevel) OptionFn { + return func(options *options) { options.strLvl = strLvl } +} + +// SetLevel set the minimum log level to handle. +// By default, level INFO is set. +func SetLevel(lvl slog.Level) OptionFn { return func(options *options) { options.level = lvl } } + +// SetTimeFormat specifies the time format for the log records. +// By default, nothing is reported. +func SetTimeFormat(fmt string) OptionFn { return func(options *options) { options.timeFormat = fmt } } + +// ShowSource indicates whether to display the source of the log records. +// By default, nothing is reported. +func ShowSource() OptionFn { return func(options *options) { options.showSource = true } } + +// DisableColor. +func DisableColor() OptionFn { return func(options *options) { options.noColor = true } } + +func getDefaultoption() *options { + return &options{ + strLvl: mapOfLevel, level: slog.LevelInfo, + } +} + +func (o *options) consumeFnOpt(fns ...OptionFn) *options { + for _, fn := range fns { + fn(o) + } + + return o +} diff --git a/slogor.go b/slogor.go index b74e6c0..41d7857 100644 --- a/slogor.go +++ b/slogor.go @@ -27,77 +27,21 @@ type Handler struct { goa []GroupOrAttrs // goa for handling group or attributes. } -type OptionFn func(*options) - -// Options defines the options for configuring the Handler. -type options struct { - // level is the minimum log level to handle. - level slog.Leveler - // timeFormat specifies the time format for log records. - // Empty string will remove the time in records. - timeFormat string - // showSource indicates whether to display the source of log records. - showSource bool - // noColor Disable colored output. - noColor bool - // strLvl allow custom string to log level conversion. - strLvl map[slog.Level]string -} - -// Map for STD log level conversion. -var defaultLevelStr = map[slog.Level]string{ - slog.LevelDebug: slog.LevelDebug.Level().String() + " ", - slog.LevelInfo: slog.LevelInfo.Level().String(), - slog.LevelWarn: slog.LevelWarn.Level().String() + " ", - slog.LevelError: slog.LevelError.Level().String(), -} - -// SetLevelStr set the handler "level to string" map. -// The default one is used if none specified. -func SetLevelStr(strLvl map[slog.Level]string) OptionFn { - return func(options *options) { options.strLvl = strLvl } -} - -// SetLevel set the minmum log level to handle. -// The STD default one is used if none specified. -func SetLevel(lvl slog.Level) OptionFn { return func(options *options) { options.level = lvl } } - -// SetTimeFormat specifies the time format for the log records. -// By default, nothing is reported. -func SetTimeFormat(fmt string) OptionFn { return func(options *options) { options.timeFormat = fmt } } - -// ShowSource indicates whether to display the source of the log records. -// By default, nothing is reported. -func ShowSource() OptionFn { return func(options *options) { options.showSource = true } } - -// DisableColor. -func DisableColor() OptionFn { return func(options *options) { options.noColor = true } } - // NewHandler creates a Handler that writes to w with the provided options. func NewHandler(writer io.Writer, fns ...OptionFn) *Handler { - opt := options{ - strLvl: defaultLevelStr, - } - - clr := func(buf []byte, color string) []byte { - return append(buf, color...) - } - - for _, fn := range fns { - fn(&opt) - } - - if opt.noColor { - clr = func(buf []byte, color string) []byte { return buf } - } + opt := getDefaultoption().consumeFnOpt(fns...) // Return a new Handler with the provided writer and options. return &Handler{ - Mutex: &sync.Mutex{}, - Writer: writer, - options: opt, - goa: []GroupOrAttrs{}, - addColorToBuf: clr, + Mutex: &sync.Mutex{}, + Writer: writer, + options: *opt, + goa: []GroupOrAttrs{}, + addColorToBuf: tern(opt.noColor, + func(buf []byte, color string) []byte { return buf }, + func(buf []byte, color string) []byte { + return append(buf, color...) + }), } } @@ -306,3 +250,11 @@ func appendAttr(buf []byte, attr slog.Attr, addColor func([]byte, string) []byte func Err(err any) slog.Attr { return slog.Any("err", err) } + +func tern[T any](cond bool, l, r T) T { + if cond { + return l + } + + return r +} -- GitLab From e28d779c50cfa85eec2241b82a6ee2cbd0d48f7f Mon Sep 17 00:00:00 2001 From: Quentin Burgess Date: Mon, 14 Oct 2024 13:31:45 +0200 Subject: [PATCH 7/7] refactor(option): move addColorToBuf from Handler to Option No need to run an extra copy on child handler creation --- option.go | 16 ++++++++++++---- slogor.go | 40 +++++++++++++--------------------------- 2 files changed, 25 insertions(+), 31 deletions(-) diff --git a/option.go b/option.go index 7996c80..181a56f 100644 --- a/option.go +++ b/option.go @@ -13,8 +13,8 @@ type options struct { timeFormat string // showSource indicates whether to display the source of log records. showSource bool - // noColor Disable colored output. - noColor bool + // addColorToBuf conditionally add color to the output buffer. + addColorToBuf func([]byte, string) []byte // strLvl allow custom string to log level conversion. strLvl map[slog.Level]string } @@ -48,11 +48,19 @@ func SetTimeFormat(fmt string) OptionFn { return func(options *options) { option func ShowSource() OptionFn { return func(options *options) { options.showSource = true } } // DisableColor. -func DisableColor() OptionFn { return func(options *options) { options.noColor = true } } +func DisableColor() OptionFn { + return func(options *options) { + options.addColorToBuf = func(buf []byte, color string) []byte { return buf } + } +} func getDefaultoption() *options { return &options{ - strLvl: mapOfLevel, level: slog.LevelInfo, + strLvl: mapOfLevel, + level: slog.LevelInfo, + addColorToBuf: func(buf []byte, color string) []byte { + return append(buf, color...) + }, } } diff --git a/slogor.go b/slogor.go index 41d7857..46acab8 100644 --- a/slogor.go +++ b/slogor.go @@ -20,11 +20,10 @@ type GroupOrAttrs struct { // Handler is a slog.Handler that writes Records to an io.Writer as a sequence of colorful time, message, and pairs separated by spaces and followed by a newline. type Handler struct { - Writer io.Writer // Writer is the destination for the log records. - Mutex *sync.Mutex // Mutex for handling concurrent access to the handler. - options options // Options is the configuration for the log handler. - addColorToBuf func([]byte, string) []byte // addColorToBuf conditionally add color to the output buffer. - goa []GroupOrAttrs // goa for handling group or attributes. + Writer io.Writer // Writer is the destination for the log records. + Mutex *sync.Mutex // Mutex for handling concurrent access to the handler. + options options // Options is the configuration for the log handler. + goa []GroupOrAttrs // goa for handling group or attributes. } // NewHandler creates a Handler that writes to w with the provided options. @@ -37,11 +36,6 @@ func NewHandler(writer io.Writer, fns ...OptionFn) *Handler { Writer: writer, options: *opt, goa: []GroupOrAttrs{}, - addColorToBuf: tern(opt.noColor, - func(buf []byte, color string) []byte { return buf }, - func(buf []byte, color string) []byte { - return append(buf, color...) - }), } } @@ -90,9 +84,9 @@ func (h *Handler) Handle(_ context.Context, record slog.Record) error { // Write time if the record has a valid time and TimeFormat is specified. if h.options.timeFormat != "" && !record.Time.IsZero() { // Format and append time information to the buffer. - buf = h.addColorToBuf(buf, faint) + buf = h.options.addColorToBuf(buf, faint) buf = append(buf, record.Time.Format(h.options.timeFormat)...) - buf = h.addColorToBuf(buf, normalIntensity) + buf = h.options.addColorToBuf(buf, normalIntensity) buf = append(buf, " "...) } @@ -102,7 +96,7 @@ func (h *Handler) Handle(_ context.Context, record slog.Record) error { // If configured, write the source file and line information. for h.options.showSource { - buf = h.addColorToBuf(buf, fgBlue) + buf = h.options.addColorToBuf(buf, fgBlue) buf = append(buf, underline...) frame, _ := runtime.CallersFrames([]uintptr{record.PC}).Next() @@ -154,7 +148,7 @@ func (h *Handler) Handle(_ context.Context, record slog.Record) error { attr.Key = lastGroup + attr.Key } - buf = appendAttr(buf, attr, h.addColorToBuf) + buf = appendAttr(buf, attr, h.options.addColorToBuf) } } @@ -164,7 +158,7 @@ func (h *Handler) Handle(_ context.Context, record slog.Record) error { if lastGroup != "" { attr.Key = lastGroup + attr.Key } - buf = appendAttr(buf, attr, h.addColorToBuf) + buf = appendAttr(buf, attr, h.options.addColorToBuf) return true }) @@ -191,13 +185,13 @@ func (h *Handler) addLogLevel(buf []byte, record slog.Record) []byte { // Also append right padding depending on the log level. switch record.Level { case slog.LevelInfo: - buf = h.addColorToBuf(buf, fgGreen) + buf = h.options.addColorToBuf(buf, fgGreen) case slog.LevelError: - buf = h.addColorToBuf(buf, fgRed) + buf = h.options.addColorToBuf(buf, fgRed) case slog.LevelWarn: - buf = h.addColorToBuf(buf, fgYellow) + buf = h.options.addColorToBuf(buf, fgYellow) case slog.LevelDebug: - buf = h.addColorToBuf(buf, fgMagenta) + buf = h.options.addColorToBuf(buf, fgMagenta) } if str, ok := h.options.strLvl[record.Level]; ok { @@ -250,11 +244,3 @@ func appendAttr(buf []byte, attr slog.Attr, addColor func([]byte, string) []byte func Err(err any) slog.Attr { return slog.Any("err", err) } - -func tern[T any](cond bool, l, r T) T { - if cond { - return l - } - - return r -} -- GitLab