You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
358 lines
9.0 KiB
Go
358 lines
9.0 KiB
Go
package logx
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"strings"
|
|
"sync/atomic"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"go.opentelemetry.io/otel"
|
|
sdktrace "go.opentelemetry.io/otel/sdk/trace"
|
|
)
|
|
|
|
func TestTraceLog(t *testing.T) {
|
|
SetLevel(InfoLevel)
|
|
w := new(mockWriter)
|
|
old := writer.Swap(w)
|
|
writer.lock.RLock()
|
|
defer func() {
|
|
writer.lock.RUnlock()
|
|
writer.Store(old)
|
|
}()
|
|
|
|
otp := otel.GetTracerProvider()
|
|
tp := sdktrace.NewTracerProvider(sdktrace.WithSampler(sdktrace.AlwaysSample()))
|
|
otel.SetTracerProvider(tp)
|
|
defer otel.SetTracerProvider(otp)
|
|
|
|
ctx, span := tp.Tracer("trace-id").Start(context.Background(), "span-id")
|
|
defer span.End()
|
|
|
|
WithContext(ctx).Info(testlog)
|
|
validate(t, w.String(), true, true)
|
|
}
|
|
|
|
func TestTraceDebug(t *testing.T) {
|
|
w := new(mockWriter)
|
|
old := writer.Swap(w)
|
|
writer.lock.RLock()
|
|
defer func() {
|
|
writer.lock.RUnlock()
|
|
writer.Store(old)
|
|
}()
|
|
|
|
otp := otel.GetTracerProvider()
|
|
tp := sdktrace.NewTracerProvider(sdktrace.WithSampler(sdktrace.AlwaysSample()))
|
|
otel.SetTracerProvider(tp)
|
|
defer otel.SetTracerProvider(otp)
|
|
|
|
ctx, span := tp.Tracer("foo").Start(context.Background(), "bar")
|
|
defer span.End()
|
|
|
|
l := WithContext(ctx)
|
|
SetLevel(DebugLevel)
|
|
l.WithDuration(time.Second).Debug(testlog)
|
|
assert.True(t, strings.Contains(w.String(), traceKey))
|
|
assert.True(t, strings.Contains(w.String(), spanKey))
|
|
w.Reset()
|
|
l.WithDuration(time.Second).Debugf(testlog)
|
|
validate(t, w.String(), true, true)
|
|
w.Reset()
|
|
l.WithDuration(time.Second).Debugv(testlog)
|
|
validate(t, w.String(), true, true)
|
|
w.Reset()
|
|
l.WithDuration(time.Second).Debugv(testobj)
|
|
validateContentType(t, w.String(), map[string]any{}, true, true)
|
|
w.Reset()
|
|
l.WithDuration(time.Second).Debugw(testlog, Field("foo", "bar"))
|
|
validate(t, w.String(), true, true)
|
|
assert.True(t, strings.Contains(w.String(), "foo"), w.String())
|
|
assert.True(t, strings.Contains(w.String(), "bar"), w.String())
|
|
}
|
|
|
|
func TestTraceError(t *testing.T) {
|
|
w := new(mockWriter)
|
|
old := writer.Swap(w)
|
|
writer.lock.RLock()
|
|
defer func() {
|
|
writer.lock.RUnlock()
|
|
writer.Store(old)
|
|
}()
|
|
|
|
otp := otel.GetTracerProvider()
|
|
tp := sdktrace.NewTracerProvider(sdktrace.WithSampler(sdktrace.AlwaysSample()))
|
|
otel.SetTracerProvider(tp)
|
|
defer otel.SetTracerProvider(otp)
|
|
|
|
ctx, span := tp.Tracer("trace-id").Start(context.Background(), "span-id")
|
|
defer span.End()
|
|
|
|
var nilCtx context.Context
|
|
l := WithContext(context.Background())
|
|
l = l.WithContext(nilCtx)
|
|
l = l.WithContext(ctx)
|
|
SetLevel(ErrorLevel)
|
|
l.WithDuration(time.Second).Error(testlog)
|
|
validate(t, w.String(), true, true)
|
|
w.Reset()
|
|
l.WithDuration(time.Second).Errorf(testlog)
|
|
validate(t, w.String(), true, true)
|
|
w.Reset()
|
|
l.WithDuration(time.Second).Errorv(testlog)
|
|
validate(t, w.String(), true, true)
|
|
w.Reset()
|
|
l.WithDuration(time.Second).Errorv(testobj)
|
|
validateContentType(t, w.String(), map[string]any{}, true, true)
|
|
w.Reset()
|
|
l.WithDuration(time.Second).Errorw(testlog, Field("basket", "ball"))
|
|
validate(t, w.String(), true, true)
|
|
assert.True(t, strings.Contains(w.String(), "basket"), w.String())
|
|
assert.True(t, strings.Contains(w.String(), "ball"), w.String())
|
|
}
|
|
|
|
func TestTraceInfo(t *testing.T) {
|
|
w := new(mockWriter)
|
|
old := writer.Swap(w)
|
|
writer.lock.RLock()
|
|
defer func() {
|
|
writer.lock.RUnlock()
|
|
writer.Store(old)
|
|
}()
|
|
|
|
otp := otel.GetTracerProvider()
|
|
tp := sdktrace.NewTracerProvider(sdktrace.WithSampler(sdktrace.AlwaysSample()))
|
|
otel.SetTracerProvider(tp)
|
|
defer otel.SetTracerProvider(otp)
|
|
|
|
ctx, span := tp.Tracer("trace-id").Start(context.Background(), "span-id")
|
|
defer span.End()
|
|
|
|
SetLevel(InfoLevel)
|
|
l := WithContext(ctx)
|
|
l.WithDuration(time.Second).Info(testlog)
|
|
validate(t, w.String(), true, true)
|
|
w.Reset()
|
|
l.WithDuration(time.Second).Infof(testlog)
|
|
validate(t, w.String(), true, true)
|
|
w.Reset()
|
|
l.WithDuration(time.Second).Infov(testlog)
|
|
validate(t, w.String(), true, true)
|
|
w.Reset()
|
|
l.WithDuration(time.Second).Infov(testobj)
|
|
validateContentType(t, w.String(), map[string]any{}, true, true)
|
|
w.Reset()
|
|
l.WithDuration(time.Second).Infow(testlog, Field("basket", "ball"))
|
|
validate(t, w.String(), true, true)
|
|
assert.True(t, strings.Contains(w.String(), "basket"), w.String())
|
|
assert.True(t, strings.Contains(w.String(), "ball"), w.String())
|
|
}
|
|
|
|
func TestTraceInfoConsole(t *testing.T) {
|
|
old := atomic.SwapUint32(&encoding, jsonEncodingType)
|
|
defer atomic.StoreUint32(&encoding, old)
|
|
|
|
w := new(mockWriter)
|
|
o := writer.Swap(w)
|
|
writer.lock.RLock()
|
|
defer func() {
|
|
writer.lock.RUnlock()
|
|
writer.Store(o)
|
|
}()
|
|
|
|
otp := otel.GetTracerProvider()
|
|
tp := sdktrace.NewTracerProvider(sdktrace.WithSampler(sdktrace.AlwaysSample()))
|
|
otel.SetTracerProvider(tp)
|
|
defer otel.SetTracerProvider(otp)
|
|
|
|
ctx, span := tp.Tracer("trace-id").Start(context.Background(), "span-id")
|
|
defer span.End()
|
|
|
|
l := WithContext(ctx)
|
|
SetLevel(InfoLevel)
|
|
l.WithDuration(time.Second).Info(testlog)
|
|
validate(t, w.String(), true, true)
|
|
w.Reset()
|
|
l.WithDuration(time.Second).Infof(testlog)
|
|
validate(t, w.String(), true, true)
|
|
w.Reset()
|
|
l.WithDuration(time.Second).Infov(testlog)
|
|
validate(t, w.String(), true, true)
|
|
w.Reset()
|
|
l.WithDuration(time.Second).Infov(testobj)
|
|
validateContentType(t, w.String(), map[string]any{}, true, true)
|
|
}
|
|
|
|
func TestTraceSlow(t *testing.T) {
|
|
w := new(mockWriter)
|
|
old := writer.Swap(w)
|
|
writer.lock.RLock()
|
|
defer func() {
|
|
writer.lock.RUnlock()
|
|
writer.Store(old)
|
|
}()
|
|
|
|
otp := otel.GetTracerProvider()
|
|
tp := sdktrace.NewTracerProvider(sdktrace.WithSampler(sdktrace.AlwaysSample()))
|
|
otel.SetTracerProvider(tp)
|
|
defer otel.SetTracerProvider(otp)
|
|
|
|
ctx, span := tp.Tracer("trace-id").Start(context.Background(), "span-id")
|
|
defer span.End()
|
|
|
|
l := WithContext(ctx)
|
|
SetLevel(InfoLevel)
|
|
l.WithDuration(time.Second).Slow(testlog)
|
|
assert.True(t, strings.Contains(w.String(), traceKey))
|
|
assert.True(t, strings.Contains(w.String(), spanKey))
|
|
w.Reset()
|
|
l.WithDuration(time.Second).Slowf(testlog)
|
|
validate(t, w.String(), true, true)
|
|
w.Reset()
|
|
l.WithDuration(time.Second).Slowv(testlog)
|
|
validate(t, w.String(), true, true)
|
|
w.Reset()
|
|
l.WithDuration(time.Second).Slowv(testobj)
|
|
validateContentType(t, w.String(), map[string]any{}, true, true)
|
|
w.Reset()
|
|
l.WithDuration(time.Second).Sloww(testlog, Field("basket", "ball"))
|
|
validate(t, w.String(), true, true)
|
|
assert.True(t, strings.Contains(w.String(), "basket"), w.String())
|
|
assert.True(t, strings.Contains(w.String(), "ball"), w.String())
|
|
}
|
|
|
|
func TestTraceWithoutContext(t *testing.T) {
|
|
w := new(mockWriter)
|
|
old := writer.Swap(w)
|
|
writer.lock.RLock()
|
|
defer func() {
|
|
writer.lock.RUnlock()
|
|
writer.Store(old)
|
|
}()
|
|
|
|
l := WithContext(context.Background())
|
|
SetLevel(InfoLevel)
|
|
l.WithDuration(time.Second).Info(testlog)
|
|
validate(t, w.String(), false, false)
|
|
w.Reset()
|
|
l.WithDuration(time.Second).Infof(testlog)
|
|
validate(t, w.String(), false, false)
|
|
}
|
|
|
|
func TestLogWithFields(t *testing.T) {
|
|
w := new(mockWriter)
|
|
old := writer.Swap(w)
|
|
writer.lock.RLock()
|
|
defer func() {
|
|
writer.lock.RUnlock()
|
|
writer.Store(old)
|
|
}()
|
|
|
|
ctx := ContextWithFields(context.Background(), Field("foo", "bar"))
|
|
l := WithContext(ctx)
|
|
SetLevel(InfoLevel)
|
|
l.Info(testlog)
|
|
|
|
var val mockValue
|
|
assert.Nil(t, json.Unmarshal([]byte(w.String()), &val))
|
|
assert.Equal(t, "bar", val.Foo)
|
|
}
|
|
|
|
func TestLogWithCallerSkip(t *testing.T) {
|
|
w := new(mockWriter)
|
|
old := writer.Swap(w)
|
|
writer.lock.RLock()
|
|
defer func() {
|
|
writer.lock.RUnlock()
|
|
writer.Store(old)
|
|
}()
|
|
|
|
l := WithCallerSkip(1).WithCallerSkip(0)
|
|
p := func(v string) {
|
|
l.Info(v)
|
|
}
|
|
|
|
file, line := getFileLine()
|
|
p(testlog)
|
|
assert.True(t, w.Contains(fmt.Sprintf("%s:%d", file, line+1)))
|
|
|
|
w.Reset()
|
|
l = WithCallerSkip(0).WithCallerSkip(1)
|
|
file, line = getFileLine()
|
|
p(testlog)
|
|
assert.True(t, w.Contains(fmt.Sprintf("%s:%d", file, line+1)))
|
|
}
|
|
|
|
func TestLoggerWithFields(t *testing.T) {
|
|
w := new(mockWriter)
|
|
old := writer.Swap(w)
|
|
writer.lock.RLock()
|
|
defer func() {
|
|
writer.lock.RUnlock()
|
|
writer.Store(old)
|
|
}()
|
|
|
|
l := WithContext(context.Background()).WithFields(Field("foo", "bar"))
|
|
l.Info(testlog)
|
|
|
|
var val mockValue
|
|
assert.Nil(t, json.Unmarshal([]byte(w.String()), &val))
|
|
assert.Equal(t, "bar", val.Foo)
|
|
}
|
|
|
|
func validate(t *testing.T, body string, expectedTrace, expectedSpan bool) {
|
|
var val mockValue
|
|
dec := json.NewDecoder(strings.NewReader(body))
|
|
|
|
for {
|
|
var doc mockValue
|
|
err := dec.Decode(&doc)
|
|
if err == io.EOF {
|
|
// all done
|
|
break
|
|
}
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
val = doc
|
|
}
|
|
|
|
assert.Equal(t, expectedTrace, len(val.Trace) > 0, body)
|
|
assert.Equal(t, expectedSpan, len(val.Span) > 0, body)
|
|
}
|
|
|
|
func validateContentType(t *testing.T, body string, expectedType any, expectedTrace, expectedSpan bool) {
|
|
var val mockValue
|
|
dec := json.NewDecoder(strings.NewReader(body))
|
|
|
|
for {
|
|
var doc mockValue
|
|
err := dec.Decode(&doc)
|
|
if err == io.EOF {
|
|
// all done
|
|
break
|
|
}
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
val = doc
|
|
}
|
|
|
|
assert.IsType(t, expectedType, val.Content, body)
|
|
assert.Equal(t, expectedTrace, len(val.Trace) > 0, body)
|
|
assert.Equal(t, expectedSpan, len(val.Span) > 0, body)
|
|
}
|
|
|
|
type mockValue struct {
|
|
Trace string `json:"trace"`
|
|
Span string `json:"span"`
|
|
Foo string `json:"foo"`
|
|
Content any `json:"content"`
|
|
}
|