Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 12 additions & 17 deletions encoding.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ package console
import (
"fmt"
"log/slog"
"path/filepath"
"runtime"
"time"
)

Expand Down Expand Up @@ -75,21 +73,6 @@ func (e encoder) writeTimestamp(buf *buffer, tt time.Time) {
}
}

func (e encoder) writeSource(buf *buffer, pc uintptr, cwd string) {
frame, _ := runtime.CallersFrames([]uintptr{pc}).Next()
if cwd != "" {
if ff, err := filepath.Rel(cwd, frame.File); err == nil {
frame.File = ff
}
}
e.withColor(buf, e.opts.Theme.Source(), func() {
buf.AppendString(frame.File)
buf.AppendByte(':')
buf.AppendInt(int64(frame.Line))
})
e.writeColoredString(buf, " > ", e.opts.Theme.AttrKey())
}

func (e encoder) writeMessage(buf *buffer, level slog.Level, msg string) {
if level >= slog.LevelInfo {
e.writeColoredString(buf, msg, e.opts.Theme.Message())
Expand All @@ -103,6 +86,18 @@ func (e encoder) writeAttr(buf *buffer, a slog.Attr, group string) {
if a.Equal(slog.Attr{}) {
return
}
// Special handling for source attribute.
if a.Key == slog.SourceKey {
if v, ok := a.Value.Any().(*slog.Source); ok {
e.withColor(buf, e.opts.Theme.Source(), func() {
buf.AppendString(v.File)
buf.AppendByte(':')
buf.AppendInt(int64(v.Line))
})
e.writeColoredString(buf, " > ", e.opts.Theme.AttrKey())
return
}
}
value := a.Value.Resolve()
if value.Kind() == slog.KindGroup {
subgroup := a.Key
Expand Down
25 changes: 24 additions & 1 deletion example/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,36 @@ import (
"errors"
"log/slog"
"os"
"strings"

"github.com/phsym/console-slog"
)

func main() {
logger := slog.New(
console.NewHandler(os.Stderr, &console.HandlerOptions{Level: slog.LevelDebug, AddSource: true}),
console.NewHandler(os.Stderr, &console.HandlerOptions{
Level: slog.LevelDebug,
AddSource: true,
TimeFormat: "15:04:05.000000",
ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr {
if v, ok := a.Value.Any().(*slog.Source); ok {
file := v.File
parts := strings.Split(v.File, "/")
if len(parts) > 0 {
file = parts[len(parts)-1]
}
return slog.Attr{
Key: slog.SourceKey,
Value: slog.AnyValue(&slog.Source{
Function: v.Function,
File: file,
Line: v.Line,
}),
}
}
return a
},
}),
)
slog.SetDefault(logger)
slog.Info("Hello world!", "foo", "bar")
Expand Down
32 changes: 31 additions & 1 deletion handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"io"
"log/slog"
"os"
"path/filepath"
"runtime"
"strings"
"sync"
"time"
Expand Down Expand Up @@ -38,6 +40,10 @@ type HandlerOptions struct {

// Theme defines the colorized output using ANSI escape sequences
Theme Theme

// See [slog.HandlerOptions] for details.
// Groups are not supported though.
ReplaceAttr func(groups []string, a slog.Attr) slog.Attr
}

type Handler struct {
Expand Down Expand Up @@ -87,11 +93,35 @@ func (h *Handler) Handle(_ context.Context, rec slog.Record) error {
h.enc.writeTimestamp(buf, rec.Time)
h.enc.writeLevel(buf, rec.Level)
if h.opts.AddSource && rec.PC > 0 {
h.enc.writeSource(buf, rec.PC, cwd)
frame, _ := runtime.CallersFrames([]uintptr{rec.PC}).Next()
if cwd != "" {
if ff, err := filepath.Rel(cwd, frame.File); err == nil {
frame.File = ff
}
}
a := slog.Attr{
Key: slog.SourceKey,
Value: slog.AnyValue(&slog.Source{
Function: frame.Function,
File: frame.File,
Line: frame.Line,
}),
}
if h.opts.ReplaceAttr != nil {
a = h.opts.ReplaceAttr(nil, a)
}
h.enc.writeAttr(
buf,
a,
h.group,
)
}
h.enc.writeMessage(buf, rec.Level, rec.Message)
buf.copy(&h.context)
rec.Attrs(func(a slog.Attr) bool {
if h.opts.ReplaceAttr != nil {
a = h.opts.ReplaceAttr(nil, a)
}
h.enc.writeAttr(buf, a, h.group)
return true
})
Expand Down
23 changes: 23 additions & 0 deletions handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,29 @@ func TestHandler_TimeFormat(t *testing.T) {
AssertEqual(t, expected, buf.String())
}

func TestHandler_ReplaceAttr(t *testing.T) {
ra := func(groups []string, a slog.Attr) slog.Attr {
if a.Key == "test-key" {
return slog.Attr{Key: "testkey", Value: a.Value}
}
if a.Key == "empty" {
return slog.Attr{}
}
return a
}
buf := bytes.Buffer{}
h := NewHandler(&buf, &HandlerOptions{TimeFormat: time.RFC3339Nano, NoColor: true, ReplaceAttr: ra})
rec := slog.NewRecord(time.Time{}, slog.LevelInfo, "foobar", 0)
rec.AddAttrs(
slog.String("test-key", "test-value"),
slog.String("empty", "should not be logged"),
)
AssertNoError(t, h.Handle(context.Background(), rec))

expected := fmt.Sprintf("INF foobar testkey=test-value\n")
AssertEqual(t, expected, buf.String())
}

// Handlers should not log the time field if it is zero.
// '- If r.Time is the zero time, ignore the time.'
// https://pkg.go.dev/log/slog@master#Handler
Expand Down