Skip to content

Commit

Permalink
Merge pull request #183 from rf232/KEP-1753-logfilter
Browse files Browse the repository at this point in the history
Add support to add a logfilter
  • Loading branch information
k8s-ci-robot committed Oct 28, 2020
2 parents 87db504 + 3310004 commit 321016d
Show file tree
Hide file tree
Showing 2 changed files with 244 additions and 40 deletions.
117 changes: 77 additions & 40 deletions klog.go
Expand Up @@ -510,6 +510,9 @@ type loggingT struct {

// If true, messages will not be propagated to lower severity log levels
oneOutput bool

// If set, all output will be filtered through the filter.
filter LogFilter
}

// buffer holds a byte Buffer for reuse. The zero value is ready for use.
Expand Down Expand Up @@ -692,45 +695,54 @@ func (buf *buffer) someDigits(i, d int) int {
return copy(buf.tmp[i:], buf.tmp[j:])
}

func (l *loggingT) println(s severity, logr logr.Logger, args ...interface{}) {
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) print(s severity, logr logr.Logger, args ...interface{}) {
l.printDepth(s, logr, 1, args...)
func (l *loggingT) print(s severity, logr logr.Logger, filter LogFilter, args ...interface{}) {
l.printDepth(s, logr, filter, 1, args...)
}

func (l *loggingT) printDepth(s severity, logr logr.Logger, depth int, args ...interface{}) {
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) printf(s severity, logr logr.Logger, format string, args ...interface{}) {
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')
Expand All @@ -741,14 +753,17 @@ func (l *loggingT) printf(s severity, logr logr.Logger, format string, args ...i
// printWithFileLine behaves like print but uses the provided file and line number. If
// alsoLogToStderr is true, the log message always appears on standard error; it
// will also appear in the log file unless --logtostderr is set.
func (l *loggingT) printWithFileLine(s severity, logr logr.Logger, file string, line int, alsoToStderr bool, args ...interface{}) {
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')
Expand All @@ -757,7 +772,10 @@ func (l *loggingT) printWithFileLine(s severity, logr logr.Logger, file string,
}

// if loggr is specified, will call loggr.Error, otherwise output with logging module.
func (l *loggingT) errorS(err error, loggr logr.Logger, msg string, keysAndValues ...interface{}) {
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
Expand All @@ -766,7 +784,10 @@ func (l *loggingT) errorS(err error, loggr logr.Logger, msg string, keysAndValue
}

// if loggr is specified, will call loggr.Info, otherwise output with logging module.
func (l *loggingT) infoS(loggr logr.Logger, msg string, keysAndValues ...interface{}) {
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
Expand All @@ -790,7 +811,7 @@ func (l *loggingT) printS(err error, msg string, keysAndValues ...interface{}) {
} else {
s = errorLog
}
l.printDepth(s, logging.logr, 2, b)
l.printDepth(s, logging.logr, nil, 2, b)
}

const missingValue = "(MISSING)"
Expand Down Expand Up @@ -1214,7 +1235,7 @@ func (lb logBridge) Write(b []byte) (n int, err error) {
}
// printWithFileLine with alsoToStderr=true, so standard log messages
// always appear on standard error.
logging.printWithFileLine(severity(lb), logging.logr, file, line, true, text)
logging.printWithFileLine(severity(lb), logging.logr, logging.filter, file, line, true, text)
return len(b), nil
}

Expand Down Expand Up @@ -1249,13 +1270,14 @@ func (l *loggingT) setV(pc uintptr) Level {
type Verbose struct {
enabled bool
logr logr.Logger
filter LogFilter
}

func newVerbose(level Level, b bool) Verbose {
if logging.logr == nil {
return Verbose{b, nil}
return Verbose{b, nil, logging.filter}
}
return Verbose{b, logging.logr.V(int(level))}
return Verbose{b, logging.logr.V(int(level)), logging.filter}
}

// V reports whether verbosity at the call site is at least the requested level.
Expand Down Expand Up @@ -1313,71 +1335,71 @@ func (v Verbose) Enabled() bool {
// See the documentation of V for usage.
func (v Verbose) Info(args ...interface{}) {
if v.enabled {
logging.print(infoLog, v.logr, args...)
logging.print(infoLog, v.logr, v.filter, args...)
}
}

// Infoln is equivalent to the global Infoln function, guarded by the value of v.
// See the documentation of V for usage.
func (v Verbose) Infoln(args ...interface{}) {
if v.enabled {
logging.println(infoLog, v.logr, args...)
logging.println(infoLog, v.logr, v.filter, args...)
}
}

// Infof is equivalent to the global Infof function, guarded by the value of v.
// See the documentation of V for usage.
func (v Verbose) Infof(format string, args ...interface{}) {
if v.enabled {
logging.printf(infoLog, v.logr, format, args...)
logging.printf(infoLog, v.logr, v.filter, format, args...)
}
}

// InfoS is equivalent to the global InfoS function, guarded by the value of v.
// See the documentation of V for usage.
func (v Verbose) InfoS(msg string, keysAndValues ...interface{}) {
if v.enabled {
logging.infoS(v.logr, msg, keysAndValues...)
logging.infoS(v.logr, v.filter, msg, keysAndValues...)
}
}

// Deprecated: Use ErrorS instead.
func (v Verbose) Error(err error, msg string, args ...interface{}) {
if v.enabled {
logging.errorS(err, v.logr, msg, args...)
logging.errorS(err, v.logr, v.filter, msg, args...)
}
}

// ErrorS is equivalent to the global Error function, guarded by the value of v.
// See the documentation of V for usage.
func (v Verbose) ErrorS(err error, msg string, keysAndValues ...interface{}) {
if v.enabled {
logging.errorS(err, v.logr, msg, keysAndValues...)
logging.errorS(err, v.logr, v.filter, msg, keysAndValues...)
}
}

// Info logs to the INFO log.
// Arguments are handled in the manner of fmt.Print; a newline is appended if missing.
func Info(args ...interface{}) {
logging.print(infoLog, logging.logr, args...)
logging.print(infoLog, logging.logr, logging.filter, args...)
}

// InfoDepth acts as Info but uses depth to determine which call frame to log.
// InfoDepth(0, "msg") is the same as Info("msg").
func InfoDepth(depth int, args ...interface{}) {
logging.printDepth(infoLog, logging.logr, depth, args...)
logging.printDepth(infoLog, logging.logr, logging.filter, depth, args...)
}

// Infoln logs to the INFO log.
// Arguments are handled in the manner of fmt.Println; a newline is always appended.
func Infoln(args ...interface{}) {
logging.println(infoLog, logging.logr, args...)
logging.println(infoLog, logging.logr, logging.filter, args...)
}

// Infof logs to the INFO log.
// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
func Infof(format string, args ...interface{}) {
logging.printf(infoLog, logging.logr, format, args...)
logging.printf(infoLog, logging.logr, logging.filter, format, args...)
}

// InfoS structured logs to the INFO log.
Expand All @@ -1389,55 +1411,55 @@ func Infof(format string, args ...interface{}) {
// output:
// >> I1025 00:15:15.525108 1 controller_utils.go:116] "Pod status updated" pod="kubedns" status="ready"
func InfoS(msg string, keysAndValues ...interface{}) {
logging.infoS(logging.logr, msg, keysAndValues...)
logging.infoS(logging.logr, logging.filter, msg, keysAndValues...)
}

// Warning logs to the WARNING and INFO logs.
// Arguments are handled in the manner of fmt.Print; a newline is appended if missing.
func Warning(args ...interface{}) {
logging.print(warningLog, logging.logr, args...)
logging.print(warningLog, logging.logr, logging.filter, args...)
}

// WarningDepth acts as Warning but uses depth to determine which call frame to log.
// WarningDepth(0, "msg") is the same as Warning("msg").
func WarningDepth(depth int, args ...interface{}) {
logging.printDepth(warningLog, logging.logr, depth, args...)
logging.printDepth(warningLog, logging.logr, logging.filter, depth, args...)
}

// Warningln logs to the WARNING and INFO logs.
// Arguments are handled in the manner of fmt.Println; a newline is always appended.
func Warningln(args ...interface{}) {
logging.println(warningLog, logging.logr, args...)
logging.println(warningLog, logging.logr, logging.filter, args...)
}

// Warningf logs to the WARNING and INFO logs.
// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
func Warningf(format string, args ...interface{}) {
logging.printf(warningLog, logging.logr, format, args...)
logging.printf(warningLog, logging.logr, logging.filter, format, args...)
}

// Error logs to the ERROR, WARNING, and INFO logs.
// Arguments are handled in the manner of fmt.Print; a newline is appended if missing.
func Error(args ...interface{}) {
logging.print(errorLog, logging.logr, args...)
logging.print(errorLog, logging.logr, logging.filter, args...)
}

// ErrorDepth acts as Error but uses depth to determine which call frame to log.
// ErrorDepth(0, "msg") is the same as Error("msg").
func ErrorDepth(depth int, args ...interface{}) {
logging.printDepth(errorLog, logging.logr, depth, args...)
logging.printDepth(errorLog, logging.logr, logging.filter, depth, args...)
}

// Errorln logs to the ERROR, WARNING, and INFO logs.
// Arguments are handled in the manner of fmt.Println; a newline is always appended.
func Errorln(args ...interface{}) {
logging.println(errorLog, logging.logr, args...)
logging.println(errorLog, logging.logr, logging.filter, args...)
}

// Errorf logs to the ERROR, WARNING, and INFO logs.
// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
func Errorf(format string, args ...interface{}) {
logging.printf(errorLog, logging.logr, format, args...)
logging.printf(errorLog, logging.logr, logging.filter, format, args...)
}

// ErrorS structured logs to the ERROR, WARNING, and INFO logs.
Expand All @@ -1450,34 +1472,34 @@ func Errorf(format string, args ...interface{}) {
// output:
// >> E1025 00:15:15.525108 1 controller_utils.go:114] "Failed to update pod status" err="timeout"
func ErrorS(err error, msg string, keysAndValues ...interface{}) {
logging.errorS(err, logging.logr, msg, keysAndValues...)
logging.errorS(err, logging.logr, logging.filter, msg, keysAndValues...)
}

// Fatal logs to the FATAL, ERROR, WARNING, and INFO logs,
// including a stack trace of all running goroutines, then calls os.Exit(255).
// Arguments are handled in the manner of fmt.Print; a newline is appended if missing.
func Fatal(args ...interface{}) {
logging.print(fatalLog, logging.logr, args...)
logging.print(fatalLog, logging.logr, logging.filter, args...)
}

// FatalDepth acts as Fatal but uses depth to determine which call frame to log.
// FatalDepth(0, "msg") is the same as Fatal("msg").
func FatalDepth(depth int, args ...interface{}) {
logging.printDepth(fatalLog, logging.logr, depth, args...)
logging.printDepth(fatalLog, logging.logr, logging.filter, depth, args...)
}

// Fatalln logs to the FATAL, ERROR, WARNING, and INFO logs,
// including a stack trace of all running goroutines, then calls os.Exit(255).
// Arguments are handled in the manner of fmt.Println; a newline is always appended.
func Fatalln(args ...interface{}) {
logging.println(fatalLog, logging.logr, args...)
logging.println(fatalLog, logging.logr, logging.filter, args...)
}

// Fatalf logs to the FATAL, ERROR, WARNING, and INFO logs,
// including a stack trace of all running goroutines, then calls os.Exit(255).
// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
func Fatalf(format string, args ...interface{}) {
logging.printf(fatalLog, logging.logr, format, args...)
logging.printf(fatalLog, logging.logr, logging.filter, format, args...)
}

// fatalNoStacks is non-zero if we are to exit without dumping goroutine stacks.
Expand All @@ -1488,27 +1510,42 @@ var fatalNoStacks uint32
// Arguments are handled in the manner of fmt.Print; a newline is appended if missing.
func Exit(args ...interface{}) {
atomic.StoreUint32(&fatalNoStacks, 1)
logging.print(fatalLog, logging.logr, args...)
logging.print(fatalLog, logging.logr, logging.filter, args...)
}

// ExitDepth acts as Exit but uses depth to determine which call frame to log.
// ExitDepth(0, "msg") is the same as Exit("msg").
func ExitDepth(depth int, args ...interface{}) {
atomic.StoreUint32(&fatalNoStacks, 1)
logging.printDepth(fatalLog, logging.logr, depth, args...)
logging.printDepth(fatalLog, logging.logr, logging.filter, depth, args...)
}

// Exitln logs to the FATAL, ERROR, WARNING, and INFO logs, then calls os.Exit(1).
func Exitln(args ...interface{}) {
atomic.StoreUint32(&fatalNoStacks, 1)
logging.println(fatalLog, logging.logr, args...)
logging.println(fatalLog, logging.logr, logging.filter, args...)
}

// Exitf logs to the FATAL, ERROR, WARNING, and INFO logs, then calls os.Exit(1).
// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
func Exitf(format string, args ...interface{}) {
atomic.StoreUint32(&fatalNoStacks, 1)
logging.printf(fatalLog, logging.logr, format, args...)
logging.printf(fatalLog, logging.logr, logging.filter, format, args...)
}

// 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
}

// ObjectRef references a kubernetes object
Expand Down

0 comments on commit 321016d

Please sign in to comment.