Skip to content

Commit

Permalink
ADD: logger.Logf() formats message
Browse files Browse the repository at this point in the history
  • Loading branch information
whoisnian committed Nov 19, 2023
1 parent d091f16 commit 959024b
Show file tree
Hide file tree
Showing 2 changed files with 136 additions and 1 deletion.
52 changes: 52 additions & 0 deletions logger/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ package logger

import (
"context"
"fmt"
"log/slog"
"os"
"runtime"
Expand Down Expand Up @@ -112,38 +113,75 @@ func (l *Logger) Debug(msg string, args ...any) {
l.log(context.Background(), LevelDebug, msg, args...)
}

// Debugf formats message at LevelDebug.
func (l *Logger) Debugf(format string, args ...any) {
l.logf(context.Background(), LevelDebug, format, args...)
}

// Info logs at LevelInfo.
func (l *Logger) Info(msg string, args ...any) {
l.log(context.Background(), LevelInfo, msg, args...)
}

// Infof formats message at LevelInfo.
func (l *Logger) Infof(format string, args ...any) {
l.logf(context.Background(), LevelInfo, format, args...)
}

// Warn logs at LevelWarn.
func (l *Logger) Warn(msg string, args ...any) {
l.log(context.Background(), LevelWarn, msg, args...)
}

// Warnf formats message at LevelWarn.
func (l *Logger) Warnf(format string, args ...any) {
l.logf(context.Background(), LevelWarn, format, args...)
}

// Error logs at LevelError.
func (l *Logger) Error(msg string, args ...any) {
l.log(context.Background(), LevelError, msg, args...)
}

// Errorf formats message at LevelError.
func (l *Logger) Errorf(format string, args ...any) {
l.logf(context.Background(), LevelError, format, args...)
}

// Panic logs at LevelError and follows with a call to panic(msg).
func (l *Logger) Panic(msg string, args ...any) {
l.log(context.Background(), LevelError, msg, args...)
panic(msg)
}

// Panicf formats message at LevelError and follows with a call to panic(message).
func (l *Logger) Panicf(format string, args ...any) {
l.logf(context.Background(), LevelError, format, args...)
panic(fmt.Sprintf(format, args...))
}

// Fatal logs at LevelFatal and follows with a call to os.Exit(1).
func (l *Logger) Fatal(msg string, args ...any) {
l.log(context.Background(), LevelFatal, msg, args...)
os.Exit(1)
}

// Fatalf formats message at LevelFatal and follows with a call to os.Exit(1).
func (l *Logger) Fatalf(format string, args ...any) {
l.logf(context.Background(), LevelFatal, format, args...)
os.Exit(1)
}

// Log emits a log record with the current time and the given level and message.
func (l *Logger) Log(ctx context.Context, level slog.Level, msg string, args ...any) {
l.log(ctx, level, msg, args...)
}

// Logf emits a log record with the current time and the given level and format message.
func (l *Logger) Logf(ctx context.Context, level slog.Level, format string, args ...any) {
l.logf(ctx, level, format, args...)
}

// LogAttrs is a more efficient version of [Logger.Log] that accepts only Attrs.
func (l *Logger) LogAttrs(ctx context.Context, level slog.Level, msg string, attrs ...slog.Attr) {
l.logAttrs(ctx, level, msg, attrs...)
Expand All @@ -164,6 +202,20 @@ func (l *Logger) log(ctx context.Context, level slog.Level, msg string, args ...
return l.h.Handle(ctx, r)
}

func (l *Logger) logf(ctx context.Context, level slog.Level, format string, args ...any) error {
if !l.h.Enabled(level) {
return nil
}
var pc uintptr
if l.h.IsAddSource() {
var pcs [1]uintptr
runtime.Callers(3, pcs[:])
pc = pcs[0]
}
r := slog.NewRecord(time.Now(), level, fmt.Sprintf(format, args...), pc)
return l.h.Handle(ctx, r)
}

func (l *Logger) logAttrs(ctx context.Context, level slog.Level, msg string, attrs ...slog.Attr) error {
if !l.h.Enabled(level) {
return nil
Expand Down
85 changes: 84 additions & 1 deletion logger/logger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package logger
import (
"bytes"
"context"
"errors"
"log/slog"
"os"
"os/exec"
Expand Down Expand Up @@ -136,6 +137,49 @@ func TestLoggerOutput(t *testing.T) {
}
}

func TestLoggerOutputf(t *testing.T) {
var buf bytes.Buffer
var l *Logger = New(NewTextHandler(&buf, NewOptions(LevelInfo, false, false)))

// Infof
l.Infof("from:%s", "192.168.0.2")
got, want := buf.String(), `^time=`+reTextTime+` level=INFO msg=from:192.168.0.2\n$`
if !regexp.MustCompile(want).MatchString(got) {
t.Errorf("Logger.Infof() got %q, want matched by %s", got, want)
}

// Debugf
buf.Reset()
l.Debugf("cost:%ds", 5)
if buf.String() != "" {
t.Errorf("Logger.Debugf() got %q, want %q", got, "")
}

// Warnf
buf.Reset()
l.Warnf("cost:%.2fs", 2.5)
got, want = buf.String(), `^time=`+reTextTime+` level=WARN msg=cost:2.50s\n$`
if !regexp.MustCompile(want).MatchString(got) {
t.Errorf("Logger.Warnf() got %q, want matched by %s", got, want)
}

// Errorf
buf.Reset()
l.Errorf("err:%s", errors.New("invalid"))
got, want = buf.String(), `^time=`+reTextTime+` level=ERROR msg=err:invalid\n$`
if !regexp.MustCompile(want).MatchString(got) {
t.Errorf("Logger.Errorf() got %q, want matched by %s", got, want)
}

// Logf
buf.Reset()
l.Logf(context.Background(), LevelInfo, "finished:%d%%", 80)
got, want = buf.String(), `^time=`+reTextTime+` level=INFO msg=finished:80%\n$`
if !regexp.MustCompile(want).MatchString(got) {
t.Errorf("Logger.Logf() got %q, want matched by %s", got, want)
}
}

func TestLoggerPanic(t *testing.T) {
var buf bytes.Buffer
var l *Logger = New(NewTextHandler(&buf, NewOptions(LevelInfo, false, false)))
Expand All @@ -152,6 +196,22 @@ func TestLoggerPanic(t *testing.T) {
t.Fatal("Logger.Panic() should get panic")
}

func TestLoggerPanicf(t *testing.T) {
var buf bytes.Buffer
var l *Logger = New(NewTextHandler(&buf, NewOptions(LevelInfo, false, false)))
want := `^time=` + reTextTime + ` level=ERROR msg="err: invalid addr"\n$`

defer func() {
got := buf.String()
if recover() == nil || !regexp.MustCompile(want).MatchString(got) {
t.Fatalf("Logger.Panicf() got %q, want matched by %s", got, want)
}
}()

l.Panicf("err: %s", errors.New("invalid addr"))
t.Fatal("Logger.Panicf() should get panic")
}

func TestLoggerFatal(t *testing.T) {
// https://stackoverflow.com/a/33404435/11239247
if os.Getenv("TEST_FATAL") == "true" {
Expand All @@ -168,7 +228,30 @@ func TestLoggerFatal(t *testing.T) {
if e, ok := err.(*exec.ExitError); ok && e.ExitCode() == 1 {
got := stderr.String()
if !regexp.MustCompile(want).MatchString(got) {
t.Fatalf("Logger.Panic() got %q, want matched by %s", got, want)
t.Fatalf("Logger.Fatal() got %q, want matched by %s", got, want)
}
return
}
t.Fatalf("process ran with err %v, want exit status 1", err)
}

func TestLoggerFatalf(t *testing.T) {
// https://stackoverflow.com/a/33404435/11239247
if os.Getenv("TEST_FATAL") == "true" {
l := New(NewTextHandler(os.Stderr, NewOptions(LevelInfo, false, false)))
l.Fatalf("%[3]*.[2]*[1]f", 12.0, 2, 6)
return
}
want := `^time=` + reTextTime + ` level=FATAL msg=" 12.00"\n$`
var stderr bytes.Buffer
cmd := exec.Command(os.Args[0], "-test.run=TestLoggerFatalf")
cmd.Env = append(os.Environ(), "TEST_FATAL=true")
cmd.Stderr = &stderr
err := cmd.Run()
if e, ok := err.(*exec.ExitError); ok && e.ExitCode() == 1 {
got := stderr.String()
if !regexp.MustCompile(want).MatchString(got) {
t.Fatalf("Logger.Fatalf() got %q, want matched by %s", got, want)
}
return
}
Expand Down

0 comments on commit 959024b

Please sign in to comment.