trpc.group/trpc-go/trpc-go@v1.0.3/log/log_test.go (about)

     1  //
     2  //
     3  // Tencent is pleased to support the open source community by making tRPC available.
     4  //
     5  // Copyright (C) 2023 THL A29 Limited, a Tencent company.
     6  // All rights reserved.
     7  //
     8  // If you have downloaded a copy of the tRPC source code from Tencent,
     9  // please note that tRPC source code is licensed under the  Apache 2.0 License,
    10  // A copy of the Apache 2.0 License is included in this file.
    11  //
    12  //
    13  
    14  package log_test
    15  
    16  import (
    17  	"bytes"
    18  	"context"
    19  	"fmt"
    20  	"path/filepath"
    21  	"runtime"
    22  	"strconv"
    23  	"strings"
    24  	"testing"
    25  
    26  	"github.com/stretchr/testify/assert"
    27  	"github.com/stretchr/testify/require"
    28  	"go.uber.org/zap"
    29  	"go.uber.org/zap/zapcore"
    30  
    31  	trpc "trpc.group/trpc-go/trpc-go"
    32  	"trpc.group/trpc-go/trpc-go/codec"
    33  	"trpc.group/trpc-go/trpc-go/log"
    34  )
    35  
    36  func TestSetLevel(t *testing.T) {
    37  	const level = "0"
    38  	log.SetLevel(level, log.LevelInfo)
    39  	require.Equal(t, log.LevelInfo, log.GetLevel(level))
    40  }
    41  
    42  func TestSetLogger(t *testing.T) {
    43  	logger := log.NewZapLog(log.Config{})
    44  	log.SetLogger(logger)
    45  	require.Equal(t, log.GetDefaultLogger(), logger)
    46  }
    47  
    48  func TestLogXXX(t *testing.T) {
    49  	log.Fatal("xxx")
    50  }
    51  
    52  func TestLoggerNil(t *testing.T) {
    53  	ctx := context.Background()
    54  	ctx, msg := codec.WithNewMessage(ctx)
    55  	msg.WithLogger((log.Logger)(nil))
    56  	log.EnableTrace()
    57  	log.TraceContext(ctx, "test")
    58  	log.TraceContextf(ctx, "test %s", "log")
    59  	log.DebugContext(ctx, "test")
    60  	log.DebugContextf(ctx, "test %s", "log")
    61  	log.InfoContext(ctx, "test")
    62  	log.InfoContextf(ctx, "test %s", "log")
    63  	log.ErrorContext(ctx, "test")
    64  	log.ErrorContextf(ctx, "test %s", "log")
    65  	log.WarnContext(ctx, "test")
    66  	log.WarnContextf(ctx, "test %s", "log")
    67  	log.FatalContext(ctx, "test")
    68  	log.FatalContextf(ctx, "test %s", "log")
    69  
    70  	l := msg.Logger()
    71  	require.Nil(t, l)
    72  }
    73  
    74  func TestLoggerZapLogWrapper(t *testing.T) {
    75  	ctx := context.Background()
    76  	ctx, msg := codec.WithNewMessage(ctx)
    77  	msg.WithLogger(log.NewZapLog(defaultConfig))
    78  
    79  	log.EnableTrace()
    80  	log.TraceContext(ctx, "test")
    81  	log.TraceContextf(ctx, "test")
    82  	log.DebugContext(ctx, "test")
    83  	log.DebugContextf(ctx, "test")
    84  	log.InfoContext(ctx, "test")
    85  	log.InfoContextf(ctx, "test %s", "s")
    86  	log.ErrorContext(ctx, "test")
    87  	log.ErrorContextf(ctx, "test")
    88  	log.WarnContext(ctx, "test")
    89  	log.WarnContextf(ctx, "test")
    90  
    91  	msg.WithLogger(log.NewZapLog(defaultConfig))
    92  	log.WithContextFields(ctx, "a", "a")
    93  	log.SetLevel("console", log.LevelDebug)
    94  	require.Equal(t, log.GetLevel("console"), log.LevelDebug)
    95  }
    96  
    97  func TestWithContextFields(t *testing.T) {
    98  	ctx := trpc.BackgroundContext()
    99  	log.WithContextFields(ctx, "k", "v")
   100  	require.NotNil(t, codec.Message(ctx).Logger())
   101  
   102  	ctx = context.Background()
   103  	newCtx := log.WithContextFields(ctx, "k", "v")
   104  	require.Nil(t, codec.Message(ctx).Logger())
   105  	require.NotNil(t, codec.Message(newCtx).Logger())
   106  }
   107  
   108  func TestOptionLogger1(t *testing.T) {
   109  	log.Debug("test1")
   110  	log.Debug("test2")
   111  	log.Debug("test3")
   112  	ctx := context.Background()
   113  	ctx, msg := codec.WithNewMessage(ctx)
   114  	msg.WithCallerServiceName("trpc.test.helloworld.Greeter")
   115  	log.WithContextFields(ctx, "a", "a")
   116  	log.TraceContext(ctx, "test")
   117  	log.InfoContext(ctx, "test")
   118  	log.WithContextFields(ctx, "b", "b")
   119  	log.InfoContext(ctx, "test")
   120  
   121  	trpc.Message(ctx).WithLogger(log.Get("default"))
   122  	log.DebugContext(ctx, "custom log msg")
   123  }
   124  
   125  func TestCustomLogger(t *testing.T) {
   126  	log.Register("custom", log.NewZapLogWithCallerSkip(log.Config{log.OutputConfig{Writer: "console"}}, 1))
   127  	log.Get("custom").Debug("test")
   128  }
   129  
   130  const (
   131  	noOptionBufLogger = "noOptionBuf"
   132  	customBufLogger   = "customBuf"
   133  )
   134  
   135  func getCtxFuncs() []func() context.Context {
   136  	return []func() context.Context{
   137  		func() context.Context {
   138  			return context.Background()
   139  		},
   140  		func() context.Context {
   141  			ctx, msg := codec.WithNewMessage(context.Background())
   142  			msg.WithCallerServiceName("trpc.test.helloworld.Greeter")
   143  			return ctx
   144  		}, func() context.Context {
   145  			ctx, msg := codec.WithNewMessage(context.Background())
   146  			msg.WithLogger(log.GetDefaultLogger())
   147  			msg.WithCallerServiceName("trpc.test.helloworld.Greeter")
   148  			return ctx
   149  		}, func() context.Context {
   150  			ctx, msg := codec.WithNewMessage(context.Background())
   151  			msg.WithLogger(log.Get(noOptionBufLogger))
   152  			msg.WithCallerServiceName("trpc.test.helloworld.Greeter")
   153  			return ctx
   154  		},
   155  	}
   156  }
   157  
   158  func TestWithContext(t *testing.T) {
   159  	old := log.GetDefaultLogger()
   160  	defer log.SetLogger(old)
   161  	for _, ctxFunc := range getCtxFuncs() {
   162  		ctx := ctxFunc()
   163  		checkTrace(t, func() {
   164  			log.WithContext(ctx, log.Field{Key: "123", Value: 123}).Debugf("test")
   165  			log.WithContext(ctx, log.Field{Key: "123", Value: 123}).With(log.Field{Key: "k2", Value: "v2"}).Debugf("test")
   166  			log.WithContext(ctx, log.Field{Key: "123", Value: 123}).With(log.Field{Key: "k2", Value: "v2"}).With(log.Field{Key: "k2", Value: "v2"}).Debugf("test")
   167  		}, nil)
   168  	}
   169  }
   170  
   171  func TestStacktrace(t *testing.T) {
   172  	checkTrace(t, func() {
   173  		log.Debug("test")
   174  		log.Error("test")
   175  	}, nil)
   176  }
   177  
   178  func check(t *testing.T, out *bytes.Buffer, fn func()) {
   179  	fn()
   180  
   181  	_, file, start, ok := runtime.Caller(2)
   182  	assert.True(t, ok)
   183  
   184  	pathPre := filepath.Join(filepath.Base(filepath.Dir(file)), filepath.Base(file)) + ":"
   185  	trace := out.String()
   186  	count := strings.Count(trace, pathPre)
   187  	fmt.Println(" line count:", count, "start:", start+1, "end:", start+count)
   188  	fmt.Println(trace)
   189  	for line := start + 1; line <= start+count; line++ {
   190  		path := pathPre + strconv.Itoa(line)
   191  		require.Contains(t, out.String(), path, "log trace error")
   192  	}
   193  
   194  	verifyNoZap(t, trace)
   195  }
   196  
   197  var (
   198  	buf = &bytes.Buffer{}
   199  )
   200  
   201  func init() {
   202  	log.Register(customBufLogger, log.NewZapBufLogger(buf, 1))
   203  	log.Register(noOptionBufLogger, newNoOptionBufLogger(buf, 1))
   204  }
   205  
   206  // checkTrace set buf log to check trace.
   207  func checkTrace(t *testing.T, fn func(), setLog func()) {
   208  	*buf = bytes.Buffer{}
   209  	log.SetLogger(log.NewZapBufLogger(buf, 2))
   210  	if setLog != nil {
   211  		setLog()
   212  	}
   213  	check(t, buf, fn)
   214  }
   215  
   216  func verifyNoZap(t *testing.T, logs string) {
   217  	for _, fnPrefix := range zapPackages {
   218  		require.NotContains(t, logs, fnPrefix, "should not contain zap package")
   219  	}
   220  }
   221  
   222  // zapPackages are packages that we search for in the logging output to match a
   223  // zap stack frame.
   224  var zapPackages = []string{
   225  	"go.uber.org/zap",
   226  	"go.uber.org/zap/zapcore",
   227  }
   228  
   229  func TestLogFatal(t *testing.T) {
   230  	old := log.GetDefaultLogger()
   231  	defer log.SetLogger(old)
   232  
   233  	var h customWriteHook
   234  	log.SetLogger(log.NewZapFatalLogger(&h))
   235  	log.Fatal("test")
   236  	assert.True(t, h.called)
   237  	h.called = false
   238  	log.Fatalf("test")
   239  	assert.True(t, h.called)
   240  	h.called = false
   241  	ctx := context.Background()
   242  	log.FatalContext(ctx, "test")
   243  	assert.True(t, h.called)
   244  	h.called = false
   245  	log.FatalContextf(ctx, "test")
   246  	assert.True(t, h.called)
   247  
   248  	ctx, msg := codec.WithNewMessage(context.Background())
   249  	msg.WithLogger(log.GetDefaultLogger())
   250  	msg.WithCallerServiceName("trpc.test.helloworld.Greeter")
   251  	h.called = false
   252  	log.FatalContext(ctx, "test")
   253  	assert.True(t, h.called)
   254  	h.called = false
   255  	log.FatalContextf(ctx, "test")
   256  	assert.True(t, h.called)
   257  }
   258  
   259  type customWriteHook struct {
   260  	called bool
   261  }
   262  
   263  func (h *customWriteHook) OnWrite(_ *zapcore.CheckedEntry, _ []zap.Field) {
   264  	h.called = true
   265  }