gologginggo-zap

What is the correspondence between go-logr and uber's zap verbosity levels?


I saw that there is log level in Uber Zap implementation:

    const (
            // DebugLevel logs are typically voluminous, and are usually disabled in
            // production.
            DebugLevel Level = iota - 1
            // InfoLevel is the default logging priority.
            InfoLevel
            // WarnLevel logs are more important than Info, but don't need individual
            // human review.
            WarnLevel
            // ErrorLevel logs are high-priority. If an application is running smoothly,
            // it shouldn't generate any error-level logs.
            ErrorLevel
            // DPanicLevel logs are particularly important errors. In development the
            // logger panics after writing the message.
            DPanicLevel
            // PanicLevel logs a message, then panics.
            PanicLevel
            // FatalLevel logs a message, then calls os.Exit(1).
            FatalLevel
        ) 

I use this when I set the level in a sigs.k8s.io/controller-runtime/pkg/log/zap logger, which uses go-logr under the hood:

func determineLogLevel(verbosityLevel string) zapcore.Level {
    var zapLevel zapcore.Level
    verbosityLevel = strings.ToLower(verbosityLevel)
    switch verbosityLevel {
    case ERROR:
        zapLevel = zapcore.ErrorLevel
    case WARNING:
        zapLevel = zapcore.WarnLevel
    case INFO:
        zapLevel = zapcore.InfoLevel
    case DEBUG:
        zapLevel = zapcore.DebugLevel
    default:
        zapLevel = zapcore.InfoLevel
    }
    return zapLevel
}

// here zap is "sigs.k8s.io/controller-runtime/pkg/log/zap"
opts := zap.Options{
    StacktraceLevel: ... ,
    Level:           determineLogLevel("ERROR"),
    Encoder:         ... ,
    ZapOpts:         ...,
}

But there is also the option of using logr.Logger.V.

Is the level value here the same as in Uber Zap's constants? ( DebugLevel, InfoLevel, WarnLevel, ....)

I also saw this:

flag --zap-log-level: Zap Level to configure the verbosity of logging. Can be one of ‘debug’, ‘info’, ‘error’, or any integer value > 0 which corresponds to custom debug levels of increasing verbosity”

Is this flag value the same as zapcore.Level in the sigs.k8s.io's zap.Options?

The documentation for logr.Logger.V

    // V returns an Logger value for a specific verbosity level, relative to
    // this Logger.  In other words, V values are additive.  V higher verbosity
    // level means a log message is less important.  It's illegal to pass a log
    // level less than zero.
    V(level int) Logger

Solution

  • The correspondence between go-logr and go.uber.org/zap log levels is given by:

    zapLevel = -1 * logrLevel
    

    In other words, the go-logr level is the inverse of zap level. This information is available in go-logr/zapr package docs:

    Levels in logr correspond to custom debug levels in Zap. Any given level in logr is represents by its inverse in zap (zapLevel = -1*logrLevel). For example V(2) is equivalent to log level -2 in Zap, while V(1) is equivalent to Zap's DebugLevel.

    You can also see a concrete example of how the level is initialized by looking at the implementation of logr.Logger.V by zapr package:

    func (zl *zapLogger) V(level int) logr.Logger {
        return &zapLogger{
            lvl: zl.lvl - zapcore.Level(level),
            l:   zl.l,
        }
    }
    

    The method zapr.NewLogger constructs a zapr.zapLogger with lvl field set to zap.InfoLevel (which you know is 0), so each time you call V on this implementation, it subtracts the given int value, thus obtaining its negative.


    The flag --zap-log-level is mapped from the string value passed on the command line (or k8s yaml config) to the Uber Zap's level as-is, based on this:

    var levelStrings = map[string]zapcore.Level{
        "debug": zap.DebugLevel,
        "info":  zap.InfoLevel,
        "error": zap.ErrorLevel,
    }
    

    The numerical value is then multiplied by -1 and then set to the logr.Logger implementation, as required by the documentation quoted above.