Skip to content

Commit

Permalink
Optimize Sugar logger for calls with a single string arg (uber-go#913)
Browse files Browse the repository at this point in the history
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%
```
  • Loading branch information
prashantv committed Feb 8, 2021
1 parent cb89e8f commit 009efbb
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 8 deletions.
27 changes: 19 additions & 8 deletions sugar.go
Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions sugar_test.go
Expand Up @@ -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")
}
})
}

0 comments on commit 009efbb

Please sign in to comment.