v2/log: check log level before using fmt.Sprint calls#19
v2/log: check log level before using fmt.Sprint calls#19Roasbeef merged 12 commits intobtcsuite:masterfrom
Conversation
|
cc @Roasbeef |
5da5eff to
e3d3184
Compare
bitromortac
left a comment
There was a problem hiding this comment.
Nice, thank you for the fix 🎉! LGTM ⚡
|
Should we add some benchmarks here as a tool to catch regressions like this in the future? Migth also be interesting to compare |
Seems the log closure pattern is an alternative? So we'd only construct the string later down the call stack if we know the log level matches. |
|
cool yeah great idea re benchmark and also having lazy compute values via closure. Currently implementing - will push up by EoD |
e3d3184 to
84cd56b
Compare
|
accidental push soz. will ping when ready for re-review |
965a07b to
913b97d
Compare
|
Cool cool cool, this has been updated quite a bit. Please see the new benchmark tests which can be used to evaluate the effectiveness of each commit here. Note that the main thing this aims to do is to let the new I've also added a new |
|
Some results: Importantly, we can see from these results that in the case where a log line is skipped due to the V1 logger (baseline)V2 Logger (current master branch)V2 Logger with this PR: |
guggero
left a comment
There was a problem hiding this comment.
Very nice performance tests and improvements 💯
v2/handler_test.go
Outdated
| level: LevelInfo, | ||
| logFunc: func(log Logger) { | ||
| ctx := context.Background() | ||
| log.InfoS(ctx, "msg", Hex("hex_val", []byte{0x01, 0x02})) |
There was a problem hiding this comment.
nit: Did you mean to call Hex6 here too?
There was a problem hiding this comment.
No I wanted to test both :) But I'll change this one to have more than 6 bytes 👍
There was a problem hiding this comment.
and I'll add a less-than-6-byte test for Hex6 👍
41945e1 to
ba4eabe
Compare
ellemouton
left a comment
There was a problem hiding this comment.
Thanks for the speedy review @guggero!! 🎉 addressed all comments
v2/handler_test.go
Outdated
| level: LevelInfo, | ||
| logFunc: func(log Logger) { | ||
| ctx := context.Background() | ||
| log.InfoS(ctx, "msg", Hex("hex_val", []byte{0x01, 0x02})) |
There was a problem hiding this comment.
No I wanted to test both :) But I'll change this one to have more than 6 bytes 👍
v2/handler_test.go
Outdated
| level: LevelInfo, | ||
| logFunc: func(log Logger) { | ||
| ctx := context.Background() | ||
| log.InfoS(ctx, "msg", Hex("hex_val", []byte{0x01, 0x02})) |
There was a problem hiding this comment.
and I'll add a less-than-6-byte test for Hex6 👍
There was a problem hiding this comment.
Nice improvements 🔥! I've also done some pathfinding benchmarks with lnd (500 random payments, no mission control data). The first benchmark is lnd with v2 logging before this PR, the second one is with v1 logging, and the last one is with this PR. So I think practially, there shouldn't be a noticable difference now 🎉.
|
Looking good to land, only blocker is this failing test: |
Move the test cases to the bottom of the file so that we can add more tests without the results (line number) of the call-site test changing.
Like the Hex helper, this helper prints a byte array in hex form but this one prints a maximum of 6 bytes.
Along with helpers to convert closures into slog Attributes.
This commit adds two benchmark tests: 1) BenchmarkLogger tests the new V2 logger under various scenarios. 2) BenchmarkV1vsV2Loggers tests the performance of the V2 logger against that of the V1 logger. As of this commit, the biggest issue is the time it takes for the new v2 logger to perform a log action that actually gets skipped due to the current log level. This is due to a bug that builds the log string using fmt.Sprintf _before_ the logger's Enabled check is run against the current log level. This will be improved upon in the upcoming commits. The BenchmarkLogger test will also help to assess the various improvements that will be make in the upcoming commits. We ideally want BenchmarkV2vsV2Loggers to show that the performance between the same methods on the two loggers does not change much. This will be improved upon in upcoming commits.
Instead of a fresh context per call to the old interface methods.
In this commit, we start checking the log level of the logger's handler before we do any more evaluation. This does not change behaviour since the level is checked by the slog library itself later on but by then we have performed some evaluation which impacts performance. In the benchmark tests, the biggest differences should be noticeable in the "skipped" tests.
The default styled options use `fmt.Sprintf` calls. This commit removes these defaults which improves the performance of the V2 logger for the cases when styled options are not provided.
To prioritise performance of the logger, we opt for code duplication instead of adding an extra code jump to the call-stack.
In this commit, instead of depending on the Handler for Level handling, we add a level object to the logger itself. This makes checking the log level before computing any expensive checks much faster. The handler still needs to carry its own level member so that it can properly implement the `Enabled` method of the Handler interface. This means that for the cases where a log line is skipped due to log level not being met, the performance will be faster. However, in the cases where the log line will be printed, execution will be slightly slower due to the fact that the level will in essence be checked twice.
So that a sub-system logger can be derived directly from a logger rather than needing to first create a new handler.
Which can be used to derive a new prefixed logger which will prefix a provided string to any message printed by the logger.
ba4eabe to
e0b4906
Compare
ellemouton
left a comment
There was a problem hiding this comment.
Thanks so much for the thorough testing @bitromortac! 🙏 addressed all comments
|
think this is g2g now @Roasbeef 🙏 |

The
Enabledcall is also called later on in the slog.Logger'slogcall but by then we have already built the string with fmt.Sprint which can result in quite a big performance hit.Thanks to @bitromortac for realising this!
EDIT: this has since been updated quite a bit. During review, you can use the new
BenchmarkLoggerandBenchmarkV1vsV2Loggersbenchmark tests to evaluate each commits impact.Note that this has also been expanded to add a
WithPrefixmethod on theLoggerso that we can get rid of the PrefixedLogger in LND