Skip to content

Commit

Permalink
Merge pull request #1 from injeniero/main
Browse files Browse the repository at this point in the history
Adding TimeFormat option and other changes
  • Loading branch information
phsym authored Nov 9, 2023
2 parents 30dd520 + 428d018 commit e094ac7
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 23 deletions.
22 changes: 16 additions & 6 deletions encoding.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@ import (
)

type encoder struct {
nocolor bool
noColor bool
timeFormat string
}

func (e *encoder) NewLine(buf *buffer) {
buf.AppendString("\r\n")
buf.AppendByte('\n')
}

func (e *encoder) withColor(b *buffer, c color, f func()) {
if c == "" || e.nocolor {
if c == "" || e.noColor {
f()
return
}
Expand Down Expand Up @@ -69,7 +70,7 @@ func (e *encoder) writeColoredDuration(w *buffer, d time.Duration, seq color) {
}

func (e *encoder) writeTimestamp(buf *buffer, tt time.Time) {
e.writeColoredTime(buf, tt, time.DateTime, colorTimestamp)
e.writeColoredTime(buf, tt, e.timeFormat, colorTimestamp)
buf.AppendByte(' ')
}

Expand Down Expand Up @@ -125,7 +126,7 @@ func (e *encoder) writeValue(buf *buffer, value slog.Value) {
case slog.KindFloat64:
e.writeColoredFloat(buf, value.Float64(), colorAttrValue)
case slog.KindTime:
e.writeColoredTime(buf, value.Time(), time.RFC3339, colorAttrValue)
e.writeColoredTime(buf, value.Time(), e.timeFormat, colorAttrValue)
case slog.KindUint64:
e.writeColoredUint(buf, value.Uint64(), colorAttrValue)
case slog.KindDuration:
Expand All @@ -150,22 +151,31 @@ func (e *encoder) writeValue(buf *buffer, value slog.Value) {
func (e *encoder) writeLevel(buf *buffer, l slog.Level) {
var style color
var str string
var delta int
switch {
case l >= slog.LevelError:
style = colorLevelError
str = "ERR"
delta = int(l - slog.LevelError)
case l >= slog.LevelWarn:
style = colorLevelWarn
str = "WRN"
delta = int(l - slog.LevelWarn)
case l >= slog.LevelInfo:
style = colorLevelInfo
str = "INF"
delta = int(l - slog.LevelInfo)
case l >= slog.LevelDebug:
style = colorLevelDebug
str = "DBG"
delta = int(l - slog.LevelDebug)
default:
style = bold
str = "???"
str = "DBG"
delta = int(l - slog.LevelDebug)
}
if delta != 0 {
str = fmt.Sprintf("%s%+d", str, delta)
}
e.writeColoredString(buf, str, style)
buf.AppendByte(' ')
Expand Down
9 changes: 8 additions & 1 deletion handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"os"
"strings"
"sync"
"time"
)

var bufferPool = &sync.Pool{
Expand All @@ -31,6 +32,9 @@ type HandlerOptions struct {

// Disable colorized output
NoColor bool

// TimeFormat is the format used for time.DateTime
TimeFormat string
}

type Handler struct {
Expand All @@ -53,13 +57,16 @@ func NewHandler(out io.Writer, opts *HandlerOptions) *Handler {
if opts.Level == nil {
opts.Level = slog.LevelInfo
}
if opts.TimeFormat == "" {
opts.TimeFormat = time.DateTime
}
opt := *opts // Copy struct
return &Handler{
opts: &opt,
out: out,
group: "",
context: nil,
enc: &encoder{nocolor: opt.NoColor},
enc: &encoder{noColor: opt.NoColor, timeFormat: opt.TimeFormat},
}
}

Expand Down
45 changes: 29 additions & 16 deletions handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,20 @@ func TestHandler_colors(t *testing.T) {
rec := slog.NewRecord(now, slog.LevelInfo, "foobar", 0)
AssertNoError(t, h.Handle(context.Background(), rec))

expected := fmt.Sprintf("\x1b[90m%s\x1b[0m \x1b[92mINF\x1b[0m \x1b[97mfoobar\x1b[0m\r\n", now.Format(time.DateTime))
expected := fmt.Sprintf("\x1b[90m%s\x1b[0m \x1b[92mINF\x1b[0m \x1b[97mfoobar\x1b[0m\n", now.Format(time.DateTime))
AssertEqual(t, expected, buf.String())
}

func TestHandler_TimeFormat(t *testing.T) {
buf := bytes.Buffer{}
h := NewHandler(&buf, &HandlerOptions{TimeFormat: time.RFC3339Nano, NoColor: true})
now := time.Now()
rec := slog.NewRecord(now, slog.LevelInfo, "foobar", 0)
endTime := now.Add(time.Second)
rec.AddAttrs(slog.Time("endtime", endTime))
AssertNoError(t, h.Handle(context.Background(), rec))

expected := fmt.Sprintf("%s INF foobar endtime=%s\n", now.Format(time.RFC3339Nano), endTime.Format(time.RFC3339Nano))
AssertEqual(t, expected, buf.String())
}

Expand All @@ -31,7 +44,7 @@ func TestHandler_NoColor(t *testing.T) {
rec := slog.NewRecord(now, slog.LevelInfo, "foobar", 0)
AssertNoError(t, h.Handle(context.Background(), rec))

expected := fmt.Sprintf("%s INF foobar\r\n", now.Format(time.DateTime))
expected := fmt.Sprintf("%s INF foobar\n", now.Format(time.DateTime))
AssertEqual(t, expected, buf.String())
}

Expand Down Expand Up @@ -63,7 +76,7 @@ func TestHandler_Attr(t *testing.T) {
)
AssertNoError(t, h.Handle(context.Background(), rec))

expected := fmt.Sprintf("%s INF foobar bool=true int=-12 uint=12 float=3.14 foo=bar time=%s dur=1s group.foo=bar group.subgroup.foo=bar err=the error stringer=stringer nostringer={bar}\r\n", now.Format(time.DateTime), now.Format(time.RFC3339))
expected := fmt.Sprintf("%s INF foobar bool=true int=-12 uint=12 float=3.14 foo=bar time=%s dur=1s group.foo=bar group.subgroup.foo=bar err=the error stringer=stringer nostringer={bar}\n", now.Format(time.DateTime), now.Format(time.DateTime))
AssertEqual(t, expected, buf.String())
}

Expand All @@ -84,12 +97,12 @@ func TestHandler_WithAttr(t *testing.T) {
})
AssertNoError(t, h2.Handle(context.Background(), rec))

expected := fmt.Sprintf("%s INF foobar bool=true int=-12 uint=12 float=3.14 foo=bar time=%s dur=1s group.foo=bar group.subgroup.foo=bar\r\n", now.Format(time.DateTime), now.Format(time.RFC3339))
expected := fmt.Sprintf("%s INF foobar bool=true int=-12 uint=12 float=3.14 foo=bar time=%s dur=1s group.foo=bar group.subgroup.foo=bar\n", now.Format(time.DateTime), now.Format(time.DateTime))
AssertEqual(t, expected, buf.String())

buf.Reset()
AssertNoError(t, h.Handle(context.Background(), rec))
AssertEqual(t, fmt.Sprintf("%s INF foobar\r\n", now.Format(time.DateTime)), buf.String())
AssertEqual(t, fmt.Sprintf("%s INF foobar\n", now.Format(time.DateTime)), buf.String())
}

func TestHandler_WithGroup(t *testing.T) {
Expand All @@ -100,31 +113,31 @@ func TestHandler_WithGroup(t *testing.T) {
rec.Add("int", 12)
h2 := h.WithGroup("group1").WithAttrs([]slog.Attr{slog.String("foo", "bar")})
AssertNoError(t, h2.Handle(context.Background(), rec))
expected := fmt.Sprintf("%s INF foobar group1.foo=bar group1.int=12\r\n", now.Format(time.DateTime))
expected := fmt.Sprintf("%s INF foobar group1.foo=bar group1.int=12\n", now.Format(time.DateTime))
AssertEqual(t, expected, buf.String())
buf.Reset()

h3 := h2.WithGroup("group2")
AssertNoError(t, h3.Handle(context.Background(), rec))
expected = fmt.Sprintf("%s INF foobar group1.foo=bar group1.group2.int=12\r\n", now.Format(time.DateTime))
expected = fmt.Sprintf("%s INF foobar group1.foo=bar group1.group2.int=12\n", now.Format(time.DateTime))
AssertEqual(t, expected, buf.String())

buf.Reset()
AssertNoError(t, h.Handle(context.Background(), rec))
AssertEqual(t, fmt.Sprintf("%s INF foobar int=12\r\n", now.Format(time.DateTime)), buf.String())
AssertEqual(t, fmt.Sprintf("%s INF foobar int=12\n", now.Format(time.DateTime)), buf.String())
}

func TestHandler_Levels(t *testing.T) {
levels := map[slog.Level]string{
slog.LevelDebug - 1: "???",
slog.LevelDebug - 1: "DBG-1",
slog.LevelDebug: "DBG",
slog.LevelDebug + 1: "DBG",
slog.LevelDebug + 1: "DBG+1",
slog.LevelInfo: "INF",
slog.LevelInfo + 1: "INF",
slog.LevelInfo + 1: "INF+1",
slog.LevelWarn: "WRN",
slog.LevelWarn + 1: "WRN",
slog.LevelWarn + 1: "WRN+1",
slog.LevelError: "ERR",
slog.LevelError + 1: "ERR",
slog.LevelError + 1: "ERR+1",
}

for l := range levels {
Expand All @@ -137,7 +150,7 @@ func TestHandler_Levels(t *testing.T) {
rec := slog.NewRecord(now, ll, "foobar", 0)
if ll >= l {
AssertNoError(t, h.Handle(context.Background(), rec))
AssertEqual(t, fmt.Sprintf("%s %s foobar\r\n", now.Format(time.DateTime), s), buf.String())
AssertEqual(t, fmt.Sprintf("%s %s foobar\n", now.Format(time.DateTime), s), buf.String())
buf.Reset()
}
}
Expand All @@ -155,10 +168,10 @@ func TestHandler_Source(t *testing.T) {
AssertNoError(t, h.Handle(context.Background(), rec))
cwd, _ := os.Getwd()
file, _ = filepath.Rel(cwd, file)
AssertEqual(t, fmt.Sprintf("%s INF %s:%d > foobar\r\n", now.Format(time.DateTime), file, line), buf.String())
AssertEqual(t, fmt.Sprintf("%s INF %s:%d > foobar\n", now.Format(time.DateTime), file, line), buf.String())
buf.Reset()
AssertNoError(t, h2.Handle(context.Background(), rec))
AssertEqual(t, fmt.Sprintf("%s INF foobar\r\n", now.Format(time.DateTime)), buf.String())
AssertEqual(t, fmt.Sprintf("%s INF foobar\n", now.Format(time.DateTime)), buf.String())
}

func TestHandler_Err(t *testing.T) {
Expand Down

0 comments on commit e094ac7

Please sign in to comment.