Skip to content

Commit

Permalink
updated NewHandler(io.Writer) to NewHandler(io.Writer, *Options)
Browse files Browse the repository at this point in the history
* dropped `Options.NewHandler`
* use `slog.Source` instead of `runtime.Frame`
  • Loading branch information
lmittmann committed May 11, 2023
1 parent a6123dc commit d1df6e1
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 41 deletions.
2 changes: 1 addition & 1 deletion buffer.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ type buffer []byte
var bufPool = sync.Pool{
New: func() any {
b := make(buffer, 0, 1024)
return &b
return (*buffer)(&b)
},
}

Expand Down
46 changes: 25 additions & 21 deletions handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ const (
const keyErr = "err"

var (
defaultTimeFormat = time.StampMilli
defaultLevel = slog.LevelInfo
defaultTimeFormat = time.StampMilli
)

// Options for a slog.Handler that writes tinted logs. A zero Options consists
Expand All @@ -64,32 +64,30 @@ type Options struct {
NoColor bool
}

// NewHandler creates a [slog.Handler] that writes tinted logs to Writer w with
// the given options.
func (opts Options) NewHandler(w io.Writer) slog.Handler {
// NewHandler creates a [slog.Handler] that writes tinted logs to Writer w,
// using the default options. If opts is nil, the default options are used.
func NewHandler(w io.Writer, opts *Options) slog.Handler {
h := &handler{
w: w,
addSource: opts.AddSource,
level: defaultLevel,
replaceAttr: opts.ReplaceAttr,
timeFormat: defaultTimeFormat,
noColor: opts.NoColor,
w: w,
level: defaultLevel,
timeFormat: defaultTimeFormat,
}
if opts == nil {
return h
}

h.addSource = opts.AddSource
if opts.Level != nil {
h.level = opts.Level.Level()
}
h.replaceAttr = opts.ReplaceAttr
if opts.TimeFormat != "" {
h.timeFormat = opts.TimeFormat
}
h.noColor = opts.NoColor
return h
}

// NewHandler creates a [slog.Handler] that writes tinted logs to Writer w,
// using the default options.
func NewHandler(w io.Writer) slog.Handler {
return Options{}.NewHandler(w)
}

// handler implements a [slog.Handler].
type handler struct {
attrs string
Expand Down Expand Up @@ -165,10 +163,16 @@ func (h *handler) Handle(_ context.Context, r slog.Record) error {
fs := runtime.CallersFrames([]uintptr{r.PC})
f, _ := fs.Next()
if f.File != "" {
src := &slog.Source{
Function: f.Function,
File: f.File,
Line: f.Line,
}

if rep == nil {
h.appendSource(buf, f)
h.appendSource(buf, src)
buf.WriteByte(' ')
} else if a := rep(h.groupsSlice, slog.Any(slog.SourceKey, f)); a.Key != "" {
} else if a := rep(h.groupsSlice, slog.Any(slog.SourceKey, src)); a.Key != "" {
appendValue(buf, a.Value, false)
buf.WriteByte(' ')
}
Expand Down Expand Up @@ -277,13 +281,13 @@ func (h *handler) appendLevel(buf *buffer, level slog.Level) {
}
}

func (h *handler) appendSource(buf *buffer, f runtime.Frame) {
dir, file := filepath.Split(f.File)
func (h *handler) appendSource(buf *buffer, src *slog.Source) {
dir, file := filepath.Split(src.File)

buf.WriteStringIf(!h.noColor, ansiFaint)
buf.WriteString(filepath.Join(filepath.Base(dir), file))
buf.WriteByte(':')
buf.WriteString(strconv.Itoa(f.Line))
buf.WriteString(strconv.Itoa(src.Line))
buf.WriteStringIf(!h.noColor, ansiReset)
}

Expand Down
41 changes: 22 additions & 19 deletions handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ import (
var faketime = time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)

func Example() {
slog.SetDefault(slog.New(tint.Options{
slog.SetDefault(slog.New(tint.NewHandler(os.Stderr, &tint.Options{
Level: slog.LevelDebug,
TimeFormat: time.Kitchen,
}.NewHandler(os.Stderr)))
})))

slog.Info("Starting server", "addr", ":8080", "env", "production")
slog.Debug("Connected to DB", "db", "myapp", "host", "localhost:5432")
Expand All @@ -39,7 +39,7 @@ func TestHandler(t *testing.T) {
}

tests := []struct {
Opts tint.Options
Opts *tint.Options
F func(l *slog.Logger)
Want string
}{
Expand Down Expand Up @@ -92,7 +92,7 @@ func TestHandler(t *testing.T) {
Want: `Nov 10 23:00:00.000 INF test slice="[a b c]" map="map[a:1 b:2 c:3]"`,
},
{
Opts: tint.Options{
Opts: &tint.Options{
AddSource: true,
},
F: func(l *slog.Logger) {
Expand All @@ -101,7 +101,7 @@ func TestHandler(t *testing.T) {
Want: `Nov 10 23:00:00.000 INF tint/handler_test.go:99 test key=val`,
},
{
Opts: tint.Options{
Opts: &tint.Options{
TimeFormat: time.Kitchen,
},
F: func(l *slog.Logger) {
Expand All @@ -110,7 +110,7 @@ func TestHandler(t *testing.T) {
Want: `11:00PM INF test key=val`,
},
{
Opts: tint.Options{
Opts: &tint.Options{
ReplaceAttr: drop(slog.TimeKey),
},
F: func(l *slog.Logger) {
Expand All @@ -119,7 +119,7 @@ func TestHandler(t *testing.T) {
Want: `INF test key=val`,
},
{
Opts: tint.Options{
Opts: &tint.Options{
ReplaceAttr: drop(slog.LevelKey),
},
F: func(l *slog.Logger) {
Expand All @@ -128,7 +128,7 @@ func TestHandler(t *testing.T) {
Want: `Nov 10 23:00:00.000 test key=val`,
},
{
Opts: tint.Options{
Opts: &tint.Options{
ReplaceAttr: drop(slog.MessageKey),
},
F: func(l *slog.Logger) {
Expand All @@ -137,7 +137,7 @@ func TestHandler(t *testing.T) {
Want: `Nov 10 23:00:00.000 INF key=val`,
},
{
Opts: tint.Options{
Opts: &tint.Options{
ReplaceAttr: drop(slog.TimeKey, slog.LevelKey, slog.MessageKey),
},
F: func(l *slog.Logger) {
Expand All @@ -146,7 +146,7 @@ func TestHandler(t *testing.T) {
Want: `key=val`,
},
{
Opts: tint.Options{
Opts: &tint.Options{
ReplaceAttr: drop("key"),
},
F: func(l *slog.Logger) {
Expand All @@ -155,7 +155,7 @@ func TestHandler(t *testing.T) {
Want: `Nov 10 23:00:00.000 INF test`,
},
{
Opts: tint.Options{
Opts: &tint.Options{
ReplaceAttr: drop("key"),
},
F: func(l *slog.Logger) {
Expand All @@ -164,7 +164,7 @@ func TestHandler(t *testing.T) {
Want: `Nov 10 23:00:00.000 INF test group.key=val group.key2=val2`,
},
{
Opts: tint.Options{
Opts: &tint.Options{
ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr {
if a.Key == "key" && len(groups) == 1 && groups[0] == "group" {
return slog.Attr{}
Expand All @@ -178,7 +178,7 @@ func TestHandler(t *testing.T) {
Want: `Nov 10 23:00:00.000 INF test group.key2=val2`,
},
{
Opts: tint.Options{
Opts: &tint.Options{
ReplaceAttr: replace(slog.IntValue(42), slog.TimeKey),
},
F: func(l *slog.Logger) {
Expand All @@ -187,7 +187,7 @@ func TestHandler(t *testing.T) {
Want: `42 INF test key=val`,
},
{
Opts: tint.Options{
Opts: &tint.Options{
ReplaceAttr: replace(slog.StringValue("INFO"), slog.LevelKey),
},
F: func(l *slog.Logger) {
Expand All @@ -196,7 +196,7 @@ func TestHandler(t *testing.T) {
Want: `Nov 10 23:00:00.000 INFO test key=val`,
},
{
Opts: tint.Options{
Opts: &tint.Options{
ReplaceAttr: replace(slog.IntValue(42), slog.MessageKey),
},
F: func(l *slog.Logger) {
Expand All @@ -205,7 +205,7 @@ func TestHandler(t *testing.T) {
Want: `Nov 10 23:00:00.000 INF 42 key=val`,
},
{
Opts: tint.Options{
Opts: &tint.Options{
ReplaceAttr: replace(slog.IntValue(42), "key"),
},
F: func(l *slog.Logger) {
Expand All @@ -214,7 +214,7 @@ func TestHandler(t *testing.T) {
Want: `Nov 10 23:00:00.000 INF test key=42 key2=val2`,
},
{
Opts: tint.Options{
Opts: &tint.Options{
ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr {
return slog.Attr{}
},
Expand Down Expand Up @@ -266,8 +266,11 @@ func TestHandler(t *testing.T) {
for i, test := range tests {
t.Run(strconv.Itoa(i), func(t *testing.T) {
var buf bytes.Buffer
if test.Opts == nil {
test.Opts = &tint.Options{}
}
test.Opts.NoColor = true
l := slog.New(test.Opts.NewHandler(&buf))
l := slog.New(tint.NewHandler(&buf, test.Opts))
test.F(l)

got := strings.TrimRight(buf.String(), "\n")
Expand Down Expand Up @@ -319,7 +322,7 @@ func BenchmarkLogAttrs(b *testing.B) {
Name string
H slog.Handler
}{
{"tint", tint.NewHandler(io.Discard)},
{"tint", tint.NewHandler(io.Discard, nil)},
{"text", slog.NewTextHandler(io.Discard, nil)},
{"json", slog.NewJSONHandler(io.Discard, nil)},
{"discard", new(discarder)},
Expand Down

0 comments on commit d1df6e1

Please sign in to comment.