...

Source file src/go.uber.org/zap/sugar_test.go

Documentation: go.uber.org/zap

     1  // Copyright (c) 2016 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package zap
    22  
    23  import (
    24  	"errors"
    25  	"fmt"
    26  	"strconv"
    27  	"testing"
    28  
    29  	"go.uber.org/zap/internal/exit"
    30  	"go.uber.org/zap/internal/ztest"
    31  	"go.uber.org/zap/zapcore"
    32  	"go.uber.org/zap/zaptest/observer"
    33  
    34  	"github.com/stretchr/testify/assert"
    35  	"github.com/stretchr/testify/require"
    36  )
    37  
    38  func TestSugarWith(t *testing.T) {
    39  	// Convenience functions to create expected error logs.
    40  	ignored := func(msg interface{}) observer.LoggedEntry {
    41  		return observer.LoggedEntry{
    42  			Entry:   zapcore.Entry{Level: ErrorLevel, Message: _oddNumberErrMsg},
    43  			Context: []Field{Any("ignored", msg)},
    44  		}
    45  	}
    46  	nonString := func(pairs ...invalidPair) observer.LoggedEntry {
    47  		return observer.LoggedEntry{
    48  			Entry:   zapcore.Entry{Level: ErrorLevel, Message: _nonStringKeyErrMsg},
    49  			Context: []Field{Array("invalid", invalidPairs(pairs))},
    50  		}
    51  	}
    52  	ignoredError := func(err error) observer.LoggedEntry {
    53  		return observer.LoggedEntry{
    54  			Entry:   zapcore.Entry{Level: ErrorLevel, Message: _multipleErrMsg},
    55  			Context: []Field{Error(err)},
    56  		}
    57  	}
    58  
    59  	type withAny func(*SugaredLogger, ...interface{}) *SugaredLogger
    60  	withMethods := []withAny{(*SugaredLogger).With, (*SugaredLogger).WithLazy}
    61  
    62  	tests := []struct {
    63  		desc     string
    64  		args     []interface{}
    65  		expected []Field
    66  		errLogs  []observer.LoggedEntry
    67  	}{
    68  		{
    69  			desc:     "nil args",
    70  			args:     nil,
    71  			expected: []Field{},
    72  			errLogs:  nil,
    73  		},
    74  		{
    75  			desc:     "empty slice of args",
    76  			args:     []interface{}{},
    77  			expected: []Field{},
    78  			errLogs:  nil,
    79  		},
    80  		{
    81  			desc:     "just a dangling key",
    82  			args:     []interface{}{"should ignore"},
    83  			expected: []Field{},
    84  			errLogs:  []observer.LoggedEntry{ignored("should ignore")},
    85  		},
    86  		{
    87  			desc:     "well-formed key-value pairs",
    88  			args:     []interface{}{"foo", 42, "true", "bar"},
    89  			expected: []Field{Int("foo", 42), String("true", "bar")},
    90  			errLogs:  nil,
    91  		},
    92  		{
    93  			desc:     "just a structured field",
    94  			args:     []interface{}{Int("foo", 42)},
    95  			expected: []Field{Int("foo", 42)},
    96  			errLogs:  nil,
    97  		},
    98  		{
    99  			desc:     "structured field and a dangling key",
   100  			args:     []interface{}{Int("foo", 42), "dangling"},
   101  			expected: []Field{Int("foo", 42)},
   102  			errLogs:  []observer.LoggedEntry{ignored("dangling")},
   103  		},
   104  		{
   105  			desc:     "structured field and a dangling non-string key",
   106  			args:     []interface{}{Int("foo", 42), 13},
   107  			expected: []Field{Int("foo", 42)},
   108  			errLogs:  []observer.LoggedEntry{ignored(13)},
   109  		},
   110  		{
   111  			desc:     "key-value pair and a dangling key",
   112  			args:     []interface{}{"foo", 42, "dangling"},
   113  			expected: []Field{Int("foo", 42)},
   114  			errLogs:  []observer.LoggedEntry{ignored("dangling")},
   115  		},
   116  		{
   117  			desc:     "pairs, a structured field, and a dangling key",
   118  			args:     []interface{}{"first", "field", Int("foo", 42), "baz", "quux", "dangling"},
   119  			expected: []Field{String("first", "field"), Int("foo", 42), String("baz", "quux")},
   120  			errLogs:  []observer.LoggedEntry{ignored("dangling")},
   121  		},
   122  		{
   123  			desc:     "one non-string key",
   124  			args:     []interface{}{"foo", 42, true, "bar"},
   125  			expected: []Field{Int("foo", 42)},
   126  			errLogs:  []observer.LoggedEntry{nonString(invalidPair{2, true, "bar"})},
   127  		},
   128  		{
   129  			desc:     "pairs, structured fields, non-string keys, and a dangling key",
   130  			args:     []interface{}{"foo", 42, true, "bar", Int("structure", 11), 42, "reversed", "baz", "quux", "dangling"},
   131  			expected: []Field{Int("foo", 42), Int("structure", 11), String("baz", "quux")},
   132  			errLogs: []observer.LoggedEntry{
   133  				ignored("dangling"),
   134  				nonString(invalidPair{2, true, "bar"}, invalidPair{5, 42, "reversed"}),
   135  			},
   136  		},
   137  		{
   138  			desc:     "multiple errors",
   139  			args:     []interface{}{errors.New("first"), errors.New("second"), errors.New("third")},
   140  			expected: []Field{Error(errors.New("first"))},
   141  			errLogs: []observer.LoggedEntry{
   142  				ignoredError(errors.New("second")),
   143  				ignoredError(errors.New("third")),
   144  			},
   145  		},
   146  	}
   147  
   148  	for _, tt := range tests {
   149  		for _, withMethod := range withMethods {
   150  			withSugar(t, DebugLevel, nil, func(logger *SugaredLogger, logs *observer.ObservedLogs) {
   151  				withMethod(logger, tt.args...).Info("")
   152  				output := logs.AllUntimed()
   153  				if len(tt.errLogs) > 0 {
   154  					for i := range tt.errLogs {
   155  						assert.Equal(t, tt.errLogs[i], output[i], "Unexpected error log at position %d for scenario %s.", i, tt.desc)
   156  					}
   157  				}
   158  				assert.Equal(t, len(tt.errLogs)+1, len(output), "Expected only one non-error message to be logged in scenario %s.", tt.desc)
   159  				assert.Equal(t, tt.expected, output[len(tt.errLogs)].Context, "Unexpected message context in scenario %s.", tt.desc)
   160  			})
   161  		}
   162  	}
   163  }
   164  
   165  func TestSugarWithCaptures(t *testing.T) {
   166  	type withAny func(*SugaredLogger, ...interface{}) *SugaredLogger
   167  
   168  	tests := []struct {
   169  		name        string
   170  		withMethods []withAny
   171  		wantJSON    []string
   172  	}{
   173  		{
   174  			name:        "with captures arguments at time of With",
   175  			withMethods: []withAny{(*SugaredLogger).With},
   176  			wantJSON: []string{
   177  				`{
   178  					"m": "hello 0",
   179  					"a0": [0],
   180  					"b0": [1]
   181  				}`,
   182  				`{
   183  					"m": "world 0",
   184  					"a0": [0],
   185  					"c0": [2]
   186  				}`,
   187  			},
   188  		},
   189  		{
   190  			name:        "lazy with captures arguments at time of Logging",
   191  			withMethods: []withAny{(*SugaredLogger).WithLazy},
   192  			wantJSON: []string{
   193  				`{
   194  					"m": "hello 0",
   195  					"a0": [1],
   196  					"b0": [1]
   197  				}`,
   198  				`{
   199  					"m": "world 0",
   200  					"a0": [1],
   201  					"c0": [2]
   202  				}`,
   203  			},
   204  		},
   205  	}
   206  
   207  	for _, tt := range tests {
   208  		t.Run(tt.name, func(t *testing.T) {
   209  			enc := zapcore.NewJSONEncoder(zapcore.EncoderConfig{
   210  				MessageKey: "m",
   211  			})
   212  
   213  			var bs ztest.Buffer
   214  			logger := New(zapcore.NewCore(enc, &bs, DebugLevel)).Sugar()
   215  
   216  			for i, withMethod := range tt.withMethods {
   217  				iStr := strconv.Itoa(i)
   218  				x := 10 * i
   219  				arr := zapcore.ArrayMarshalerFunc(func(enc zapcore.ArrayEncoder) error {
   220  					enc.AppendInt(x)
   221  					return nil
   222  				})
   223  
   224  				logger = withMethod(logger, Array("a"+iStr, arr))
   225  				x++
   226  				logger.Infow(fmt.Sprintf("hello %d", i), Array("b"+iStr, arr))
   227  				x++
   228  				logger = withMethod(logger, Array("c"+iStr, arr))
   229  				logger.Infow(fmt.Sprintf("world %d", i))
   230  			}
   231  
   232  			if lines := bs.Lines(); assert.Len(t, lines, len(tt.wantJSON)) {
   233  				for i, want := range tt.wantJSON {
   234  					assert.JSONEq(t, want, lines[i], "Unexpected output from the %d'th log.", i)
   235  				}
   236  			}
   237  		})
   238  	}
   239  }
   240  
   241  func TestSugaredLoggerLevel(t *testing.T) {
   242  	levels := []zapcore.Level{
   243  		DebugLevel,
   244  		InfoLevel,
   245  		WarnLevel,
   246  		ErrorLevel,
   247  		DPanicLevel,
   248  		PanicLevel,
   249  		FatalLevel,
   250  	}
   251  
   252  	for _, lvl := range levels {
   253  		lvl := lvl
   254  		t.Run(lvl.String(), func(t *testing.T) {
   255  			t.Parallel()
   256  
   257  			core, _ := observer.New(lvl)
   258  			log := New(core).Sugar()
   259  			assert.Equal(t, lvl, log.Level())
   260  		})
   261  	}
   262  
   263  	t.Run("Nop", func(t *testing.T) {
   264  		t.Parallel()
   265  
   266  		assert.Equal(t, zapcore.InvalidLevel, NewNop().Sugar().Level())
   267  	})
   268  }
   269  
   270  func TestSugarFieldsInvalidPairs(t *testing.T) {
   271  	withSugar(t, DebugLevel, nil, func(logger *SugaredLogger, logs *observer.ObservedLogs) {
   272  		logger.With(42, "foo", []string{"bar"}, "baz").Info("")
   273  		output := logs.AllUntimed()
   274  
   275  		// Double-check that the actual message was logged.
   276  		require.Equal(t, 2, len(output), "Unexpected number of entries logged.")
   277  		require.Equal(t, observer.LoggedEntry{Context: []Field{}}, output[1], "Unexpected non-error log entry.")
   278  
   279  		// Assert that the error message's structured fields serialize properly.
   280  		require.Equal(t, 1, len(output[0].Context), "Expected one field in error entry context.")
   281  		enc := zapcore.NewMapObjectEncoder()
   282  		output[0].Context[0].AddTo(enc)
   283  		assert.Equal(t, []interface{}{
   284  			map[string]interface{}{"position": int64(0), "key": int64(42), "value": "foo"},
   285  			map[string]interface{}{"position": int64(2), "key": []interface{}{"bar"}, "value": "baz"},
   286  		}, enc.Fields["invalid"], "Unexpected output when logging invalid key-value pairs.")
   287  	})
   288  }
   289  
   290  func TestSugarStructuredLogging(t *testing.T) {
   291  	tests := []struct {
   292  		msg       string
   293  		expectMsg string
   294  	}{
   295  		{"foo", "foo"},
   296  		{"", ""},
   297  	}
   298  
   299  	// Common to all test cases.
   300  	var (
   301  		err            = errors.New("qux")
   302  		context        = []interface{}{"foo", "bar"}
   303  		extra          = []interface{}{err, "baz", false}
   304  		expectedFields = []Field{String("foo", "bar"), Error(err), Bool("baz", false)}
   305  	)
   306  
   307  	for _, tt := range tests {
   308  		withSugar(t, DebugLevel, nil, func(logger *SugaredLogger, logs *observer.ObservedLogs) {
   309  			logger.With(context...).Debugw(tt.msg, extra...)
   310  			logger.With(context...).Infow(tt.msg, extra...)
   311  			logger.With(context...).Warnw(tt.msg, extra...)
   312  			logger.With(context...).Errorw(tt.msg, extra...)
   313  			logger.With(context...).DPanicw(tt.msg, extra...)
   314  			logger.With(context...).Logw(WarnLevel, tt.msg, extra...)
   315  
   316  			expected := make([]observer.LoggedEntry, 6)
   317  			for i, lvl := range []zapcore.Level{DebugLevel, InfoLevel, WarnLevel, ErrorLevel, DPanicLevel, WarnLevel} {
   318  				expected[i] = observer.LoggedEntry{
   319  					Entry:   zapcore.Entry{Message: tt.expectMsg, Level: lvl},
   320  					Context: expectedFields,
   321  				}
   322  			}
   323  			assert.Equal(t, expected, logs.AllUntimed(), "Unexpected log output.")
   324  		})
   325  	}
   326  }
   327  
   328  func TestSugarConcatenatingLogging(t *testing.T) {
   329  	tests := []struct {
   330  		args   []interface{}
   331  		expect string
   332  	}{
   333  		{[]interface{}{nil}, "<nil>"},
   334  	}
   335  
   336  	// Common to all test cases.
   337  	context := []interface{}{"foo", "bar"}
   338  	expectedFields := []Field{String("foo", "bar")}
   339  
   340  	for _, tt := range tests {
   341  		withSugar(t, DebugLevel, nil, func(logger *SugaredLogger, logs *observer.ObservedLogs) {
   342  			logger.With(context...).Debug(tt.args...)
   343  			logger.With(context...).Info(tt.args...)
   344  			logger.With(context...).Warn(tt.args...)
   345  			logger.With(context...).Error(tt.args...)
   346  			logger.With(context...).DPanic(tt.args...)
   347  			logger.With(context...).Log(InfoLevel, tt.args...)
   348  
   349  			expected := make([]observer.LoggedEntry, 6)
   350  			for i, lvl := range []zapcore.Level{DebugLevel, InfoLevel, WarnLevel, ErrorLevel, DPanicLevel, InfoLevel} {
   351  				expected[i] = observer.LoggedEntry{
   352  					Entry:   zapcore.Entry{Message: tt.expect, Level: lvl},
   353  					Context: expectedFields,
   354  				}
   355  			}
   356  			assert.Equal(t, expected, logs.AllUntimed(), "Unexpected log output.")
   357  		})
   358  	}
   359  }
   360  
   361  func TestSugarTemplatedLogging(t *testing.T) {
   362  	tests := []struct {
   363  		format string
   364  		args   []interface{}
   365  		expect string
   366  	}{
   367  		{"", nil, ""},
   368  		{"foo", nil, "foo"},
   369  		// If the user fails to pass a template, degrade to fmt.Sprint.
   370  		{"", []interface{}{"foo"}, "foo"},
   371  	}
   372  
   373  	// Common to all test cases.
   374  	context := []interface{}{"foo", "bar"}
   375  	expectedFields := []Field{String("foo", "bar")}
   376  
   377  	for _, tt := range tests {
   378  		withSugar(t, DebugLevel, nil, func(logger *SugaredLogger, logs *observer.ObservedLogs) {
   379  			logger.With(context...).Debugf(tt.format, tt.args...)
   380  			logger.With(context...).Infof(tt.format, tt.args...)
   381  			logger.With(context...).Warnf(tt.format, tt.args...)
   382  			logger.With(context...).Errorf(tt.format, tt.args...)
   383  			logger.With(context...).DPanicf(tt.format, tt.args...)
   384  			logger.With(context...).Logf(ErrorLevel, tt.format, tt.args...)
   385  
   386  			expected := make([]observer.LoggedEntry, 6)
   387  			for i, lvl := range []zapcore.Level{DebugLevel, InfoLevel, WarnLevel, ErrorLevel, DPanicLevel, ErrorLevel} {
   388  				expected[i] = observer.LoggedEntry{
   389  					Entry:   zapcore.Entry{Message: tt.expect, Level: lvl},
   390  					Context: expectedFields,
   391  				}
   392  			}
   393  			assert.Equal(t, expected, logs.AllUntimed(), "Unexpected log output.")
   394  		})
   395  	}
   396  }
   397  
   398  func TestSugarLnLogging(t *testing.T) {
   399  	tests := []struct {
   400  		args   []interface{}
   401  		expect string
   402  	}{
   403  		{nil, ""},
   404  		{[]interface{}{}, ""},
   405  		{[]interface{}{""}, ""},
   406  		{[]interface{}{"foo"}, "foo"},
   407  		{[]interface{}{"foo", "bar"}, "foo bar"},
   408  	}
   409  
   410  	// Common to all test cases.
   411  	context := []interface{}{"foo", "bar"}
   412  	expectedFields := []Field{String("foo", "bar")}
   413  
   414  	for _, tt := range tests {
   415  		withSugar(t, DebugLevel, nil, func(logger *SugaredLogger, logs *observer.ObservedLogs) {
   416  			logger.With(context...).Debugln(tt.args...)
   417  			logger.With(context...).Infoln(tt.args...)
   418  			logger.With(context...).Warnln(tt.args...)
   419  			logger.With(context...).Errorln(tt.args...)
   420  			logger.With(context...).DPanicln(tt.args...)
   421  			logger.With(context...).Logln(InfoLevel, tt.args...)
   422  
   423  			expected := make([]observer.LoggedEntry, 6)
   424  			for i, lvl := range []zapcore.Level{DebugLevel, InfoLevel, WarnLevel, ErrorLevel, DPanicLevel, InfoLevel} {
   425  				expected[i] = observer.LoggedEntry{
   426  					Entry:   zapcore.Entry{Message: tt.expect, Level: lvl},
   427  					Context: expectedFields,
   428  				}
   429  			}
   430  			assert.Equal(t, expected, logs.AllUntimed(), "Unexpected log output.")
   431  		})
   432  	}
   433  }
   434  
   435  func TestSugarLnLoggingIgnored(t *testing.T) {
   436  	withSugar(t, WarnLevel, nil, func(logger *SugaredLogger, logs *observer.ObservedLogs) {
   437  		logger.Infoln("hello")
   438  		assert.Zero(t, logs.Len(), "Expected zero log statements.")
   439  	})
   440  }
   441  
   442  func TestSugarPanicLogging(t *testing.T) {
   443  	tests := []struct {
   444  		loggerLevel zapcore.Level
   445  		f           func(*SugaredLogger)
   446  		expectedMsg string
   447  	}{
   448  		{FatalLevel, func(s *SugaredLogger) { s.Panic("foo") }, ""},
   449  		{PanicLevel, func(s *SugaredLogger) { s.Panic("foo") }, "foo"},
   450  		{DebugLevel, func(s *SugaredLogger) { s.Panic("foo") }, "foo"},
   451  		{FatalLevel, func(s *SugaredLogger) { s.Panicf("%s", "foo") }, ""},
   452  		{PanicLevel, func(s *SugaredLogger) { s.Panicf("%s", "foo") }, "foo"},
   453  		{DebugLevel, func(s *SugaredLogger) { s.Panicf("%s", "foo") }, "foo"},
   454  		{FatalLevel, func(s *SugaredLogger) { s.Panicw("foo") }, ""},
   455  		{PanicLevel, func(s *SugaredLogger) { s.Panicw("foo") }, "foo"},
   456  		{DebugLevel, func(s *SugaredLogger) { s.Panicw("foo") }, "foo"},
   457  		{FatalLevel, func(s *SugaredLogger) { s.Panicln("foo") }, ""},
   458  		{PanicLevel, func(s *SugaredLogger) { s.Panicln("foo") }, "foo"},
   459  		{DebugLevel, func(s *SugaredLogger) { s.Panicln("foo") }, "foo"},
   460  	}
   461  
   462  	for _, tt := range tests {
   463  		withSugar(t, tt.loggerLevel, nil, func(sugar *SugaredLogger, logs *observer.ObservedLogs) {
   464  			assert.Panics(t, func() { tt.f(sugar) }, "Expected panic-level logger calls to panic.")
   465  			if tt.expectedMsg != "" {
   466  				assert.Equal(t, []observer.LoggedEntry{{
   467  					Context: []Field{},
   468  					Entry:   zapcore.Entry{Message: tt.expectedMsg, Level: PanicLevel},
   469  				}}, logs.AllUntimed(), "Unexpected log output.")
   470  			} else {
   471  				assert.Equal(t, 0, logs.Len(), "Didn't expect any log output.")
   472  			}
   473  		})
   474  	}
   475  }
   476  
   477  func TestSugarFatalLogging(t *testing.T) {
   478  	tests := []struct {
   479  		loggerLevel zapcore.Level
   480  		f           func(*SugaredLogger)
   481  		expectedMsg string
   482  	}{
   483  		{FatalLevel + 1, func(s *SugaredLogger) { s.Fatal("foo") }, ""},
   484  		{FatalLevel, func(s *SugaredLogger) { s.Fatal("foo") }, "foo"},
   485  		{DebugLevel, func(s *SugaredLogger) { s.Fatal("foo") }, "foo"},
   486  		{FatalLevel + 1, func(s *SugaredLogger) { s.Fatalf("%s", "foo") }, ""},
   487  		{FatalLevel, func(s *SugaredLogger) { s.Fatalf("%s", "foo") }, "foo"},
   488  		{DebugLevel, func(s *SugaredLogger) { s.Fatalf("%s", "foo") }, "foo"},
   489  		{FatalLevel + 1, func(s *SugaredLogger) { s.Fatalw("foo") }, ""},
   490  		{FatalLevel, func(s *SugaredLogger) { s.Fatalw("foo") }, "foo"},
   491  		{DebugLevel, func(s *SugaredLogger) { s.Fatalw("foo") }, "foo"},
   492  		{FatalLevel + 1, func(s *SugaredLogger) { s.Fatalln("foo") }, ""},
   493  		{FatalLevel, func(s *SugaredLogger) { s.Fatalln("foo") }, "foo"},
   494  		{DebugLevel, func(s *SugaredLogger) { s.Fatalln("foo") }, "foo"},
   495  	}
   496  
   497  	for _, tt := range tests {
   498  		withSugar(t, tt.loggerLevel, nil, func(sugar *SugaredLogger, logs *observer.ObservedLogs) {
   499  			stub := exit.WithStub(func() { tt.f(sugar) })
   500  			assert.True(t, stub.Exited, "Expected all calls to fatal logger methods to exit process.")
   501  			if tt.expectedMsg != "" {
   502  				assert.Equal(t, []observer.LoggedEntry{{
   503  					Context: []Field{},
   504  					Entry:   zapcore.Entry{Message: tt.expectedMsg, Level: FatalLevel},
   505  				}}, logs.AllUntimed(), "Unexpected log output.")
   506  			} else {
   507  				assert.Equal(t, 0, logs.Len(), "Didn't expect any log output.")
   508  			}
   509  		})
   510  	}
   511  }
   512  
   513  func TestSugarAddCaller(t *testing.T) {
   514  	tests := []struct {
   515  		options []Option
   516  		pat     string
   517  	}{
   518  		{opts(AddCaller()), `.+/sugar_test.go:[\d]+$`},
   519  		{opts(AddCaller(), AddCallerSkip(1), AddCallerSkip(-1)), `.+/sugar_test.go:[\d]+$`},
   520  		{opts(AddCaller(), AddCallerSkip(1)), `.+/common_test.go:[\d]+$`},
   521  		{opts(AddCaller(), AddCallerSkip(1), AddCallerSkip(5)), `.+/src/runtime/.*:[\d]+$`},
   522  	}
   523  	for _, tt := range tests {
   524  		withSugar(t, DebugLevel, tt.options, func(logger *SugaredLogger, logs *observer.ObservedLogs) {
   525  			logger.Info("")
   526  			output := logs.AllUntimed()
   527  			assert.Equal(t, 1, len(output), "Unexpected number of logs written out.")
   528  			assert.Regexp(
   529  				t,
   530  				tt.pat,
   531  				output[0].Caller,
   532  				"Expected to find package name and file name in output.",
   533  			)
   534  		})
   535  	}
   536  }
   537  
   538  func TestSugarAddCallerFail(t *testing.T) {
   539  	errBuf := &ztest.Buffer{}
   540  	withSugar(t, DebugLevel, opts(AddCaller(), AddCallerSkip(1e3), ErrorOutput(errBuf)), func(log *SugaredLogger, logs *observer.ObservedLogs) {
   541  		log.Info("Failure.")
   542  		assert.Regexp(
   543  			t,
   544  			`Logger.check error: failed to get caller`,
   545  			errBuf.String(),
   546  			"Didn't find expected failure message.",
   547  		)
   548  		assert.Equal(
   549  			t,
   550  			logs.AllUntimed()[0].Message,
   551  			"Failure.",
   552  			"Expected original message to survive failures in runtime.Caller.")
   553  	})
   554  }
   555  
   556  func TestSugarWithOptionsIncreaseLevel(t *testing.T) {
   557  	withSugar(t, DebugLevel, nil, func(logger *SugaredLogger, logs *observer.ObservedLogs) {
   558  		logger = logger.WithOptions(IncreaseLevel(WarnLevel))
   559  		logger.Info("logger.Info")
   560  		logger.Warn("logger.Warn")
   561  		logger.Error("logger.Error")
   562  		require.Equal(t, 2, logs.Len(), "expected only warn + error logs due to IncreaseLevel.")
   563  		assert.Equal(
   564  			t,
   565  			logs.AllUntimed()[0].Message,
   566  			"logger.Warn",
   567  			"Expected first logged message to be warn level message",
   568  		)
   569  	})
   570  }
   571  
   572  func TestSugarLnWithOptionsIncreaseLevel(t *testing.T) {
   573  	withSugar(t, DebugLevel, nil, func(logger *SugaredLogger, logs *observer.ObservedLogs) {
   574  		logger = logger.WithOptions(IncreaseLevel(WarnLevel))
   575  		logger.Infoln("logger.Infoln")
   576  		logger.Warnln("logger.Warnln")
   577  		logger.Errorln("logger.Errorln")
   578  		require.Equal(t, 2, logs.Len(), "expected only warn + error logs due to IncreaseLevel.")
   579  		assert.Equal(
   580  			t,
   581  			logs.AllUntimed()[0].Message,
   582  			"logger.Warnln",
   583  			"Expected first logged message to be warn level message",
   584  		)
   585  	})
   586  }
   587  
   588  func BenchmarkSugarSingleStrArg(b *testing.B) {
   589  	withSugar(b, InfoLevel, nil /* opts* */, func(log *SugaredLogger, logs *observer.ObservedLogs) {
   590  		for i := 0; i < b.N; i++ {
   591  			log.Info("hello world")
   592  		}
   593  	})
   594  }
   595  
   596  func BenchmarkLnSugarSingleStrArg(b *testing.B) {
   597  	withSugar(b, InfoLevel, nil /* opts* */, func(log *SugaredLogger, logs *observer.ObservedLogs) {
   598  		for i := 0; i < b.N; i++ {
   599  			log.Infoln("hello world")
   600  		}
   601  	})
   602  }
   603  

View as plain text