Skip to content

Commit d38507c

Browse files
authored
SugaredLogger: Add *ln variants (#1080)
The existing `SugaredLogger.${Level}(..)` methods use `fmt.Print`-style formatting. Add `${Level}ln` variants for `Println`-stye formatting. Refs #889
1 parent 1d435ba commit d38507c

File tree

2 files changed

+141
-4
lines changed

2 files changed

+141
-4
lines changed

sugar.go

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,19 @@ const (
3838
// method.
3939
//
4040
// Unlike the Logger, the SugaredLogger doesn't insist on structured logging.
41-
// For each log level, it exposes three methods: one for loosely-typed
42-
// structured logging, one for println-style formatting, and one for
43-
// printf-style formatting. For example, SugaredLoggers can produce InfoLevel
44-
// output with Infow ("info with" structured context), Info, or Infof.
41+
// For each log level, it exposes four methods:
42+
//
43+
// - methods named after the log level for log.Print-style logging
44+
// - methods ending in "w" for loosely-typed structured logging
45+
// - methods ending in "f" for log.Printf-style logging
46+
// - methods ending in "ln" for log.Println-style logging
47+
//
48+
// For example, the methods for InfoLevel are:
49+
//
50+
// Info(...any) Print-style logging
51+
// Infow(...any) Structured logging (read as "info with")
52+
// Infof(string, ...any) Printf-style logging
53+
// Infoln(...any) Println-style logging
4554
type SugaredLogger struct {
4655
base *Logger
4756
}
@@ -220,11 +229,48 @@ func (s *SugaredLogger) Fatalw(msg string, keysAndValues ...interface{}) {
220229
s.log(FatalLevel, msg, nil, keysAndValues)
221230
}
222231

232+
// Debugln uses fmt.Sprintln to construct and log a message.
233+
func (s *SugaredLogger) Debugln(args ...interface{}) {
234+
s.logln(DebugLevel, "", args, nil)
235+
}
236+
237+
// Infoln uses fmt.Sprintln to construct and log a message.
238+
func (s *SugaredLogger) Infoln(args ...interface{}) {
239+
s.logln(InfoLevel, "", args, nil)
240+
}
241+
242+
// Warnln uses fmt.Sprintln to construct and log a message.
243+
func (s *SugaredLogger) Warnln(args ...interface{}) {
244+
s.logln(WarnLevel, "", args, nil)
245+
}
246+
247+
// Errorln uses fmt.Sprintln to construct and log a message.
248+
func (s *SugaredLogger) Errorln(args ...interface{}) {
249+
s.logln(ErrorLevel, "", args, nil)
250+
}
251+
252+
// DPanicln uses fmt.Sprintln to construct and log a message. In development, the
253+
// logger then panics. (See DPanicLevel for details.)
254+
func (s *SugaredLogger) DPanicln(args ...interface{}) {
255+
s.logln(DPanicLevel, "", args, nil)
256+
}
257+
258+
// Panicln uses fmt.Sprintln to construct and log a message, then panics.
259+
func (s *SugaredLogger) Panicln(args ...interface{}) {
260+
s.logln(PanicLevel, "", args, nil)
261+
}
262+
263+
// Fatalln uses fmt.Sprintln to construct and log a message, then calls os.Exit.
264+
func (s *SugaredLogger) Fatalln(args ...interface{}) {
265+
s.logln(FatalLevel, "", args, nil)
266+
}
267+
223268
// Sync flushes any buffered log entries.
224269
func (s *SugaredLogger) Sync() error {
225270
return s.base.Sync()
226271
}
227272

273+
// log message with Sprint, Sprintf, or neither.
228274
func (s *SugaredLogger) log(lvl zapcore.Level, template string, fmtArgs []interface{}, context []interface{}) {
229275
// If logging at this level is completely disabled, skip the overhead of
230276
// string formatting.
@@ -238,6 +284,18 @@ func (s *SugaredLogger) log(lvl zapcore.Level, template string, fmtArgs []interf
238284
}
239285
}
240286

287+
// logln message with Sprintln
288+
func (s *SugaredLogger) logln(lvl zapcore.Level, template string, fmtArgs []interface{}, context []interface{}) {
289+
if lvl < DPanicLevel && !s.base.Core().Enabled(lvl) {
290+
return
291+
}
292+
293+
msg := getMessageln(fmtArgs)
294+
if ce := s.base.Check(lvl, msg); ce != nil {
295+
ce.Write(s.sweetenFields(context)...)
296+
}
297+
}
298+
241299
// getMessage format with Sprint, Sprintf, or neither.
242300
func getMessage(template string, fmtArgs []interface{}) string {
243301
if len(fmtArgs) == 0 {
@@ -256,6 +314,12 @@ func getMessage(template string, fmtArgs []interface{}) string {
256314
return fmt.Sprint(fmtArgs...)
257315
}
258316

317+
// getMessageln format with Sprintln.
318+
func getMessageln(fmtArgs []interface{}) string {
319+
msg := fmt.Sprintln(fmtArgs...)
320+
return msg[:len(msg)-1]
321+
}
322+
259323
func (s *SugaredLogger) sweetenFields(args []interface{}) []Field {
260324
if len(args) == 0 {
261325
return nil

sugar_test.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,49 @@ func TestSugarTemplatedLogging(t *testing.T) {
261261
}
262262
}
263263

264+
func TestSugarLnLogging(t *testing.T) {
265+
tests := []struct {
266+
args []interface{}
267+
expect string
268+
}{
269+
{nil, ""},
270+
{[]interface{}{}, ""},
271+
{[]interface{}{""}, ""},
272+
{[]interface{}{"foo"}, "foo"},
273+
{[]interface{}{"foo", "bar"}, "foo bar"},
274+
}
275+
276+
// Common to all test cases.
277+
context := []interface{}{"foo", "bar"}
278+
expectedFields := []Field{String("foo", "bar")}
279+
280+
for _, tt := range tests {
281+
withSugar(t, DebugLevel, nil, func(logger *SugaredLogger, logs *observer.ObservedLogs) {
282+
logger.With(context...).Debugln(tt.args...)
283+
logger.With(context...).Infoln(tt.args...)
284+
logger.With(context...).Warnln(tt.args...)
285+
logger.With(context...).Errorln(tt.args...)
286+
logger.With(context...).DPanicln(tt.args...)
287+
288+
expected := make([]observer.LoggedEntry, 5)
289+
for i, lvl := range []zapcore.Level{DebugLevel, InfoLevel, WarnLevel, ErrorLevel, DPanicLevel} {
290+
expected[i] = observer.LoggedEntry{
291+
Entry: zapcore.Entry{Message: tt.expect, Level: lvl},
292+
Context: expectedFields,
293+
}
294+
}
295+
assert.Equal(t, expected, logs.AllUntimed(), "Unexpected log output.")
296+
})
297+
}
298+
}
299+
300+
func TestSugarLnLoggingIgnored(t *testing.T) {
301+
withSugar(t, WarnLevel, nil, func(logger *SugaredLogger, logs *observer.ObservedLogs) {
302+
logger.Infoln("hello")
303+
assert.Zero(t, logs.Len(), "Expected zero log statements.")
304+
})
305+
}
306+
264307
func TestSugarPanicLogging(t *testing.T) {
265308
tests := []struct {
266309
loggerLevel zapcore.Level
@@ -276,6 +319,9 @@ func TestSugarPanicLogging(t *testing.T) {
276319
{FatalLevel, func(s *SugaredLogger) { s.Panicw("foo") }, ""},
277320
{PanicLevel, func(s *SugaredLogger) { s.Panicw("foo") }, "foo"},
278321
{DebugLevel, func(s *SugaredLogger) { s.Panicw("foo") }, "foo"},
322+
{FatalLevel, func(s *SugaredLogger) { s.Panicln("foo") }, ""},
323+
{PanicLevel, func(s *SugaredLogger) { s.Panicln("foo") }, "foo"},
324+
{DebugLevel, func(s *SugaredLogger) { s.Panicln("foo") }, "foo"},
279325
}
280326

281327
for _, tt := range tests {
@@ -308,6 +354,9 @@ func TestSugarFatalLogging(t *testing.T) {
308354
{FatalLevel + 1, func(s *SugaredLogger) { s.Fatalw("foo") }, ""},
309355
{FatalLevel, func(s *SugaredLogger) { s.Fatalw("foo") }, "foo"},
310356
{DebugLevel, func(s *SugaredLogger) { s.Fatalw("foo") }, "foo"},
357+
{FatalLevel + 1, func(s *SugaredLogger) { s.Fatalln("foo") }, ""},
358+
{FatalLevel, func(s *SugaredLogger) { s.Fatalln("foo") }, "foo"},
359+
{DebugLevel, func(s *SugaredLogger) { s.Fatalln("foo") }, "foo"},
311360
}
312361

313362
for _, tt := range tests {
@@ -385,10 +434,34 @@ func TestSugarWithOptionsIncreaseLevel(t *testing.T) {
385434
})
386435
}
387436

437+
func TestSugarLnWithOptionsIncreaseLevel(t *testing.T) {
438+
withSugar(t, DebugLevel, nil, func(logger *SugaredLogger, logs *observer.ObservedLogs) {
439+
logger = logger.WithOptions(IncreaseLevel(WarnLevel))
440+
logger.Infoln("logger.Infoln")
441+
logger.Warnln("logger.Warnln")
442+
logger.Errorln("logger.Errorln")
443+
require.Equal(t, 2, logs.Len(), "expected only warn + error logs due to IncreaseLevel.")
444+
assert.Equal(
445+
t,
446+
logs.AllUntimed()[0].Message,
447+
"logger.Warnln",
448+
"Expected first logged message to be warn level message",
449+
)
450+
})
451+
}
452+
388453
func BenchmarkSugarSingleStrArg(b *testing.B) {
389454
withSugar(b, InfoLevel, nil /* opts* */, func(log *SugaredLogger, logs *observer.ObservedLogs) {
390455
for i := 0; i < b.N; i++ {
391456
log.Info("hello world")
392457
}
393458
})
394459
}
460+
461+
func BenchmarkLnSugarSingleStrArg(b *testing.B) {
462+
withSugar(b, InfoLevel, nil /* opts* */, func(log *SugaredLogger, logs *observer.ObservedLogs) {
463+
for i := 0; i < b.N; i++ {
464+
log.Infoln("hello world")
465+
}
466+
})
467+
}

0 commit comments

Comments
 (0)