序
本文主要研究一下klog的LogFilter
LogFilter
k8s.io/klog/[email protected]/klog.go
// LogFilter is a collection of functions that can filter all logging calls,
// e.g. for sanitization of arguments and prevent accidental leaking of secrets.
type LogFilter interface {
Filter(args []interface{}) []interface{}
FilterF(format string, args []interface{}) (string, []interface{})
FilterS(msg string, keysAndValues []interface{}) (string, []interface{})
}
func SetLogFilter(filter LogFilter) {
logging.mu.Lock()
defer logging.mu.Unlock()
logging.filter = filter
}
LogFilter接口定义了Filter、FilterF、FilterS方法用于过滤log
filter.Filter
k8s.io/klog/[email protected]/klog.go
func (l *loggingT) println(s severity, logr logr.Logger, filter LogFilter, args ...interface{}) {
buf, file, line := l.header(s, 0)
// if logr is set, we clear the generated header as we rely on the backing
// logr implementation to print headers
if logr != nil {
l.putBuffer(buf)
buf = l.getBuffer()
}
if filter != nil {
args = filter.Filter(args)
}
fmt.Fprintln(buf, args...)
l.output(s, logr, buf, file, line, false)
}
func (l *loggingT) printDepth(s severity, logr logr.Logger, filter LogFilter, depth int, args ...interface{}) {
buf, file, line := l.header(s, depth)
// if logr is set, we clear the generated header as we rely on the backing
// logr implementation to print headers
if logr != nil {
l.putBuffer(buf)
buf = l.getBuffer()
}
if filter != nil {
args = filter.Filter(args)
}
fmt.Fprint(buf, args...)
if buf.Bytes()[buf.Len()-1] != '\n' {
buf.WriteByte('\n')
}
l.output(s, logr, buf, file, line, false)
}
func (l *loggingT) printWithFileLine(s severity, logr logr.Logger, filter LogFilter, file string, line int, alsoToStderr bool, args ...interface{}) {
buf := l.formatHeader(s, file, line)
// if logr is set, we clear the generated header as we rely on the backing
// logr implementation to print headers
if logr != nil {
l.putBuffer(buf)
buf = l.getBuffer()
}
if filter != nil {
args = filter.Filter(args)
}
fmt.Fprint(buf, args...)
if buf.Bytes()[buf.Len()-1] != '\n' {
buf.WriteByte('\n')
}
l.output(s, logr, buf, file, line, alsoToStderr)
}
println、printDepth、printWithFileLine会通过filter.Filter(args)来过滤args
filter.FilterF
k8s.io/klog/[email protected]/klog.go
func (l *loggingT) printf(s severity, logr logr.Logger, filter LogFilter, format string, args ...interface{}) {
buf, file, line := l.header(s, 0)
// if logr is set, we clear the generated header as we rely on the backing
// logr implementation to print headers
if logr != nil {
l.putBuffer(buf)
buf = l.getBuffer()
}
if filter != nil {
format, args = filter.FilterF(format, args)
}
fmt.Fprintf(buf, format, args...)
if buf.Bytes()[buf.Len()-1] != '\n' {
buf.WriteByte('\n')
}
l.output(s, logr, buf, file, line, false)
}
printf方法使用filter.FilterF(format, args)返回的format及args进行格式化
filter.FilterS
k8s.io/klog/[email protected]/klog.go
func (l *loggingT) infoS(loggr logr.Logger, filter LogFilter, msg string, keysAndValues ...interface{}) {
if filter != nil {
msg, keysAndValues = filter.FilterS(msg, keysAndValues)
}
if loggr != nil {
loggr.Info(msg, keysAndValues...)
return
}
l.printS(nil, msg, keysAndValues...)
}
func (l *loggingT) errorS(err error, loggr logr.Logger, filter LogFilter, msg string, keysAndValues ...interface{}) {
if filter != nil {
msg, keysAndValues = filter.FilterS(msg, keysAndValues)
}
if loggr != nil {
loggr.Error(err, msg, keysAndValues...)
return
}
l.printS(err, msg, keysAndValues...)
}
infoS及errorS方法会使用filter.FilterS(msg, keysAndValues)返回的msg及keysAndValues进行打印
实例
type sampleLogFilter struct{}
func (f *sampleLogFilter) Filter(args []interface{}) []interface{} {
for i, arg := range args {
v, ok := arg.(string)
if ok && strings.Contains(v, "filter me") {
args[i] = "[FILTERED]"
}
}
return args
}
func (f *sampleLogFilter) FilterF(format string, args []interface{}) (string, []interface{}) {
return strings.Replace(format, "filter me", "[FILTERED]", 1), f.Filter(args)
}
func (f *sampleLogFilter) FilterS(msg string, keysAndValues []interface{}) (string, []interface{}) {
return strings.Replace(msg, "filter me", "[FILTERED]", 1), f.Filter(keysAndValues)
}
func TestLogFilter(t *testing.T) {
setFlags()
defer logging.swap(logging.newBuffers())
SetLogFilter(&sampleLogFilter{})
defer SetLogFilter(nil)
funcs := []struct {
name string
logFunc func(args ...interface{})
severity severity
}{{
name: "Info",
logFunc: Info,
severity: infoLog,
}, {
name: "InfoDepth",
logFunc: func(args ...interface{}) {
InfoDepth(1, args...)
},
severity: infoLog,
}, {
name: "Infoln",
logFunc: Infoln,
severity: infoLog,
}, {
name: "Infof",
logFunc: func(args ...interface{}) {
Infof(args[0].(string), args[1:]...)
},
severity: infoLog,
}, {
name: "InfoS",
logFunc: func(args ...interface{}) {
InfoS(args[0].(string), args[1:]...)
},
severity: infoLog,
}, {
name: "Warning",
logFunc: Warning,
severity: warningLog,
}, {
name: "WarningDepth",
logFunc: func(args ...interface{}) {
WarningDepth(1, args...)
},
severity: warningLog,
}, {
name: "Warningln",
logFunc: Warningln,
severity: warningLog,
}, {
name: "Warningf",
logFunc: func(args ...interface{}) {
Warningf(args[0].(string), args[1:]...)
},
severity: warningLog,
}, {
name: "Error",
logFunc: Error,
severity: errorLog,
}, {
name: "ErrorDepth",
logFunc: func(args ...interface{}) {
ErrorDepth(1, args...)
},
severity: errorLog,
}, {
name: "Errorln",
logFunc: Errorln,
severity: errorLog,
}, {
name: "Errorf",
logFunc: func(args ...interface{}) {
Errorf(args[0].(string), args[1:]...)
},
severity: errorLog,
}, {
name: "ErrorS",
logFunc: func(args ...interface{}) {
ErrorS(errors.New("testerror"), args[0].(string), args[1:]...)
},
severity: errorLog,
}, {
name: "V().Info",
logFunc: func(args ...interface{}) {
V(0).Info(args...)
},
severity: infoLog,
}, {
name: "V().Infoln",
logFunc: func(args ...interface{}) {
V(0).Infoln(args...)
},
severity: infoLog,
}, {
name: "V().Infof",
logFunc: func(args ...interface{}) {
V(0).Infof(args[0].(string), args[1:]...)
},
severity: infoLog,
}, {
name: "V().InfoS",
logFunc: func(args ...interface{}) {
V(0).InfoS(args[0].(string), args[1:]...)
},
severity: infoLog,
}, {
name: "V().Error",
logFunc: func(args ...interface{}) {
V(0).Error(errors.New("test error"), args[0].(string), args[1:]...)
},
severity: errorLog,
}, {
name: "V().ErrorS",
logFunc: func(args ...interface{}) {
V(0).ErrorS(errors.New("test error"), args[0].(string), args[1:]...)
},
severity: errorLog,
}}
testcases := []struct {
name string
args []interface{}
expectFiltered bool
}{{
args: []interface{}{"%s:%s", "foo", "bar"},
expectFiltered: false,
}, {
args: []interface{}{"%s:%s", "foo", "filter me"},
expectFiltered: true,
}, {
args: []interface{}{"filter me %s:%s", "foo", "bar"},
expectFiltered: true,
}}
for _, f := range funcs {
for _, tc := range testcases {
logging.newBuffers()
f.logFunc(tc.args...)
got := contains(f.severity, "[FILTERED]", t)
if got != tc.expectFiltered {
t.Errorf("%s filter application failed, got %v, want %v", f.name, got, tc.expectFiltered)
}
}
}
}
小结
klog的LogFilter接口定义了Filter、FilterF、FilterS方法用于过滤log;println、printDepth、printWithFileLine会通过filter.Filter(args)来过滤args;printf方法使用filter.FilterF(format, args)返回的format及args进行格式化;infoS及errorS方法会使用filter.FilterS(msg, keysAndValues)返回的msg及keysAndValues进行打印。