fiber/log/default_test.go

441 lines
10 KiB
Go

package log
import (
"bytes"
"context"
"log"
"os"
"testing"
"github.com/stretchr/testify/require"
)
const work = "work"
func initDefaultLogger() {
logger = &defaultLogger{
stdlog: log.New(os.Stderr, "", 0),
depth: 4,
}
}
type byteSliceWriter struct {
b []byte
}
func (w *byteSliceWriter) Write(p []byte) (int, error) {
w.b = append(w.b, p...)
return len(p), nil
}
func Test_WithContextCaller(t *testing.T) {
logger = &defaultLogger{
stdlog: log.New(os.Stderr, "", log.Lshortfile),
depth: 4,
}
var w byteSliceWriter
SetOutput(&w)
ctx := context.TODO()
WithContext(ctx).Info("")
Info("")
require.Equal(t, "default_test.go:41: [Info] \ndefault_test.go:42: [Info] \n", string(w.b))
}
func Test_DefaultLogger(t *testing.T) {
initDefaultLogger()
var w byteSliceWriter
SetOutput(&w)
Trace("trace work")
Debug("received work order")
Info("starting work")
Warn("work may fail")
Error("work failed")
require.Panics(t, func() {
Panic("work panic")
})
require.Equal(t, "[Trace] trace work\n"+
"[Debug] received work order\n"+
"[Info] starting work\n"+
"[Warn] work may fail\n"+
"[Error] work failed\n"+
"[Panic] work panic\n", string(w.b))
}
func Test_DefaultFormatLogger(t *testing.T) {
initDefaultLogger()
var w byteSliceWriter
SetOutput(&w)
Tracef("trace %s", work)
Debugf("received %s order", work)
Infof("starting %s", work)
Warnf("%s may fail", work)
Errorf("%s failed", work)
require.Panics(t, func() {
Panicf("%s panic", work)
})
require.Equal(t, "[Trace] trace work\n"+
"[Debug] received work order\n"+
"[Info] starting work\n"+
"[Warn] work may fail\n"+
"[Error] work failed\n"+
"[Panic] work panic\n", string(w.b))
}
func Test_CtxLogger(t *testing.T) {
initDefaultLogger()
var w byteSliceWriter
SetOutput(&w)
ctx := context.Background()
WithContext(ctx).Tracef("trace %s", work)
WithContext(ctx).Debugf("received %s order", work)
WithContext(ctx).Infof("starting %s", work)
WithContext(ctx).Warnf("%s may fail", work)
WithContext(ctx).Errorf("%s failed %d", work, 50)
require.Panics(t, func() {
WithContext(ctx).Panicf("%s panic", work)
})
require.Equal(t, "[Trace] trace work\n"+
"[Debug] received work order\n"+
"[Info] starting work\n"+
"[Warn] work may fail\n"+
"[Error] work failed 50\n"+
"[Panic] work panic\n", string(w.b))
}
func Test_LogfKeyAndValues(t *testing.T) {
tests := []struct {
name string
format string
wantOutput string
fmtArgs []any
keysAndValues []any
level Level
}{
{
name: "test logf with debug level and key-values",
level: LevelDebug,
format: "",
fmtArgs: nil,
keysAndValues: []any{"name", "Bob", "age", 30},
wantOutput: "[Debug] name=Bob age=30\n",
},
{
name: "test logf with info level and key-values",
level: LevelInfo,
format: "",
fmtArgs: nil,
keysAndValues: []any{"status", "ok", "code", 200},
wantOutput: "[Info] status=ok code=200\n",
},
{
name: "test logf with warn level and key-values",
level: LevelWarn,
format: "",
fmtArgs: nil,
keysAndValues: []any{"error", "not found", "id", 123},
wantOutput: "[Warn] error=not found id=123\n",
},
{
name: "test logf with format and key-values",
level: LevelWarn,
format: "test",
fmtArgs: nil,
keysAndValues: []any{"error", "not found", "id", 123},
wantOutput: "[Warn] test error=not found id=123\n",
},
{
name: "test logf with one key",
level: LevelWarn,
format: "",
fmtArgs: nil,
keysAndValues: []any{"error"},
wantOutput: "[Warn] error=KEYVALS UNPAIRED\n",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var buf bytes.Buffer
l := &defaultLogger{
stdlog: log.New(&buf, "", 0),
level: tt.level,
depth: 4,
}
l.privateLogw(tt.level, tt.format, tt.keysAndValues)
require.Equal(t, tt.wantOutput, buf.String())
})
}
}
func Test_SetLevel(t *testing.T) {
setLogger := &defaultLogger{
stdlog: log.New(os.Stderr, "", log.LstdFlags|log.Lshortfile|log.Lmicroseconds),
depth: 4,
}
setLogger.SetLevel(LevelTrace)
require.Equal(t, LevelTrace, setLogger.level)
require.Equal(t, LevelTrace.toString(), setLogger.level.toString())
setLogger.SetLevel(LevelDebug)
require.Equal(t, LevelDebug, setLogger.level)
require.Equal(t, LevelDebug.toString(), setLogger.level.toString())
setLogger.SetLevel(LevelInfo)
require.Equal(t, LevelInfo, setLogger.level)
require.Equal(t, LevelInfo.toString(), setLogger.level.toString())
setLogger.SetLevel(LevelWarn)
require.Equal(t, LevelWarn, setLogger.level)
require.Equal(t, LevelWarn.toString(), setLogger.level.toString())
setLogger.SetLevel(LevelError)
require.Equal(t, LevelError, setLogger.level)
require.Equal(t, LevelError.toString(), setLogger.level.toString())
setLogger.SetLevel(LevelFatal)
require.Equal(t, LevelFatal, setLogger.level)
require.Equal(t, LevelFatal.toString(), setLogger.level.toString())
setLogger.SetLevel(LevelPanic)
require.Equal(t, LevelPanic, setLogger.level)
require.Equal(t, LevelPanic.toString(), setLogger.level.toString())
setLogger.SetLevel(8)
require.Equal(t, 8, int(setLogger.level))
require.Equal(t, "[?8] ", setLogger.level.toString())
}
func Test_Logger(t *testing.T) {
underlyingLogger := log.New(os.Stderr, "", log.LstdFlags|log.Lshortfile|log.Lmicroseconds)
setLogger := &defaultLogger{
stdlog: underlyingLogger,
depth: 4,
}
require.Equal(t, underlyingLogger, setLogger.Logger())
logger, ok := setLogger.Logger().(*log.Logger)
require.True(t, ok)
logger.SetFlags(log.LstdFlags | log.Lshortfile | log.Lmicroseconds)
require.Equal(t, log.LstdFlags|log.Lshortfile|log.Lmicroseconds, setLogger.stdlog.Flags())
}
func Test_Debugw(t *testing.T) {
initDefaultLogger()
var w byteSliceWriter
SetOutput(&w)
msg := "debug work"
keysAndValues := []any{"key1", "value1", "key2", "value2"}
Debugw(msg, keysAndValues...)
require.Equal(t, "[Debug] debug work key1=value1 key2=value2\n", string(w.b))
}
func Test_Infow(t *testing.T) {
initDefaultLogger()
var w byteSliceWriter
SetOutput(&w)
msg := "info work"
keysAndValues := []any{"key1", "value1", "key2", "value2"}
Infow(msg, keysAndValues...)
require.Equal(t, "[Info] info work key1=value1 key2=value2\n", string(w.b))
}
func Test_Warnw(t *testing.T) {
initDefaultLogger()
var w byteSliceWriter
SetOutput(&w)
msg := "warning work"
keysAndValues := []any{"key1", "value1", "key2", "value2"}
Warnw(msg, keysAndValues...)
require.Equal(t, "[Warn] warning work key1=value1 key2=value2\n", string(w.b))
}
func Test_Errorw(t *testing.T) {
initDefaultLogger()
var w byteSliceWriter
SetOutput(&w)
msg := "error work"
keysAndValues := []any{"key1", "value1", "key2", "value2"}
Errorw(msg, keysAndValues...)
require.Equal(t, "[Error] error work key1=value1 key2=value2\n", string(w.b))
}
func Test_Panicw(t *testing.T) {
initDefaultLogger()
var w byteSliceWriter
SetOutput(&w)
msg := "panic work"
keysAndValues := []any{"key1", "value1", "key2", "value2"}
require.Panics(t, func() {
Panicw(msg, keysAndValues...)
})
require.Equal(t, "[Panic] panic work key1=value1 key2=value2\n", string(w.b))
}
func Test_Tracew(t *testing.T) {
initDefaultLogger()
var w byteSliceWriter
SetOutput(&w)
msg := "trace work"
keysAndValues := []any{"key1", "value1", "key2", "value2"}
Tracew(msg, keysAndValues...)
require.Equal(t, "[Trace] trace work key1=value1 key2=value2\n", string(w.b))
}
func Benchmark_LogfKeyAndValues(b *testing.B) {
tests := []struct {
name string
format string
keysAndValues []any
level Level
}{
{
name: "test logf with debug level and key-values",
level: LevelDebug,
format: "",
keysAndValues: []any{"name", "Bob", "age", 30},
},
{
name: "test logf with info level and key-values",
level: LevelInfo,
format: "",
keysAndValues: []any{"status", "ok", "code", 200},
},
{
name: "test logf with warn level and key-values",
level: LevelWarn,
format: "",
keysAndValues: []any{"error", "not found", "id", 123},
},
{
name: "test logf with format and key-values",
level: LevelWarn,
format: "test",
keysAndValues: []any{"error", "not found", "id", 123},
},
{
name: "test logf with one key",
level: LevelWarn,
format: "",
keysAndValues: []any{"error"},
},
}
for _, tt := range tests {
b.Run(tt.name, func(bb *testing.B) {
var buf bytes.Buffer
l := &defaultLogger{
stdlog: log.New(&buf, "", 0),
level: tt.level,
depth: 4,
}
bb.ReportAllocs()
bb.ResetTimer()
for i := 0; i < bb.N; i++ {
l.privateLogw(tt.level, tt.format, tt.keysAndValues)
}
})
}
}
func Benchmark_LogfKeyAndValues_Parallel(b *testing.B) {
tests := []struct {
name string
format string
keysAndValues []any
level Level
}{
{
name: "debug level with key-values",
level: LevelDebug,
format: "",
keysAndValues: []any{"name", "Bob", "age", 30},
},
{
name: "info level with key-values",
level: LevelInfo,
format: "",
keysAndValues: []any{"status", "ok", "code", 200},
},
{
name: "warn level with key-values",
level: LevelWarn,
format: "",
keysAndValues: []any{"error", "not found", "id", 123},
},
{
name: "warn level with format and key-values",
level: LevelWarn,
format: "test",
keysAndValues: []any{"error", "not found", "id", 123},
},
{
name: "warn level with one key",
level: LevelWarn,
format: "",
keysAndValues: []any{"error"},
},
}
for _, tt := range tests {
b.Run(tt.name, func(bb *testing.B) {
bb.ReportAllocs()
bb.ResetTimer()
bb.RunParallel(func(pb *testing.PB) {
var buf bytes.Buffer
l := &defaultLogger{
stdlog: log.New(&buf, "", 0),
level: tt.level,
depth: 4,
}
for pb.Next() {
l.privateLogw(tt.level, tt.format, tt.keysAndValues)
}
})
})
}
}