diff --git a/go.mod b/go.mod index 4202982..d8c783b 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ module github.com/lmittmann/tint -go 1.21 +go 1.22 diff --git a/handler.go b/handler.go index e235378..7684599 100644 --- a/handler.go +++ b/handler.go @@ -122,6 +122,10 @@ type Options struct { // Disable color (Default: false) NoColor bool + + // Multiline determines if each log entry should be written on a new line. + // (Default: false) + Multiline bool } // NewHandler creates a [slog.Handler] that writes tinted logs to Writer w, @@ -145,6 +149,7 @@ func NewHandler(w io.Writer, opts *Options) slog.Handler { h.timeFormat = opts.TimeFormat } h.noColor = opts.NoColor + h.multiline = opts.Multiline return h } @@ -162,6 +167,7 @@ type handler struct { replaceAttr func([]string, slog.Attr) slog.Attr timeFormat string noColor bool + multiline bool } func (h *handler) clone() *handler { @@ -238,10 +244,10 @@ func (h *handler) Handle(_ context.Context, r slog.Record) error { // write message if rep == nil { buf.WriteString(r.Message) - buf.WriteByte(' ') + h.appendSeparator(buf) } else if a := rep(nil /* groups */, slog.String(slog.MessageKey, r.Message)); a.Key != "" { h.appendValue(buf, a.Value, false) - buf.WriteByte(' ') + h.appendSeparator(buf) } // write handler attributes @@ -294,6 +300,14 @@ func (h *handler) WithGroup(name string) slog.Handler { return h2 } +func (h *handler) appendSeparator(buf *buffer) { + if h.multiline { + buf.WriteByte('\n') + } else { + buf.WriteByte(' ') + } +} + func (h *handler) appendTime(buf *buffer, t time.Time) { buf.WriteStringIf(!h.noColor, ansiFaint) *buf = t.AppendFormat(*buf, h.timeFormat) @@ -361,15 +375,22 @@ func (h *handler) appendAttr(buf *buffer, attr slog.Attr, groupsPrefix string, g for _, groupAttr := range attr.Value.Group() { h.appendAttr(buf, groupAttr, groupsPrefix, groups) } - } else if err, ok := attr.Value.Any().(tintError); ok { - // append tintError + return + } + + if h.multiline { + buf.WriteString(" ") + } + + if err, ok := attr.Value.Any().(tintError); ok { h.appendTintError(buf, err, attr.Key, groupsPrefix) - buf.WriteByte(' ') - } else { - h.appendKey(buf, attr.Key, groupsPrefix) - h.appendValue(buf, attr.Value, true) - buf.WriteByte(' ') + h.appendSeparator(buf) + return } + + h.appendKey(buf, attr.Key, groupsPrefix) + h.appendValue(buf, attr.Value, true) + h.appendSeparator(buf) } func (h *handler) appendKey(buf *buffer, key, groups string) { diff --git a/handler_test.go b/handler_test.go index 737f2d0..adc96e1 100644 --- a/handler_test.go +++ b/handler_test.go @@ -21,7 +21,7 @@ var faketime = time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC) func Example() { slog.SetDefault(slog.New(tint.NewHandler(os.Stderr, &tint.Options{ Level: slog.LevelDebug, - TimeFormat: time.Kitchen, + TimeFormat: time.Kitchen, Multiline: true, }))) slog.Info("Starting server", "addr", ":8080", "env", "production") @@ -352,6 +352,19 @@ func TestHandler(t *testing.T) { }, Want: `Nov 10 23:00:00.000 ERR test error=fail`, }, + { + Opts: &tint.Options{ + Multiline: true, + }, + F: func(l *slog.Logger) { + l.Info("test", + "key1", "val1", + "key2", "val2") + }, + Want: `Nov 10 23:00:00.000 INF test` + "\n" + + ` key1=val1` + "\n" + + ` key2=val2`, + }, } for i, test := range tests {