@@ -35,18 +35,50 @@ package log
35
35
36
36
import (
37
37
"context"
38
+ "sync"
39
+ "time"
38
40
39
41
"github.com/go-logr/logr"
40
42
)
41
43
42
44
// SetLogger sets a concrete logging implementation for all deferred Loggers.
43
45
func SetLogger (l logr.Logger ) {
46
+ loggerWasSetLock .Lock ()
47
+ defer loggerWasSetLock .Unlock ()
48
+
49
+ loggerWasSet = true
44
50
Log .Fulfill (l )
45
51
}
46
52
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
+
47
77
// 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.
50
82
var Log = NewDelegatingLogger (NullLogger {})
51
83
52
84
// FromContext returns a logger with predefined values from a context.Context.
0 commit comments