From 9382aa49f21e5f2492b9ac0501e20972ecf19efa Mon Sep 17 00:00:00 2001 From: Prashant Varanasi Date: Thu, 4 Feb 2021 19:13:58 -0800 Subject: [PATCH] Optimize Sugar logger for calls with a single string arg Currently, the Sugar logger uses fmt.Sprint in all cases when the template is empty. However, this call is unnecessary if there's a single string type argument, as we can use it directly. With this optimization, we reduce the cost and avoid an unnecessary alloc: ``` > benchcmp pre post benchmark old ns/op new ns/op delta BenchmarkSugarSingleStrArg-10 636 570 -10.38% benchmark old allocs new allocs delta BenchmarkSugarSingleStrArg-10 1 0 -100.00% ``` --- sugar.go | 27 +++++++++++++++++++-------- sugar_test.go | 8 ++++++++ 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/sugar.go b/sugar.go index 77ca227f4..4084dada7 100644 --- a/sugar.go +++ b/sugar.go @@ -222,19 +222,30 @@ func (s *SugaredLogger) log(lvl zapcore.Level, template string, fmtArgs []interf return } - // Format with Sprint, Sprintf, or neither. - msg := template - if msg == "" && len(fmtArgs) > 0 { - msg = fmt.Sprint(fmtArgs...) - } else if msg != "" && len(fmtArgs) > 0 { - msg = fmt.Sprintf(template, fmtArgs...) - } - + msg := getMessage(template, fmtArgs) if ce := s.base.Check(lvl, msg); ce != nil { ce.Write(s.sweetenFields(context)...) } } +// getMessage format with Sprint, Sprintf, or neither. +func getMessage(template string, fmtArgs []interface{}) string { + if len(fmtArgs) == 0 { + return template + } + + if template != "" { + return fmt.Sprintf(template, fmtArgs...) + } + + if len(fmtArgs) == 1 { + if str, ok := fmtArgs[0].(string); ok { + return str + } + } + return fmt.Sprint(fmtArgs...) +} + func (s *SugaredLogger) sweetenFields(args []interface{}) []Field { if len(args) == 0 { return nil diff --git a/sugar_test.go b/sugar_test.go index 5f4bb83b9..ac7b92064 100644 --- a/sugar_test.go +++ b/sugar_test.go @@ -368,3 +368,11 @@ func TestSugarAddCallerFail(t *testing.T) { "Expected original message to survive failures in runtime.Caller.") }) } + +func BenchmarkSugarSingleStrArg(b *testing.B) { + withSugar(b, InfoLevel, nil /* opts* */, func(log *SugaredLogger, logs *observer.ObservedLogs) { + for i := 0; i < b.N; i++ { + log.Info("hello world") + } + }) +}