-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Reduce allocations performed by the Logger returned from log.With. #28
Conversation
The old method performed O(n) allocs, the new method is O(1), where n is the number of nested With contexts.
I'm not immediately seeing where the |
keyvals []interface{} | ||
} | ||
|
||
func (l *withLogger) Log(kvs ...interface{}) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we keep parameter names consistent? i.e. here it should be keyvals ...interface{}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, sorry about that. Fixed.
@tsenart The problem isn't that Here is some benchmark code that I think represents a typical scenario (let me know if you think this is worth adding to this PR). func BenchmarkTypicalWith(b *testing.B) {
logger := log.NewDiscardLogger()
logger = log.With(logger, "lvl", "info")
logger = log.With(logger, "host", "hostname")
logger = log.With(logger, "svc", "svcname")
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
l := log.With(logger, "client", "client-id", "item", "item-id")
l.Log("step", 1)
l.Log("step", 2, "param", "arg")
l.Log("step", 3, "err", errors.New("error text"))
}
} I get the results shown below which I think are significant, especially in light of Peter's statement in the discussion of PR #16 that he, "... own[s] and operate[s] services that can become CPU bound based on log output ...." In my experience, logging impacts CPU primarily by heap allocations and formatting into the final
|
@ChrisHines: That makes sense now. Thanks for the detailed explanation. |
} | ||
|
||
func (l *withLogger) Log(keyvals ...interface{}) error { | ||
return l.logger.Log(append(l.keyvals, keyvals...)...) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this thread safe?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, l.keyvals
is capacity sliced when each withLogger
is created. See line 33 and 50. The code passes TestWithConcurrent
with race detector and multiple cores enabled.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
On Sunday, April 19, 2015, Chris Hines [email protected] wrote:
In log/log.go
#28 (comment):
- // Using the extra capacity without copying risks a data race that
- // would violate the Logger interface contract.
- n := len(keyvals)
- return &withLogger{
logger: logger,
keyvals: keyvals[:n:n],
- }
+}
+type withLogger struct {
- logger Logger
- keyvals []interface{}
+}
+func (l *withLogger) Log(keyvals ...interface{}) error {
- return l.logger.Log(append(l.keyvals, keyvals...)...)
Yes, l.keyvals is capacity sliced when each withLogger is created. See
line 33 and 50. The code passes TestWithConcurrent with race detector and
multiple cores enabled.—
Reply to this email directly or view it on GitHub
https://github.com/peterbourgon/gokit/pull/28/files#r28652359.
Sent from Gmail Mobile
Nice! Thanks! |
Reduce allocations performed by the Logger returned from log.With.
Reduce allocations performed by the Logger returned from log.With.
The old method performed O(n) allocs, the new method is O(1), where n is the number of nested With contexts.
(Note: this PR also adds NewDiscardLogger() to the API. It is used in the new benchmarks, but also has other uses, so I thought it should be exported.)