From 66bdb5be13b81467a46a87a3766a9c908eeea6dd Mon Sep 17 00:00:00 2001 From: Prashant Varanasi Date: Tue, 17 Dec 2019 17:52:48 -0800 Subject: [PATCH] logger: Check level before creating entry (#771) Calling `time.Now()` and creating an entry is unnecessary if the underlying core has the specified level disabled. To reduce the cost of logs at disabled levels, skip entry creation if the log level is disabled in the core. This special logic does not apply to DPanic or higher logs as they may need to panic/exit even if the entry does not cause any log to be emitted. On my machine, disabled debugging logs are 6x (~60ns to ~10ns) based on the example in the issue. benchcmp: ``` benchmark old ns/op new ns/op delta BenchmarkDisabledWithoutFields/Zap-12 8.42 1.59 -81.12% BenchmarkDisabledWithoutFields/Zap.Check-12 8.01 1.32 -83.52% BenchmarkDisabledWithoutFields/Zap.Sugar-12 12.4 11.4 -8.06% BenchmarkDisabledWithoutFields/Zap.SugarFormatting-12 117 102 -12.82% ``` Fixes #770. --- logger.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/logger.go b/logger.go index dc8f6e3a4..cd6e19551 100644 --- a/logger.go +++ b/logger.go @@ -258,6 +258,12 @@ func (log *Logger) check(lvl zapcore.Level, msg string) *zapcore.CheckedEntry { // (e.g., Check, Info, Fatal). const callerSkipOffset = 2 + // Check the level first to reduce the cost of disabled log calls. + // Since Panic and higher may exit, we skip the optimization for those levels. + if lvl < zapcore.DPanicLevel && !log.core.Enabled(lvl) { + return nil + } + // Create basic checked entry thru the core; this will be non-nil if the // log message will actually be written somewhere. ent := zapcore.Entry{