美文网首页
聊聊klog的klogger

聊聊klog的klogger

作者: go4it | 来源:发表于2020-12-30 23:38 被阅读0次

    本文主要研究一下klog的klogger

    logr

    go-logr/logr@v0.2.0/logr.go

    // Logger represents the ability to log messages, both errors and not.
    type Logger interface {
        // Enabled tests whether this Logger is enabled.  For example, commandline
        // flags might be used to set the logging verbosity and disable some info
        // logs.
        Enabled() bool
    
        // Info logs a non-error message with the given key/value pairs as context.
        //
        // The msg argument should be used to add some constant description to
        // the log line.  The key/value pairs can then be used to add additional
        // variable information.  The key/value pairs should alternate string
        // keys and arbitrary values.
        Info(msg string, keysAndValues ...interface{})
    
        // Error logs an error, with the given message and key/value pairs as context.
        // It functions similarly to calling Info with the "error" named value, but may
        // have unique behavior, and should be preferred for logging errors (see the
        // package documentations for more information).
        //
        // The msg field should be used to add context to any underlying error,
        // while the err field should be used to attach the actual error that
        // triggered this log line, if present.
        Error(err error, msg string, keysAndValues ...interface{})
    
        // 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
    
        // WithValues adds some key-value pairs of context to a logger.
        // See Info for documentation on how key/value pairs work.
        WithValues(keysAndValues ...interface{}) Logger
    
        // WithName adds a new element to the logger's name.
        // Successive calls with WithName continue to append
        // suffixes to the logger's name.  It's strongly reccomended
        // that name segments contain only letters, digits, and hyphens
        // (see the package documentation for more information).
        WithName(name string) Logger
    }
    

    logr类似java的slf4j,其Logger接口定义了Enabled、Info、Error、V、WithValues、WithName方法

    klogr

    k8s.io/klog/v2@v2.4.0/klogr/klogr.go

    type klogger struct {
        level  int
        prefix string
        values []interface{}
    }
    
    // New returns a logr.Logger which is implemented by klog.
    func New() logr.Logger {
        return klogger{
            level:  0,
            prefix: "",
            values: nil,
        }
    }
    
    func (l klogger) Enabled() bool {
        return bool(klog.V(klog.Level(l.level)).Enabled())
    }
    
    func (l klogger) Info(msg string, kvList ...interface{}) {
        if l.Enabled() {
            msgStr := flatten("msg", msg)
            trimmed := trimDuplicates(l.values, kvList)
            fixedStr := flatten(trimmed[0]...)
            userStr := flatten(trimmed[1]...)
            klog.InfoDepth(framesToCaller(), l.prefix, " ", msgStr, " ", fixedStr, " ", userStr)
        }
    }
    
    func (l klogger) Error(err error, msg string, kvList ...interface{}) {
        msgStr := flatten("msg", msg)
        var loggableErr interface{}
        if err != nil {
            loggableErr = err.Error()
        }
        errStr := flatten("error", loggableErr)
        trimmed := trimDuplicates(l.values, kvList)
        fixedStr := flatten(trimmed[0]...)
        userStr := flatten(trimmed[1]...)
        klog.ErrorDepth(framesToCaller(), l.prefix, " ", msgStr, " ", errStr, " ", fixedStr, " ", userStr)
    }
    
    func (l klogger) V(level int) logr.Logger {
        new := l.clone()
        new.level = level
        return new
    }
    
    func (l klogger) WithValues(kvList ...interface{}) logr.Logger {
        new := l.clone()
        new.values = append(new.values, kvList...)
        return new
    }
    
    func (l klogger) WithName(name string) logr.Logger {
        new := l.clone()
        if len(l.prefix) > 0 {
            new.prefix = l.prefix + "/"
        }
        new.prefix += name
        return new
    }
    

    klogger定义了level、prefix、values属性,New方法创建的klogger其level为0;它实现了logr.Logger接口,其Info先判断Enabled,之后调用klog.InfoDepth;其Error方法调用的是klog.ErrorDepth;其V方法先进行clone在对level进行赋值,返回新的logr.Logger;WithValues方法先进行clone,然后设置values,返回新的logr.Logger;WithName方法也是先进行clone,在设置prefix,返回新的logr.Logger

    clone

    k8s.io/klog/v2@v2.4.0/klogr/klogr.go

    func (l klogger) clone() klogger {
        return klogger{
            level:  l.level,
            prefix: l.prefix,
            values: copySlice(l.values),
        }
    }
    

    clone方法使用原有的klogger的level、prefix、values创建一个新的klogger

    klog.V

    k8s.io/klog/v2@v2.4.0/klogr/klogr.go

    func V(level Level) Verbose {
        // This function tries hard to be cheap unless there's work to do.
        // The fast path is two atomic loads and compares.
    
        // Here is a cheap but safe test to see if V logging is enabled globally.
        if logging.verbosity.get() >= level {
            return newVerbose(level, true)
        }
    
        // It's off globally but vmodule may still be set.
        // Here is another cheap but safe test to see if vmodule is enabled.
        if atomic.LoadInt32(&logging.filterLength) > 0 {
            // Now we need a proper lock to use the logging structure. The pcs field
            // is shared so we must lock before accessing it. This is fairly expensive,
            // but if V logging is enabled we're slow anyway.
            logging.mu.Lock()
            defer logging.mu.Unlock()
            if runtime.Callers(2, logging.pcs[:]) == 0 {
                return newVerbose(level, false)
            }
            v, ok := logging.vmap[logging.pcs[0]]
            if !ok {
                v = logging.setV(logging.pcs[0])
            }
            return newVerbose(level, v >= level)
        }
        return newVerbose(level, false)
    }
    
    func newVerbose(level Level, b bool) Verbose {
        if logging.logr == nil {
            return Verbose{b, nil, logging.filter}
        }
        return Verbose{b, logging.logr.V(int(level)), logging.filter}
    }
    
    // Enabled will return true if this log level is enabled, guarded by the value
    // of v.
    // See the documentation of V for usage.
    func (v Verbose) Enabled() bool {
        return v.enabled
    }
    

    通过logging.verbosity与传入的level进行判断,若大于等于则其enabled为true;klogr.New()默认的level为0

    实例

    func logrDemo() {
        log := klogr.New().WithName("MyName").WithValues("user", "you")
        log.Info("hello", "val1", 1, "val2", map[string]int{"k": 1})
        log.V(3).Info("nice to meet you")
        log.Error(nil, "uh oh", "trouble", true, "reasons", []float64{0.1, 0.11, 3.14})
        log.Error(errors.New("an error occurred"), "goodbye", "code", -1)
    }
    

    输出

    I1230 23:12:33.388829    2890 klog_demo.go:42] MyName "msg"="hello" "user"="you" "val1"=1 "val2"={"k":1}
    E1230 23:12:33.389032    2890 klog_demo.go:44] MyName "msg"="uh oh" "error"=null "user"="you" "reasons"=[0.1,0.11,3.14] "trouble"=true
    E1230 23:12:33.389055    2890 klog_demo.go:45] MyName "msg"="goodbye" "error"="an error occurred" "user"="you" "code"=-1
    

    小结

    klogger定义了level、prefix、values属性,New方法创建的klogger其level为0;它实现了logr.Logger接口,其Info先判断Enabled,之后调用klog.InfoDepth;其Error方法调用的是klog.ErrorDepth;其V方法先进行clone在对level进行赋值,返回新的logr.Logger;WithValues方法先进行clone,然后设置values,返回新的logr.Logger;WithName方法也是先进行clone,在设置prefix,返回新的logr.Logger

    doc

    相关文章

      网友评论

          本文标题:聊聊klog的klogger

          本文链接:https://www.haomeiwen.com/subject/nqgkoktx.html