Skip to content

Commit

Permalink
Add LogSink.Init() mechanism
Browse files Browse the repository at this point in the history
This allows logr to pass params about internal stuff (such as the number
of call frames it adds) to LogSink implementations.
  • Loading branch information
thockin committed May 16, 2021
1 parent 000e78e commit 19480e9
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 17 deletions.
3 changes: 3 additions & 0 deletions discard.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ type DiscardLogger struct{}
// Verify that it actually implements the interface
var _ LogSink = DiscardLogger{}

func (l DiscardLogger) Init(RuntimeInfo) {
}

func (l DiscardLogger) Enabled(int) bool {
return false
}
Expand Down
3 changes: 3 additions & 0 deletions examples/tab_logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ type tabLogSink struct {

var _ logr.LogSink = tabLogSink{}

func (_ tabLogSink) Init(info logr.RuntimeInfo) {
}

func (_ tabLogSink) Enabled(level int) bool {
return true
}
Expand Down
42 changes: 25 additions & 17 deletions funcr/funcr.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import (

// New returns a logr.Logger which is implemented by a function.
func New(fn func(prefix, args string), opts Options) logr.Logger {
fnl := fnlogger{
fnl := &fnlogger{
prefix: "",
values: nil,
depth: 0,
Expand Down Expand Up @@ -267,16 +267,18 @@ type callerID struct {
}

func (l fnlogger) caller() callerID {
// +1 for this frame, +1 for logr itself.
// FIXME: Maybe logr should offer a clue as to how many frames are
// needed here? Or is it part of the contract to LogSinks?
_, file, line, ok := runtime.Caller(framesToCaller() + l.depth + 2)
// +1 for this frame.
_, file, line, ok := runtime.Caller(framesToCaller() + l.depth + 1)
if !ok {
return callerID{"<unknown>", 0}
}
return callerID{filepath.Base(file), line}
}

func (l *fnlogger) Init(info logr.RuntimeInfo) {
l.depth += info.CallDepth
}

func (l fnlogger) Enabled(level int) bool {
return level <= l.verbosity
}
Expand Down Expand Up @@ -313,25 +315,31 @@ func (l fnlogger) Error(err error, msg string, kvList ...interface{}) {
// WithName returns a new Logger with the specified name appended. funcr
// uses '/' characters to separate name elements. Callers should not pass '/'
// in the provided name string, but this library does not actually enforce that.
func (l fnlogger) WithName(name string) logr.LogSink {
if len(l.prefix) > 0 {
l.prefix = l.prefix + "/"
func (l *fnlogger) WithName(name string) logr.LogSink {
l2 := &fnlogger{}
*l2 = *l
if len(l2.prefix) > 0 {
l.prefix = l2.prefix + "/"
}
l.prefix += name
l2.prefix += name
return l
}

func (l fnlogger) WithValues(kvList ...interface{}) logr.LogSink {
func (l *fnlogger) WithValues(kvList ...interface{}) logr.LogSink {
l2 := &fnlogger{}
*l2 = *l
// Three slice args forces a copy.
n := len(l.values)
l.values = append(l.values[:n:n], kvList...)
return l
l2.values = append(l2.values[:n:n], kvList...)
return l2
}

func (l fnlogger) WithCallDepth(depth int) logr.LogSink {
l.depth += depth
return l
func (l *fnlogger) WithCallDepth(depth int) logr.LogSink {
l2 := &fnlogger{}
*l2 = *l
l2.depth += depth
return l2
}

var _ logr.LogSink = fnlogger{}
var _ logr.CallDepthLogSink = fnlogger{}
var _ logr.LogSink = &fnlogger{}
var _ logr.CallDepthLogSink = &fnlogger{}
20 changes: 20 additions & 0 deletions logr.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ func New(sink LogSink) Logger {
if withCallDepth, ok := sink.(CallDepthLogSink); ok {
logger.withCallDepth = withCallDepth
}
sink.Init(runtimeInfo)
return logger
}

Expand Down Expand Up @@ -319,9 +320,28 @@ func NewContext(ctx context.Context, logger Logger) context.Context {
return context.WithValue(ctx, contextKey{}, logger)
}

// RuntimeInfo holds information that the logr "core" library knows which
// LogSinks might want to know.
type RuntimeInfo struct {
// CallDepth is the number of call frames the logr library adds between the
// end-user and the LogSink. LogSink implementations which choose to print
// the original logging site (e.g. file & line) should climb this many
// additional frames to find it.
CallDepth int
}

// runtimeInfo is a static global. It must not be changed at run time.
var runtimeInfo = RuntimeInfo{
CallDepth: 1,
}

// LogSink represents a logging implementation. End-users will generally not
// interact with this type.
type LogSink interface {
// Init receives optional information about the logr library for LogSink
// implementations that need it.
Init(info RuntimeInfo)

// Enabled tests whether this LogSink is enabled at the specified V-level.
// For example, commandline flags might be used to set the logging
// verbosity and disable some info logs.
Expand Down
3 changes: 3 additions & 0 deletions logr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ import (
// testLogSink is a Logger just for testing that does nothing.
type testLogSink struct{}

func (l *testLogSink) Init(RuntimeInfo) {
}

func (l *testLogSink) Enabled(int) bool {
return false
}
Expand Down

0 comments on commit 19480e9

Please sign in to comment.