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

     1  package logx
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"fmt"
     7  	"io"
     8  	"log"
     9  	"os"
    10  	"reflect"
    11  	"runtime"
    12  	"strings"
    13  	"sync"
    14  	"sync/atomic"
    15  	"testing"
    16  	"time"
    17  
    18  	"github.com/stretchr/testify/assert"
    19  )
    20  
    21  var (
    22  	s           = []byte("Sending #11 notification (id: 1451875113812010473) in #1 connection")
    23  	pool        = make(chan []byte, 1)
    24  	_    Writer = (*mockWriter)(nil)
    25  )
    26  
    27  type mockWriter struct {
    28  	lock    sync.Mutex
    29  	builder strings.Builder
    30  }
    31  
    32  func (mw *mockWriter) Alert(v interface{}) {
    33  	mw.lock.Lock()
    34  	defer mw.lock.Unlock()
    35  	output(&mw.builder, levelAlert, v)
    36  }
    37  
    38  func (mw *mockWriter) Debug(v interface{}, fields ...LogField) {
    39  	mw.lock.Lock()
    40  	defer mw.lock.Unlock()
    41  	output(&mw.builder, levelDebug, v, fields...)
    42  }
    43  
    44  func (mw *mockWriter) Error(v interface{}, fields ...LogField) {
    45  	mw.lock.Lock()
    46  	defer mw.lock.Unlock()
    47  	output(&mw.builder, levelError, v, fields...)
    48  }
    49  
    50  func (mw *mockWriter) Info(v interface{}, fields ...LogField) {
    51  	mw.lock.Lock()
    52  	defer mw.lock.Unlock()
    53  	output(&mw.builder, levelInfo, v, fields...)
    54  }
    55  
    56  func (mw *mockWriter) Severe(v interface{}) {
    57  	mw.lock.Lock()
    58  	defer mw.lock.Unlock()
    59  	output(&mw.builder, levelSevere, v)
    60  }
    61  
    62  func (mw *mockWriter) Slow(v interface{}, fields ...LogField) {
    63  	mw.lock.Lock()
    64  	defer mw.lock.Unlock()
    65  	output(&mw.builder, levelSlow, v, fields...)
    66  }
    67  
    68  func (mw *mockWriter) Stack(v interface{}) {
    69  	mw.lock.Lock()
    70  	defer mw.lock.Unlock()
    71  	output(&mw.builder, levelError, v)
    72  }
    73  
    74  func (mw *mockWriter) Stat(v interface{}, fields ...LogField) {
    75  	mw.lock.Lock()
    76  	defer mw.lock.Unlock()
    77  	output(&mw.builder, levelStat, v, fields...)
    78  }
    79  
    80  func (mw *mockWriter) Close() error {
    81  	return nil
    82  }
    83  
    84  func (mw *mockWriter) Contains(text string) bool {
    85  	mw.lock.Lock()
    86  	defer mw.lock.Unlock()
    87  	return strings.Contains(mw.builder.String(), text)
    88  }
    89  
    90  func (mw *mockWriter) Reset() {
    91  	mw.lock.Lock()
    92  	defer mw.lock.Unlock()
    93  	mw.builder.Reset()
    94  }
    95  
    96  func (mw *mockWriter) String() string {
    97  	mw.lock.Lock()
    98  	defer mw.lock.Unlock()
    99  	return mw.builder.String()
   100  }
   101  
   102  func TestField(t *testing.T) {
   103  	tests := []struct {
   104  		name string
   105  		f    LogField
   106  		want map[string]interface{}
   107  	}{
   108  		{
   109  			name: "error",
   110  			f:    Field("foo", errors.New("bar")),
   111  			want: map[string]interface{}{
   112  				"foo": "bar",
   113  			},
   114  		},
   115  		{
   116  			name: "errors",
   117  			f:    Field("foo", []error{errors.New("bar"), errors.New("baz")}),
   118  			want: map[string]interface{}{
   119  				"foo": []interface{}{"bar", "baz"},
   120  			},
   121  		},
   122  		{
   123  			name: "strings",
   124  			f:    Field("foo", []string{"bar", "baz"}),
   125  			want: map[string]interface{}{
   126  				"foo": []interface{}{"bar", "baz"},
   127  			},
   128  		},
   129  		{
   130  			name: "duration",
   131  			f:    Field("foo", time.Second),
   132  			want: map[string]interface{}{
   133  				"foo": "1s",
   134  			},
   135  		},
   136  		{
   137  			name: "durations",
   138  			f:    Field("foo", []time.Duration{time.Second, 2 * time.Second}),
   139  			want: map[string]interface{}{
   140  				"foo": []interface{}{"1s", "2s"},
   141  			},
   142  		},
   143  		{
   144  			name: "times",
   145  			f: Field("foo", []time.Time{
   146  				time.Date(2020, time.January, 1, 0, 0, 0, 0, time.UTC),
   147  				time.Date(2020, time.January, 2, 0, 0, 0, 0, time.UTC),
   148  			}),
   149  			want: map[string]interface{}{
   150  				"foo": []interface{}{"2020-01-01 00:00:00 +0000 UTC", "2020-01-02 00:00:00 +0000 UTC"},
   151  			},
   152  		},
   153  		{
   154  			name: "stringer",
   155  			f:    Field("foo", ValStringer{val: "bar"}),
   156  			want: map[string]interface{}{
   157  				"foo": "bar",
   158  			},
   159  		},
   160  		{
   161  			name: "stringers",
   162  			f:    Field("foo", []fmt.Stringer{ValStringer{val: "bar"}, ValStringer{val: "baz"}}),
   163  			want: map[string]interface{}{
   164  				"foo": []interface{}{"bar", "baz"},
   165  			},
   166  		},
   167  	}
   168  
   169  	for _, test := range tests {
   170  		test := test
   171  		t.Run(test.name, func(t *testing.T) {
   172  			w := new(mockWriter)
   173  			old := writer.Swap(w)
   174  			defer writer.Store(old)
   175  
   176  			Infow("foo", test.f)
   177  			validateFields(t, w.String(), test.want)
   178  		})
   179  	}
   180  }
   181  
   182  func TestFileLineFileMode(t *testing.T) {
   183  	w := new(mockWriter)
   184  	old := writer.Swap(w)
   185  	defer writer.Store(old)
   186  
   187  	file, line := getFileLine()
   188  	Error("anything")
   189  	assert.True(t, w.Contains(fmt.Sprintf("%s:%d", file, line+1)))
   190  
   191  	file, line = getFileLine()
   192  	Errorf("anything %s", "format")
   193  	assert.True(t, w.Contains(fmt.Sprintf("%s:%d", file, line+1)))
   194  }
   195  
   196  func TestFileLineConsoleMode(t *testing.T) {
   197  	w := new(mockWriter)
   198  	old := writer.Swap(w)
   199  	defer writer.Store(old)
   200  
   201  	file, line := getFileLine()
   202  	Error("anything")
   203  	assert.True(t, w.Contains(fmt.Sprintf("%s:%d", file, line+1)))
   204  
   205  	w.Reset()
   206  	file, line = getFileLine()
   207  	Errorf("anything %s", "format")
   208  	assert.True(t, w.Contains(fmt.Sprintf("%s:%d", file, line+1)))
   209  }
   210  
   211  func TestStructedLogAlert(t *testing.T) {
   212  	w := new(mockWriter)
   213  	old := writer.Swap(w)
   214  	defer writer.Store(old)
   215  
   216  	doTestStructedLog(t, levelAlert, w, func(v ...interface{}) {
   217  		Alert(fmt.Sprint(v...))
   218  	})
   219  }
   220  
   221  func TestStructedLogDebug(t *testing.T) {
   222  	w := new(mockWriter)
   223  	old := writer.Swap(w)
   224  	defer writer.Store(old)
   225  
   226  	doTestStructedLog(t, levelDebug, w, func(v ...interface{}) {
   227  		Debug(v...)
   228  	})
   229  }
   230  
   231  func TestStructedLogDebugf(t *testing.T) {
   232  	w := new(mockWriter)
   233  	old := writer.Swap(w)
   234  	defer writer.Store(old)
   235  
   236  	doTestStructedLog(t, levelDebug, w, func(v ...interface{}) {
   237  		Debugf(fmt.Sprint(v...))
   238  	})
   239  }
   240  
   241  func TestStructedLogDebugv(t *testing.T) {
   242  	w := new(mockWriter)
   243  	old := writer.Swap(w)
   244  	defer writer.Store(old)
   245  
   246  	doTestStructedLog(t, levelDebug, w, func(v ...interface{}) {
   247  		Debugv(fmt.Sprint(v...))
   248  	})
   249  }
   250  
   251  func TestStructedLogDebugw(t *testing.T) {
   252  	w := new(mockWriter)
   253  	old := writer.Swap(w)
   254  	defer writer.Store(old)
   255  
   256  	doTestStructedLog(t, levelDebug, w, func(v ...interface{}) {
   257  		Debugw(fmt.Sprint(v...), Field("foo", time.Second))
   258  	})
   259  }
   260  
   261  func TestStructedLogError(t *testing.T) {
   262  	w := new(mockWriter)
   263  	old := writer.Swap(w)
   264  	defer writer.Store(old)
   265  
   266  	doTestStructedLog(t, levelError, w, func(v ...interface{}) {
   267  		Error(v...)
   268  	})
   269  }
   270  
   271  func TestStructedLogErrorf(t *testing.T) {
   272  	w := new(mockWriter)
   273  	old := writer.Swap(w)
   274  	defer writer.Store(old)
   275  
   276  	doTestStructedLog(t, levelError, w, func(v ...interface{}) {
   277  		Errorf("%s", fmt.Sprint(v...))
   278  	})
   279  }
   280  
   281  func TestStructedLogErrorv(t *testing.T) {
   282  	w := new(mockWriter)
   283  	old := writer.Swap(w)
   284  	defer writer.Store(old)
   285  
   286  	doTestStructedLog(t, levelError, w, func(v ...interface{}) {
   287  		Errorv(fmt.Sprint(v...))
   288  	})
   289  }
   290  
   291  func TestStructedLogErrorw(t *testing.T) {
   292  	w := new(mockWriter)
   293  	old := writer.Swap(w)
   294  	defer writer.Store(old)
   295  
   296  	doTestStructedLog(t, levelError, w, func(v ...interface{}) {
   297  		Errorw(fmt.Sprint(v...), Field("foo", "bar"))
   298  	})
   299  }
   300  
   301  func TestStructedLogInfo(t *testing.T) {
   302  	w := new(mockWriter)
   303  	old := writer.Swap(w)
   304  	defer writer.Store(old)
   305  
   306  	doTestStructedLog(t, levelInfo, w, func(v ...interface{}) {
   307  		Info(v...)
   308  	})
   309  }
   310  
   311  func TestStructedLogInfof(t *testing.T) {
   312  	w := new(mockWriter)
   313  	old := writer.Swap(w)
   314  	defer writer.Store(old)
   315  
   316  	doTestStructedLog(t, levelInfo, w, func(v ...interface{}) {
   317  		Infof("%s", fmt.Sprint(v...))
   318  	})
   319  }
   320  
   321  func TestStructedLogInfov(t *testing.T) {
   322  	w := new(mockWriter)
   323  	old := writer.Swap(w)
   324  	defer writer.Store(old)
   325  
   326  	doTestStructedLog(t, levelInfo, w, func(v ...interface{}) {
   327  		Infov(fmt.Sprint(v...))
   328  	})
   329  }
   330  
   331  func TestStructedLogInfow(t *testing.T) {
   332  	w := new(mockWriter)
   333  	old := writer.Swap(w)
   334  	defer writer.Store(old)
   335  
   336  	doTestStructedLog(t, levelInfo, w, func(v ...interface{}) {
   337  		Infow(fmt.Sprint(v...), Field("foo", "bar"))
   338  	})
   339  }
   340  
   341  func TestStructedLogInfoConsoleAny(t *testing.T) {
   342  	w := new(mockWriter)
   343  	old := writer.Swap(w)
   344  	defer writer.Store(old)
   345  
   346  	doTestStructedLogConsole(t, w, func(v ...interface{}) {
   347  		old := atomic.LoadUint32(&encoding)
   348  		atomic.StoreUint32(&encoding, plainEncodingType)
   349  		defer func() {
   350  			atomic.StoreUint32(&encoding, old)
   351  		}()
   352  
   353  		Infov(v)
   354  	})
   355  }
   356  
   357  func TestStructedLogInfoConsoleAnyString(t *testing.T) {
   358  	w := new(mockWriter)
   359  	old := writer.Swap(w)
   360  	defer writer.Store(old)
   361  
   362  	doTestStructedLogConsole(t, w, func(v ...interface{}) {
   363  		old := atomic.LoadUint32(&encoding)
   364  		atomic.StoreUint32(&encoding, plainEncodingType)
   365  		defer func() {
   366  			atomic.StoreUint32(&encoding, old)
   367  		}()
   368  
   369  		Infov(fmt.Sprint(v...))
   370  	})
   371  }
   372  
   373  func TestStructedLogInfoConsoleAnyError(t *testing.T) {
   374  	w := new(mockWriter)
   375  	old := writer.Swap(w)
   376  	defer writer.Store(old)
   377  
   378  	doTestStructedLogConsole(t, w, func(v ...interface{}) {
   379  		old := atomic.LoadUint32(&encoding)
   380  		atomic.StoreUint32(&encoding, plainEncodingType)
   381  		defer func() {
   382  			atomic.StoreUint32(&encoding, old)
   383  		}()
   384  
   385  		Infov(errors.New(fmt.Sprint(v...)))
   386  	})
   387  }
   388  
   389  func TestStructedLogInfoConsoleAnyStringer(t *testing.T) {
   390  	w := new(mockWriter)
   391  	old := writer.Swap(w)
   392  	defer writer.Store(old)
   393  
   394  	doTestStructedLogConsole(t, w, func(v ...interface{}) {
   395  		old := atomic.LoadUint32(&encoding)
   396  		atomic.StoreUint32(&encoding, plainEncodingType)
   397  		defer func() {
   398  			atomic.StoreUint32(&encoding, old)
   399  		}()
   400  
   401  		Infov(ValStringer{
   402  			val: fmt.Sprint(v...),
   403  		})
   404  	})
   405  }
   406  
   407  func TestStructedLogInfoConsoleText(t *testing.T) {
   408  	w := new(mockWriter)
   409  	old := writer.Swap(w)
   410  	defer writer.Store(old)
   411  
   412  	doTestStructedLogConsole(t, w, func(v ...interface{}) {
   413  		old := atomic.LoadUint32(&encoding)
   414  		atomic.StoreUint32(&encoding, plainEncodingType)
   415  		defer func() {
   416  			atomic.StoreUint32(&encoding, old)
   417  		}()
   418  
   419  		Info(fmt.Sprint(v...))
   420  	})
   421  }
   422  
   423  func TestStructedLogSlow(t *testing.T) {
   424  	w := new(mockWriter)
   425  	old := writer.Swap(w)
   426  	defer writer.Store(old)
   427  
   428  	doTestStructedLog(t, levelSlow, w, func(v ...interface{}) {
   429  		Slow(v...)
   430  	})
   431  }
   432  
   433  func TestStructedLogSlowf(t *testing.T) {
   434  	w := new(mockWriter)
   435  	old := writer.Swap(w)
   436  	defer writer.Store(old)
   437  
   438  	doTestStructedLog(t, levelSlow, w, func(v ...interface{}) {
   439  		Slowf(fmt.Sprint(v...))
   440  	})
   441  }
   442  
   443  func TestStructedLogSlowv(t *testing.T) {
   444  	w := new(mockWriter)
   445  	old := writer.Swap(w)
   446  	defer writer.Store(old)
   447  
   448  	doTestStructedLog(t, levelSlow, w, func(v ...interface{}) {
   449  		Slowv(fmt.Sprint(v...))
   450  	})
   451  }
   452  
   453  func TestStructedLogSloww(t *testing.T) {
   454  	w := new(mockWriter)
   455  	old := writer.Swap(w)
   456  	defer writer.Store(old)
   457  
   458  	doTestStructedLog(t, levelSlow, w, func(v ...interface{}) {
   459  		Sloww(fmt.Sprint(v...), Field("foo", time.Second))
   460  	})
   461  }
   462  
   463  func TestStructedLogStat(t *testing.T) {
   464  	w := new(mockWriter)
   465  	old := writer.Swap(w)
   466  	defer writer.Store(old)
   467  
   468  	doTestStructedLog(t, levelStat, w, func(v ...interface{}) {
   469  		Stat(v...)
   470  	})
   471  }
   472  
   473  func TestStructedLogStatf(t *testing.T) {
   474  	w := new(mockWriter)
   475  	old := writer.Swap(w)
   476  	defer writer.Store(old)
   477  
   478  	doTestStructedLog(t, levelStat, w, func(v ...interface{}) {
   479  		Statf(fmt.Sprint(v...))
   480  	})
   481  }
   482  
   483  func TestStructedLogSevere(t *testing.T) {
   484  	w := new(mockWriter)
   485  	old := writer.Swap(w)
   486  	defer writer.Store(old)
   487  
   488  	doTestStructedLog(t, levelSevere, w, func(v ...interface{}) {
   489  		Severe(v...)
   490  	})
   491  }
   492  
   493  func TestStructedLogSeveref(t *testing.T) {
   494  	w := new(mockWriter)
   495  	old := writer.Swap(w)
   496  	defer writer.Store(old)
   497  
   498  	doTestStructedLog(t, levelSevere, w, func(v ...interface{}) {
   499  		Severef(fmt.Sprint(v...))
   500  	})
   501  }
   502  
   503  func TestStructedLogWithDuration(t *testing.T) {
   504  	const message = "hello there"
   505  	w := new(mockWriter)
   506  	old := writer.Swap(w)
   507  	defer writer.Store(old)
   508  
   509  	WithDuration(time.Second).Info(message)
   510  	var entry map[string]interface{}
   511  	if err := json.Unmarshal([]byte(w.String()), &entry); err != nil {
   512  		t.Error(err)
   513  	}
   514  	assert.Equal(t, levelInfo, entry[levelKey])
   515  	assert.Equal(t, message, entry[contentKey])
   516  	assert.Equal(t, "1000.0ms", entry[durationKey])
   517  }
   518  
   519  func TestSetLevel(t *testing.T) {
   520  	SetLevel(ErrorLevel)
   521  	const message = "hello there"
   522  	w := new(mockWriter)
   523  	old := writer.Swap(w)
   524  	defer writer.Store(old)
   525  
   526  	Info(message)
   527  	assert.Equal(t, 0, w.builder.Len())
   528  }
   529  
   530  func TestSetLevelTwiceWithMode(t *testing.T) {
   531  	testModes := []string{
   532  		"mode",
   533  		"console",
   534  		"volumn",
   535  	}
   536  	w := new(mockWriter)
   537  	old := writer.Swap(w)
   538  	defer writer.Store(old)
   539  
   540  	for _, mode := range testModes {
   541  		testSetLevelTwiceWithMode(t, mode, w)
   542  	}
   543  }
   544  
   545  func TestSetLevelWithDuration(t *testing.T) {
   546  	SetLevel(ErrorLevel)
   547  	const message = "hello there"
   548  	w := new(mockWriter)
   549  	old := writer.Swap(w)
   550  	defer writer.Store(old)
   551  
   552  	WithDuration(time.Second).Info(message)
   553  	assert.Equal(t, 0, w.builder.Len())
   554  }
   555  
   556  func TestErrorfWithWrappedError(t *testing.T) {
   557  	SetLevel(ErrorLevel)
   558  	const message = "there"
   559  	w := new(mockWriter)
   560  	old := writer.Swap(w)
   561  	defer writer.Store(old)
   562  
   563  	Errorf("hello %w", errors.New(message))
   564  	assert.True(t, strings.Contains(w.String(), "hello there"))
   565  }
   566  
   567  func TestMustNil(t *testing.T) {
   568  	Must(nil)
   569  }
   570  
   571  func TestSetup(t *testing.T) {
   572  	defer func() {
   573  		SetLevel(InfoLevel)
   574  		atomic.StoreUint32(&encoding, jsonEncodingType)
   575  	}()
   576  
   577  	MustSetup(LogConf{
   578  		ServiceName: "any",
   579  		Mode:        "console",
   580  		TimeFormat:  timeFormat,
   581  	})
   582  	MustSetup(LogConf{
   583  		ServiceName: "any",
   584  		Mode:        "file",
   585  		Path:        os.TempDir(),
   586  	})
   587  	MustSetup(LogConf{
   588  		ServiceName: "any",
   589  		Mode:        "volume",
   590  		Path:        os.TempDir(),
   591  	})
   592  	MustSetup(LogConf{
   593  		ServiceName: "any",
   594  		Mode:        "console",
   595  		TimeFormat:  timeFormat,
   596  	})
   597  	MustSetup(LogConf{
   598  		ServiceName: "any",
   599  		Mode:        "console",
   600  		Encoding:    plainEncoding,
   601  	})
   602  
   603  	defer os.RemoveAll("CD01CB7D-2705-4F3F-889E-86219BF56F10")
   604  	assert.NotNil(t, setupWithVolume(LogConf{}))
   605  	assert.Nil(t, setupWithVolume(LogConf{
   606  		ServiceName: "CD01CB7D-2705-4F3F-889E-86219BF56F10",
   607  	}))
   608  	assert.Nil(t, setupWithVolume(LogConf{
   609  		ServiceName: "CD01CB7D-2705-4F3F-889E-86219BF56F10",
   610  		Rotation:    sizeRotationRule,
   611  	}))
   612  	assert.NotNil(t, setupWithFiles(LogConf{}))
   613  	assert.Nil(t, setupWithFiles(LogConf{
   614  		ServiceName: "any",
   615  		Path:        os.TempDir(),
   616  		Compress:    true,
   617  		KeepDays:    1,
   618  		MaxBackups:  3,
   619  		MaxSize:     1024 * 1024,
   620  	}))
   621  	setupLogLevel(LogConf{
   622  		Level: levelInfo,
   623  	})
   624  	setupLogLevel(LogConf{
   625  		Level: levelError,
   626  	})
   627  	setupLogLevel(LogConf{
   628  		Level: levelSevere,
   629  	})
   630  	_, err := createOutput("")
   631  	assert.NotNil(t, err)
   632  	Disable()
   633  	SetLevel(InfoLevel)
   634  	atomic.StoreUint32(&encoding, jsonEncodingType)
   635  }
   636  
   637  func TestDisable(t *testing.T) {
   638  	Disable()
   639  
   640  	var opt logOptions
   641  	WithKeepDays(1)(&opt)
   642  	WithGzip()(&opt)
   643  	WithMaxBackups(1)(&opt)
   644  	WithMaxSize(1024)(&opt)
   645  	assert.Nil(t, Close())
   646  	assert.Nil(t, Close())
   647  }
   648  
   649  func TestDisableStat(t *testing.T) {
   650  	DisableStat()
   651  
   652  	const message = "hello there"
   653  	w := new(mockWriter)
   654  	old := writer.Swap(w)
   655  	defer writer.Store(old)
   656  	Stat(message)
   657  	assert.Equal(t, 0, w.builder.Len())
   658  }
   659  
   660  func TestSetWriter(t *testing.T) {
   661  	atomic.StoreUint32(&disableLog, 0)
   662  	Reset()
   663  	SetWriter(nopWriter{})
   664  	assert.NotNil(t, writer.Load())
   665  	assert.True(t, writer.Load() == nopWriter{})
   666  	mocked := new(mockWriter)
   667  	SetWriter(mocked)
   668  	assert.Equal(t, mocked, writer.Load())
   669  }
   670  
   671  func TestWithGzip(t *testing.T) {
   672  	fn := WithGzip()
   673  	var opt logOptions
   674  	fn(&opt)
   675  	assert.True(t, opt.gzipEnabled)
   676  }
   677  
   678  func TestWithKeepDays(t *testing.T) {
   679  	fn := WithKeepDays(1)
   680  	var opt logOptions
   681  	fn(&opt)
   682  	assert.Equal(t, 1, opt.keepDays)
   683  }
   684  
   685  func BenchmarkCopyByteSliceAppend(b *testing.B) {
   686  	for i := 0; i < b.N; i++ {
   687  		var buf []byte
   688  		buf = append(buf, getTimestamp()...)
   689  		buf = append(buf, ' ')
   690  		buf = append(buf, s...)
   691  		_ = buf
   692  	}
   693  }
   694  
   695  func BenchmarkCopyByteSliceAllocExactly(b *testing.B) {
   696  	for i := 0; i < b.N; i++ {
   697  		now := []byte(getTimestamp())
   698  		buf := make([]byte, len(now)+1+len(s))
   699  		n := copy(buf, now)
   700  		buf[n] = ' '
   701  		copy(buf[n+1:], s)
   702  	}
   703  }
   704  
   705  func BenchmarkCopyByteSlice(b *testing.B) {
   706  	var buf []byte
   707  	for i := 0; i < b.N; i++ {
   708  		buf = make([]byte, len(s))
   709  		copy(buf, s)
   710  	}
   711  	fmt.Fprint(io.Discard, buf)
   712  }
   713  
   714  func BenchmarkCopyOnWriteByteSlice(b *testing.B) {
   715  	var buf []byte
   716  	for i := 0; i < b.N; i++ {
   717  		size := len(s)
   718  		buf = s[:size:size]
   719  	}
   720  	fmt.Fprint(io.Discard, buf)
   721  }
   722  
   723  func BenchmarkCacheByteSlice(b *testing.B) {
   724  	for i := 0; i < b.N; i++ {
   725  		dup := fetch()
   726  		copy(dup, s)
   727  		put(dup)
   728  	}
   729  }
   730  
   731  func BenchmarkLogs(b *testing.B) {
   732  	b.ReportAllocs()
   733  
   734  	log.SetOutput(io.Discard)
   735  	for i := 0; i < b.N; i++ {
   736  		Info(i)
   737  	}
   738  }
   739  
   740  func fetch() []byte {
   741  	select {
   742  	case b := <-pool:
   743  		return b
   744  	default:
   745  	}
   746  	return make([]byte, 4096)
   747  }
   748  
   749  func getFileLine() (string, int) {
   750  	_, file, line, _ := runtime.Caller(1)
   751  	short := file
   752  
   753  	for i := len(file) - 1; i > 0; i-- {
   754  		if file[i] == '/' {
   755  			short = file[i+1:]
   756  			break
   757  		}
   758  	}
   759  
   760  	return short, line
   761  }
   762  
   763  func put(b []byte) {
   764  	select {
   765  	case pool <- b:
   766  	default:
   767  	}
   768  }
   769  
   770  func doTestStructedLog(t *testing.T, level string, w *mockWriter, write func(...interface{})) {
   771  	const message = "hello there"
   772  	write(message)
   773  
   774  	var entry map[string]interface{}
   775  	if err := json.Unmarshal([]byte(w.String()), &entry); err != nil {
   776  		t.Error(err)
   777  	}
   778  
   779  	assert.Equal(t, level, entry[levelKey])
   780  	val, ok := entry[contentKey]
   781  	assert.True(t, ok)
   782  	assert.True(t, strings.Contains(val.(string), message))
   783  }
   784  
   785  func doTestStructedLogConsole(t *testing.T, w *mockWriter, write func(...interface{})) {
   786  	const message = "hello there"
   787  	write(message)
   788  	assert.True(t, strings.Contains(w.String(), message))
   789  }
   790  
   791  func testSetLevelTwiceWithMode(t *testing.T, mode string, w *mockWriter) {
   792  	writer.Store(nil)
   793  	SetUp(LogConf{
   794  		Mode:  mode,
   795  		Level: "error",
   796  		Path:  "/dev/null",
   797  	})
   798  	SetUp(LogConf{
   799  		Mode:  mode,
   800  		Level: "info",
   801  		Path:  "/dev/null",
   802  	})
   803  	const message = "hello there"
   804  	Info(message)
   805  	assert.Equal(t, 0, w.builder.Len())
   806  	Infof(message)
   807  	assert.Equal(t, 0, w.builder.Len())
   808  	ErrorStack(message)
   809  	assert.Equal(t, 0, w.builder.Len())
   810  	ErrorStackf(message)
   811  	assert.Equal(t, 0, w.builder.Len())
   812  }
   813  
   814  type ValStringer struct {
   815  	val string
   816  }
   817  
   818  func (v ValStringer) String() string {
   819  	return v.val
   820  }
   821  
   822  func validateFields(t *testing.T, content string, fields map[string]interface{}) {
   823  	var m map[string]interface{}
   824  	if err := json.Unmarshal([]byte(content), &m); err != nil {
   825  		t.Error(err)
   826  	}
   827  
   828  	for k, v := range fields {
   829  		if reflect.TypeOf(v).Kind() == reflect.Slice {
   830  			assert.EqualValues(t, v, m[k])
   831  		} else {
   832  			assert.Equal(t, v, m[k], content)
   833  		}
   834  	}
   835  }