本文次要钻研一下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"=trueE1230 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
  • logr