Skip to content

Commit ed8be90

Browse files
committed
⚠️ Unexport delegating logger, remove async init
Signed-off-by: Vince Prignano <vincepri@redhat.com>
1 parent f7ea9c0 commit ed8be90

File tree

3 files changed

+46
-46
lines changed

3 files changed

+46
-46
lines changed

pkg/log/deleg.go

+23-17
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,15 @@ import (
2525
// loggerPromise knows how to populate a concrete logr.Logger
2626
// with options, given an actual base logger later on down the line.
2727
type loggerPromise struct {
28-
logger *DelegatingLogSink
28+
logger *delegatingLogSink
2929
childPromises []*loggerPromise
3030
promisesLock sync.Mutex
3131

3232
name *string
3333
tags []interface{}
3434
}
3535

36-
func (p *loggerPromise) WithName(l *DelegatingLogSink, name string) *loggerPromise {
36+
func (p *loggerPromise) WithName(l *delegatingLogSink, name string) *loggerPromise {
3737
res := &loggerPromise{
3838
logger: l,
3939
name: &name,
@@ -47,7 +47,7 @@ func (p *loggerPromise) WithName(l *DelegatingLogSink, name string) *loggerPromi
4747
}
4848

4949
// WithValues provides a new Logger with the tags appended.
50-
func (p *loggerPromise) WithValues(l *DelegatingLogSink, tags ...interface{}) *loggerPromise {
50+
func (p *loggerPromise) WithValues(l *delegatingLogSink, tags ...interface{}) *loggerPromise {
5151
res := &loggerPromise{
5252
logger: l,
5353
tags: tags,
@@ -84,20 +84,21 @@ func (p *loggerPromise) Fulfill(parentLogSink logr.LogSink) {
8484
}
8585
}
8686

87-
// DelegatingLogSink is a logsink that delegates to another logr.LogSink.
87+
// delegatingLogSink is a logsink that delegates to another logr.LogSink.
8888
// If the underlying promise is not nil, it registers calls to sub-loggers with
8989
// the logging factory to be populated later, and returns a new delegating
9090
// logger. It expects to have *some* logr.Logger set at all times (generally
9191
// a no-op logger before the promises are fulfilled).
92-
type DelegatingLogSink struct {
92+
type delegatingLogSink struct {
9393
lock sync.RWMutex
9494
logger logr.LogSink
9595
promise *loggerPromise
9696
info logr.RuntimeInfo
9797
}
9898

9999
// Init implements logr.LogSink.
100-
func (l *DelegatingLogSink) Init(info logr.RuntimeInfo) {
100+
func (l *delegatingLogSink) Init(info logr.RuntimeInfo) {
101+
eventuallyFulfillRoot()
101102
l.lock.Lock()
102103
defer l.lock.Unlock()
103104
l.info = info
@@ -106,7 +107,8 @@ func (l *DelegatingLogSink) Init(info logr.RuntimeInfo) {
106107
// Enabled tests whether this Logger is enabled. For example, commandline
107108
// flags might be used to set the logging verbosity and disable some info
108109
// logs.
109-
func (l *DelegatingLogSink) Enabled(level int) bool {
110+
func (l *delegatingLogSink) Enabled(level int) bool {
111+
eventuallyFulfillRoot()
110112
l.lock.RLock()
111113
defer l.lock.RUnlock()
112114
return l.logger.Enabled(level)
@@ -118,7 +120,8 @@ func (l *DelegatingLogSink) Enabled(level int) bool {
118120
// the log line. The key/value pairs can then be used to add additional
119121
// variable information. The key/value pairs should alternate string
120122
// keys and arbitrary values.
121-
func (l *DelegatingLogSink) Info(level int, msg string, keysAndValues ...interface{}) {
123+
func (l *delegatingLogSink) Info(level int, msg string, keysAndValues ...interface{}) {
124+
eventuallyFulfillRoot()
122125
l.lock.RLock()
123126
defer l.lock.RUnlock()
124127
l.logger.Info(level, msg, keysAndValues...)
@@ -132,14 +135,16 @@ func (l *DelegatingLogSink) Info(level int, msg string, keysAndValues ...interfa
132135
// The msg field should be used to add context to any underlying error,
133136
// while the err field should be used to attach the actual error that
134137
// triggered this log line, if present.
135-
func (l *DelegatingLogSink) Error(err error, msg string, keysAndValues ...interface{}) {
138+
func (l *delegatingLogSink) Error(err error, msg string, keysAndValues ...interface{}) {
139+
eventuallyFulfillRoot()
136140
l.lock.RLock()
137141
defer l.lock.RUnlock()
138142
l.logger.Error(err, msg, keysAndValues...)
139143
}
140144

141145
// WithName provides a new Logger with the name appended.
142-
func (l *DelegatingLogSink) WithName(name string) logr.LogSink {
146+
func (l *delegatingLogSink) WithName(name string) logr.LogSink {
147+
eventuallyFulfillRoot()
143148
l.lock.RLock()
144149
defer l.lock.RUnlock()
145150

@@ -151,15 +156,16 @@ func (l *DelegatingLogSink) WithName(name string) logr.LogSink {
151156
return sink
152157
}
153158

154-
res := &DelegatingLogSink{logger: l.logger}
159+
res := &delegatingLogSink{logger: l.logger}
155160
promise := l.promise.WithName(res, name)
156161
res.promise = promise
157162

158163
return res
159164
}
160165

161166
// WithValues provides a new Logger with the tags appended.
162-
func (l *DelegatingLogSink) WithValues(tags ...interface{}) logr.LogSink {
167+
func (l *delegatingLogSink) WithValues(tags ...interface{}) logr.LogSink {
168+
eventuallyFulfillRoot()
163169
l.lock.RLock()
164170
defer l.lock.RUnlock()
165171

@@ -171,7 +177,7 @@ func (l *DelegatingLogSink) WithValues(tags ...interface{}) logr.LogSink {
171177
return sink
172178
}
173179

174-
res := &DelegatingLogSink{logger: l.logger}
180+
res := &delegatingLogSink{logger: l.logger}
175181
promise := l.promise.WithValues(res, tags...)
176182
res.promise = promise
177183

@@ -181,16 +187,16 @@ func (l *DelegatingLogSink) WithValues(tags ...interface{}) logr.LogSink {
181187
// Fulfill switches the logger over to use the actual logger
182188
// provided, instead of the temporary initial one, if this method
183189
// has not been previously called.
184-
func (l *DelegatingLogSink) Fulfill(actual logr.LogSink) {
190+
func (l *delegatingLogSink) Fulfill(actual logr.LogSink) {
185191
if l.promise != nil {
186192
l.promise.Fulfill(actual)
187193
}
188194
}
189195

190-
// NewDelegatingLogSink constructs a new DelegatingLogSink which uses
196+
// newDelegatingLogSink constructs a new DelegatingLogSink which uses
191197
// the given logger before its promise is fulfilled.
192-
func NewDelegatingLogSink(initial logr.LogSink) *DelegatingLogSink {
193-
l := &DelegatingLogSink{
198+
func newDelegatingLogSink(initial logr.LogSink) *delegatingLogSink {
199+
l := &delegatingLogSink{
194200
logger: initial,
195201
promise: &loggerPromise{promisesLock: sync.Mutex{}},
196202
}

pkg/log/log.go

+20-26
Original file line numberDiff line numberDiff line change
@@ -35,43 +35,35 @@ package log
3535

3636
import (
3737
"context"
38-
"sync"
38+
"fmt"
39+
"os"
40+
"runtime/debug"
41+
"sync/atomic"
3942
"time"
4043

4144
"github.com/go-logr/logr"
4245
)
4346

4447
// SetLogger sets a concrete logging implementation for all deferred Loggers.
4548
func SetLogger(l logr.Logger) {
46-
loggerWasSetLock.Lock()
47-
defer loggerWasSetLock.Unlock()
48-
49-
loggerWasSet = true
50-
dlog.Fulfill(l.GetSink())
49+
logFullfilled.Store(true)
50+
rootLog.Fulfill(l.GetSink())
5151
}
5252

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 DelegatingLogSink causes a high number of memory
55-
// allocations when not given an actual Logger, so we set a NullLogSink to avoid that.
56-
//
57-
// We need to keep the DelegatingLogSink 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-
dlog.Fulfill(NullLogSink{})
53+
func eventuallyFulfillRoot() {
54+
if logFullfilled.Load() {
55+
return
56+
}
57+
if time.Since(rootLogCreated).Seconds() >= 30 {
58+
if logFullfilled.CompareAndSwap(false, true) {
59+
fmt.Fprintf(os.Stderr, "[controller-runtime] log.SetLogger(...) was never called, logs will not be displayed:\n%s", debug.Stack())
60+
SetLogger(logr.New(NullLogSink{}))
6861
}
69-
}()
62+
}
7063
}
7164

7265
var (
73-
loggerWasSetLock sync.Mutex
74-
loggerWasSet bool
66+
logFullfilled atomic.Bool
7567
)
7668

7769
// Log is the base logger used by kubebuilder. It delegates
@@ -80,8 +72,10 @@ var (
8072
// the first 30 seconds of a binaries lifetime, it will get
8173
// set to a NullLogSink.
8274
var (
83-
dlog = NewDelegatingLogSink(NullLogSink{})
84-
Log = logr.New(dlog)
75+
rootLog, rootLogCreated = func() (*delegatingLogSink, time.Time) {
76+
return newDelegatingLogSink(NullLogSink{}), time.Now()
77+
}()
78+
Log = logr.New(rootLog)
8579
)
8680

8781
// FromContext returns a logger with predefined values from a context.Context.

pkg/log/log_test.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import (
2525
. "github.com/onsi/gomega"
2626
)
2727

28-
var _ logr.LogSink = &DelegatingLogSink{}
28+
var _ logr.LogSink = &delegatingLogSink{}
2929

3030
// logInfo is the information for a particular fakeLogger message.
3131
type logInfo struct {
@@ -124,13 +124,13 @@ var _ = Describe("logging", func() {
124124
var (
125125
root *fakeLoggerRoot
126126
baseLog logr.LogSink
127-
delegLog *DelegatingLogSink
127+
delegLog *delegatingLogSink
128128
)
129129

130130
BeforeEach(func() {
131131
root = &fakeLoggerRoot{}
132132
baseLog = &fakeLogger{root: root}
133-
delegLog = NewDelegatingLogSink(NullLogSink{})
133+
delegLog = newDelegatingLogSink(NullLogSink{})
134134
})
135135

136136
It("should delegate with name", func() {

0 commit comments

Comments
 (0)