@@ -35,18 +35,50 @@ package log
3535
3636import (
3737 "context"
38+ "sync"
39+ "time"
3840
3941 "github.com/go-logr/logr"
4042)
4143
4244// SetLogger sets a concrete logging implementation for all deferred Loggers.
4345func SetLogger (l logr.Logger ) {
46+ loggerWasSetLock .Lock ()
47+ defer loggerWasSetLock .Unlock ()
48+
49+ loggerWasSet = true
4450 Log .Fulfill (l )
4551}
4652
53+ // It is safe to assume that if this wasn't set within the first 30 seconds of a binaries
54+ // lifetime, it will never get set. The DelegatingLogger causes a high number of memory
55+ // allocations when not given an actual Logger, so we set a NullLogger to avoid that.
56+ //
57+ // We need to keep the DelegatingLogger because we have various inits() that get a logger from
58+ // here. They will always get executed before any code that imports controller-runtime
59+ // has a chance to run and hence to set an actual logger.
60+ func init () {
61+ // Init is blocking, so start a new goroutine
62+ go func () {
63+ time .Sleep (30 * time .Second )
64+ loggerWasSetLock .Lock ()
65+ defer loggerWasSetLock .Unlock ()
66+ if ! loggerWasSet {
67+ Log .Fulfill (NullLogger {})
68+ }
69+ }()
70+ }
71+
72+ var (
73+ loggerWasSetLock sync.Mutex
74+ loggerWasSet bool
75+ )
76+
4777// Log is the base logger used by kubebuilder. It delegates
48- // to another logr.Logger. You *must* call SetLogger to
49- // get any actual logging.
78+ // to another logr.Logger. You *must* call SetLogger to
79+ // get any actual logging. If SetLogger is not called within
80+ // the first 30 seconds of a binaries lifetime, it will get
81+ // set to a NullLogger.
5082var Log = NewDelegatingLogger (NullLogger {})
5183
5284// FromContext returns a logger with predefined values from a context.Context.
0 commit comments