github.com/lingyao2333/mo-zero@v1.4.1/core/logx/richlogger_test.go (about)

     1  package logx
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io"
     8  	"strings"
     9  	"sync/atomic"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/stretchr/testify/assert"
    14  	"go.opentelemetry.io/otel"
    15  	sdktrace "go.opentelemetry.io/otel/sdk/trace"
    16  )
    17  
    18  func TestTraceLog(t *testing.T) {
    19  	SetLevel(InfoLevel)
    20  	w := new(mockWriter)
    21  	old := writer.Swap(w)
    22  	writer.lock.RLock()
    23  	defer func() {
    24  		writer.lock.RUnlock()
    25  		writer.Store(old)
    26  	}()
    27  
    28  	otp := otel.GetTracerProvider()
    29  	tp := sdktrace.NewTracerProvider(sdktrace.WithSampler(sdktrace.AlwaysSample()))
    30  	otel.SetTracerProvider(tp)
    31  	defer otel.SetTracerProvider(otp)
    32  
    33  	ctx, span := tp.Tracer("trace-id").Start(context.Background(), "span-id")
    34  	defer span.End()
    35  
    36  	WithContext(ctx).Info(testlog)
    37  	validate(t, w.String(), true, true)
    38  }
    39  
    40  func TestTraceDebug(t *testing.T) {
    41  	w := new(mockWriter)
    42  	old := writer.Swap(w)
    43  	writer.lock.RLock()
    44  	defer func() {
    45  		writer.lock.RUnlock()
    46  		writer.Store(old)
    47  	}()
    48  
    49  	otp := otel.GetTracerProvider()
    50  	tp := sdktrace.NewTracerProvider(sdktrace.WithSampler(sdktrace.AlwaysSample()))
    51  	otel.SetTracerProvider(tp)
    52  	defer otel.SetTracerProvider(otp)
    53  
    54  	ctx, span := tp.Tracer("foo").Start(context.Background(), "bar")
    55  	defer span.End()
    56  
    57  	l := WithContext(ctx)
    58  	SetLevel(DebugLevel)
    59  	l.WithDuration(time.Second).Debug(testlog)
    60  	assert.True(t, strings.Contains(w.String(), traceKey))
    61  	assert.True(t, strings.Contains(w.String(), spanKey))
    62  	w.Reset()
    63  	l.WithDuration(time.Second).Debugf(testlog)
    64  	validate(t, w.String(), true, true)
    65  	w.Reset()
    66  	l.WithDuration(time.Second).Debugv(testlog)
    67  	validate(t, w.String(), true, true)
    68  	w.Reset()
    69  	l.WithDuration(time.Second).Debugw(testlog, Field("foo", "bar"))
    70  	validate(t, w.String(), true, true)
    71  	assert.True(t, strings.Contains(w.String(), "foo"), w.String())
    72  	assert.True(t, strings.Contains(w.String(), "bar"), w.String())
    73  }
    74  
    75  func TestTraceError(t *testing.T) {
    76  	w := new(mockWriter)
    77  	old := writer.Swap(w)
    78  	writer.lock.RLock()
    79  	defer func() {
    80  		writer.lock.RUnlock()
    81  		writer.Store(old)
    82  	}()
    83  
    84  	otp := otel.GetTracerProvider()
    85  	tp := sdktrace.NewTracerProvider(sdktrace.WithSampler(sdktrace.AlwaysSample()))
    86  	otel.SetTracerProvider(tp)
    87  	defer otel.SetTracerProvider(otp)
    88  
    89  	ctx, span := tp.Tracer("trace-id").Start(context.Background(), "span-id")
    90  	defer span.End()
    91  
    92  	var nilCtx context.Context
    93  	l := WithContext(context.Background())
    94  	l = l.WithContext(nilCtx)
    95  	l = l.WithContext(ctx)
    96  	SetLevel(ErrorLevel)
    97  	l.WithDuration(time.Second).Error(testlog)
    98  	validate(t, w.String(), true, true)
    99  	w.Reset()
   100  	l.WithDuration(time.Second).Errorf(testlog)
   101  	validate(t, w.String(), true, true)
   102  	w.Reset()
   103  	l.WithDuration(time.Second).Errorv(testlog)
   104  	validate(t, w.String(), true, true)
   105  	w.Reset()
   106  	l.WithDuration(time.Second).Errorw(testlog, Field("basket", "ball"))
   107  	validate(t, w.String(), true, true)
   108  	assert.True(t, strings.Contains(w.String(), "basket"), w.String())
   109  	assert.True(t, strings.Contains(w.String(), "ball"), w.String())
   110  }
   111  
   112  func TestTraceInfo(t *testing.T) {
   113  	w := new(mockWriter)
   114  	old := writer.Swap(w)
   115  	writer.lock.RLock()
   116  	defer func() {
   117  		writer.lock.RUnlock()
   118  		writer.Store(old)
   119  	}()
   120  
   121  	otp := otel.GetTracerProvider()
   122  	tp := sdktrace.NewTracerProvider(sdktrace.WithSampler(sdktrace.AlwaysSample()))
   123  	otel.SetTracerProvider(tp)
   124  	defer otel.SetTracerProvider(otp)
   125  
   126  	ctx, span := tp.Tracer("trace-id").Start(context.Background(), "span-id")
   127  	defer span.End()
   128  
   129  	SetLevel(InfoLevel)
   130  	l := WithContext(ctx)
   131  	l.WithDuration(time.Second).Info(testlog)
   132  	validate(t, w.String(), true, true)
   133  	w.Reset()
   134  	l.WithDuration(time.Second).Infof(testlog)
   135  	validate(t, w.String(), true, true)
   136  	w.Reset()
   137  	l.WithDuration(time.Second).Infov(testlog)
   138  	validate(t, w.String(), true, true)
   139  	w.Reset()
   140  	l.WithDuration(time.Second).Infow(testlog, Field("basket", "ball"))
   141  	validate(t, w.String(), true, true)
   142  	assert.True(t, strings.Contains(w.String(), "basket"), w.String())
   143  	assert.True(t, strings.Contains(w.String(), "ball"), w.String())
   144  }
   145  
   146  func TestTraceInfoConsole(t *testing.T) {
   147  	old := atomic.SwapUint32(&encoding, jsonEncodingType)
   148  	defer atomic.StoreUint32(&encoding, old)
   149  
   150  	w := new(mockWriter)
   151  	o := writer.Swap(w)
   152  	writer.lock.RLock()
   153  	defer func() {
   154  		writer.lock.RUnlock()
   155  		writer.Store(o)
   156  	}()
   157  
   158  	otp := otel.GetTracerProvider()
   159  	tp := sdktrace.NewTracerProvider(sdktrace.WithSampler(sdktrace.AlwaysSample()))
   160  	otel.SetTracerProvider(tp)
   161  	defer otel.SetTracerProvider(otp)
   162  
   163  	ctx, span := tp.Tracer("trace-id").Start(context.Background(), "span-id")
   164  	defer span.End()
   165  
   166  	l := WithContext(ctx)
   167  	SetLevel(InfoLevel)
   168  	l.WithDuration(time.Second).Info(testlog)
   169  	validate(t, w.String(), true, true)
   170  	w.Reset()
   171  	l.WithDuration(time.Second).Infof(testlog)
   172  	validate(t, w.String(), true, true)
   173  	w.Reset()
   174  	l.WithDuration(time.Second).Infov(testlog)
   175  	validate(t, w.String(), true, true)
   176  }
   177  
   178  func TestTraceSlow(t *testing.T) {
   179  	w := new(mockWriter)
   180  	old := writer.Swap(w)
   181  	writer.lock.RLock()
   182  	defer func() {
   183  		writer.lock.RUnlock()
   184  		writer.Store(old)
   185  	}()
   186  
   187  	otp := otel.GetTracerProvider()
   188  	tp := sdktrace.NewTracerProvider(sdktrace.WithSampler(sdktrace.AlwaysSample()))
   189  	otel.SetTracerProvider(tp)
   190  	defer otel.SetTracerProvider(otp)
   191  
   192  	ctx, span := tp.Tracer("trace-id").Start(context.Background(), "span-id")
   193  	defer span.End()
   194  
   195  	l := WithContext(ctx)
   196  	SetLevel(InfoLevel)
   197  	l.WithDuration(time.Second).Slow(testlog)
   198  	assert.True(t, strings.Contains(w.String(), traceKey))
   199  	assert.True(t, strings.Contains(w.String(), spanKey))
   200  	w.Reset()
   201  	l.WithDuration(time.Second).Slowf(testlog)
   202  	validate(t, w.String(), true, true)
   203  	w.Reset()
   204  	l.WithDuration(time.Second).Slowv(testlog)
   205  	validate(t, w.String(), true, true)
   206  	w.Reset()
   207  	l.WithDuration(time.Second).Sloww(testlog, Field("basket", "ball"))
   208  	validate(t, w.String(), true, true)
   209  	assert.True(t, strings.Contains(w.String(), "basket"), w.String())
   210  	assert.True(t, strings.Contains(w.String(), "ball"), w.String())
   211  }
   212  
   213  func TestTraceWithoutContext(t *testing.T) {
   214  	w := new(mockWriter)
   215  	old := writer.Swap(w)
   216  	writer.lock.RLock()
   217  	defer func() {
   218  		writer.lock.RUnlock()
   219  		writer.Store(old)
   220  	}()
   221  
   222  	l := WithContext(context.Background())
   223  	SetLevel(InfoLevel)
   224  	l.WithDuration(time.Second).Info(testlog)
   225  	validate(t, w.String(), false, false)
   226  	w.Reset()
   227  	l.WithDuration(time.Second).Infof(testlog)
   228  	validate(t, w.String(), false, false)
   229  }
   230  
   231  func TestLogWithFields(t *testing.T) {
   232  	w := new(mockWriter)
   233  	old := writer.Swap(w)
   234  	writer.lock.RLock()
   235  	defer func() {
   236  		writer.lock.RUnlock()
   237  		writer.Store(old)
   238  	}()
   239  
   240  	ctx := ContextWithFields(context.Background(), Field("foo", "bar"))
   241  	l := WithContext(ctx)
   242  	SetLevel(InfoLevel)
   243  	l.Info(testlog)
   244  
   245  	var val mockValue
   246  	assert.Nil(t, json.Unmarshal([]byte(w.String()), &val))
   247  	assert.Equal(t, "bar", val.Foo)
   248  }
   249  
   250  func TestLogWithCallerSkip(t *testing.T) {
   251  	w := new(mockWriter)
   252  	old := writer.Swap(w)
   253  	writer.lock.RLock()
   254  	defer func() {
   255  		writer.lock.RUnlock()
   256  		writer.Store(old)
   257  	}()
   258  
   259  	l := WithCallerSkip(1).WithCallerSkip(0)
   260  	p := func(v string) {
   261  		l.Info(v)
   262  	}
   263  
   264  	file, line := getFileLine()
   265  	p(testlog)
   266  	assert.True(t, w.Contains(fmt.Sprintf("%s:%d", file, line+1)))
   267  
   268  	w.Reset()
   269  	l = WithCallerSkip(0).WithCallerSkip(1)
   270  	file, line = getFileLine()
   271  	p(testlog)
   272  	assert.True(t, w.Contains(fmt.Sprintf("%s:%d", file, line+1)))
   273  }
   274  
   275  func TestLoggerWithFields(t *testing.T) {
   276  	w := new(mockWriter)
   277  	old := writer.Swap(w)
   278  	writer.lock.RLock()
   279  	defer func() {
   280  		writer.lock.RUnlock()
   281  		writer.Store(old)
   282  	}()
   283  
   284  	l := WithContext(context.Background()).WithFields(Field("foo", "bar"))
   285  	l.Info(testlog)
   286  
   287  	var val mockValue
   288  	assert.Nil(t, json.Unmarshal([]byte(w.String()), &val))
   289  	assert.Equal(t, "bar", val.Foo)
   290  }
   291  
   292  func validate(t *testing.T, body string, expectedTrace, expectedSpan bool) {
   293  	var val mockValue
   294  	dec := json.NewDecoder(strings.NewReader(body))
   295  
   296  	for {
   297  		var doc mockValue
   298  		err := dec.Decode(&doc)
   299  		if err == io.EOF {
   300  			// all done
   301  			break
   302  		}
   303  		if err != nil {
   304  			continue
   305  		}
   306  
   307  		val = doc
   308  	}
   309  
   310  	assert.Equal(t, expectedTrace, len(val.Trace) > 0, body)
   311  	assert.Equal(t, expectedSpan, len(val.Span) > 0, body)
   312  }
   313  
   314  type mockValue struct {
   315  	Trace string `json:"trace"`
   316  	Span  string `json:"span"`
   317  	Foo   string `json:"foo"`
   318  }