Skip to content

Commit 19f1595

Browse files
committed
debug logger: remove logger callbacks
All debug logger instances were previously attached to a global set of callbacks. This was done so loggers could be informed if they were ever enabled dynamically. Unfortunately, loggers were never removed from this set of callbacks, which meant that those loggers could never be reclaimed by the garbage collector. Debug loggers are often constructed as the program runs, adding fields and values to assist with tracing. This meant that programs often did not have a static set of loggers, but were always creating new debug loggers, which were always seen as live objects. Now, debug loggers always ask their enabled status from the map tracking enabled state. This incurs the cost of a mutex-read lock and map lookup at runtime.
1 parent 7f26097 commit 19f1595

File tree

4 files changed

+277
-86
lines changed

4 files changed

+277
-86
lines changed

pkg/rslog/NEWS.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,10 @@ Unreleased
99
* Uncomment when items are available.
1010
-->
1111

12-
<!--
1312
### Fixed
1413

15-
* Uncomment when items are available.
16-
-->
14+
* Debug loggers are no longer attached to a global set of callbacks, which
15+
means that those loggers are available for garbage collection.
1716

1817
<!--
1918
### Breaking

pkg/rslog/debug.go

Lines changed: 86 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -6,106 +6,125 @@ import (
66
"sync"
77
)
88

9+
// ProductRegion is a numerical value assigned to an area of the product.
910
type ProductRegion int
1011

11-
// regionNames translates the enum region to its string equivalent. This is
12-
// used for display (when logging) and also when processing the configuration
13-
// values.
14-
var regionNames map[ProductRegion]string
12+
// debugMutex protects access to product debug region/enabled information.
13+
var debugMutex sync.RWMutex
1514

16-
type callbacksArr []func(flag bool)
15+
// debugRegions relates a numerical product debug region to its string
16+
// equivalent. Used for display (when logging) and when processing
17+
// configuration values.
18+
//
19+
// Protected by debugMutex.
20+
var debugRegions map[ProductRegion]string = map[ProductRegion]string{}
1721

18-
var regionCallbacks = map[ProductRegion]callbacksArr{}
19-
var regionsEnabled = map[ProductRegion]bool{}
20-
var debugMutex sync.RWMutex
22+
// debugEnabled records product debug regions which enable debug logging.
23+
//
24+
// Protected by debugMutex.
25+
var debugEnabled map[ProductRegion]bool = map[ProductRegion]bool{}
2126

27+
// RegisterRegions registers product debug regions. Called once at program
28+
// startup.
2229
func RegisterRegions(regions map[ProductRegion]string) {
23-
regionNames = regions
30+
debugMutex.Lock()
31+
defer debugMutex.Unlock()
32+
33+
debugRegions = regions
2434
}
2535

36+
// RegionNames returns the names of all registered product debug regions.
2637
func RegionNames() []string {
38+
debugMutex.RLock()
39+
defer debugMutex.RUnlock()
40+
2741
var names []string
28-
for _, name := range regionNames {
42+
for _, name := range debugRegions {
2943
names = append(names, name)
3044
}
3145
return names
3246
}
3347

48+
// Regions returns the numerical product debug regions.
3449
func Regions() []ProductRegion {
50+
debugMutex.RLock()
51+
defer debugMutex.RUnlock()
52+
3553
var regions []ProductRegion
36-
for r := range regionNames {
54+
for r := range debugRegions {
3755
regions = append(regions, r)
3856
}
3957
return regions
4058
}
4159

42-
func RegionByName(text string) ProductRegion {
43-
for region, name := range regionNames {
44-
if name == text {
60+
// RegionByName returns the numerical product debug region associated with
61+
// name. Returns zero when there is no match.
62+
func RegionByName(name string) ProductRegion {
63+
debugMutex.RLock()
64+
defer debugMutex.RUnlock()
65+
66+
for region, region_name := range debugRegions {
67+
if name == region_name {
4568
return region
4669
}
4770
}
4871
return 0
4972
}
5073

74+
// RegionName returns the name associated with the numerical product debug
75+
// region. Returns an empty string when there is no match.
5176
func RegionName(region ProductRegion) string {
52-
return regionNames[region]
77+
debugMutex.RLock()
78+
defer debugMutex.RUnlock()
79+
80+
return debugRegions[region]
5381
}
5482

55-
// Register debug regions enabled.
56-
// This should be called as early as possible when starting an application.
83+
// InitDebugLogs registers a set of product debug regions as enabled.
84+
//
85+
// This should be called as early as possible when starting an application,
86+
// but after RegisterRegions.
5787
func InitDebugLogs(regions []ProductRegion) {
5888
debugMutex.Lock()
5989
defer debugMutex.Unlock()
6090

6191
// Reset enabled regions on each call.
62-
regionsEnabled = make(map[ProductRegion]bool)
92+
debugEnabled = make(map[ProductRegion]bool)
6393
lgr := DefaultLogger()
6494

6595
// match debug log region to list
6696
for _, region := range regions {
6797
if region == 0 {
6898
continue
6999
}
70-
regionsEnabled[region] = true
71-
regionName := RegionName(region)
100+
debugEnabled[region] = true
101+
regionName := debugRegions[region]
72102
lgr.Infof("Debug logging enabled for area: %s", regionName)
73103
}
74104
}
75105

76-
// Enable turns on logging for a named region. Useful in test.
106+
// Enable turns on debug logging for region. Useful in test.
77107
func Enable(region ProductRegion) {
78108
debugMutex.Lock()
79109
defer debugMutex.Unlock()
80110

81-
regionsEnabled[region] = true
82-
_, ok := regionCallbacks[region]
83-
if ok {
84-
for _, cb := range regionCallbacks[region] {
85-
cb(true)
86-
}
87-
}
111+
debugEnabled[region] = true
88112
}
89113

90-
// Disable turns on logging for a named region. Useful in test.
114+
// Disable turns on debug logging for region. Useful in test.
91115
func Disable(region ProductRegion) {
92116
debugMutex.Lock()
93117
defer debugMutex.Unlock()
94118

95-
regionsEnabled[region] = false
96-
_, ok := regionCallbacks[region]
97-
if ok {
98-
for _, cb := range regionCallbacks[region] {
99-
cb(false)
100-
}
101-
}
119+
debugEnabled[region] = false
102120
}
103121

104-
// Enabled returns true if debug logging is configured for this region.
122+
// Enabled returns true if debug logging is configured for region.
105123
func Enabled(region ProductRegion) bool {
106124
debugMutex.RLock()
107125
defer debugMutex.RUnlock()
108-
return regionsEnabled[region]
126+
127+
return debugEnabled[region]
109128
}
110129

111130
type DebugLogger interface {
@@ -118,86 +137,73 @@ type DebugLogger interface {
118137

119138
type debugLogger struct {
120139
Logger
121-
region ProductRegion
122-
enabled bool
140+
region ProductRegion
123141
}
124142

125-
// NewDebugLogger returns a new logger which includes
126-
// the name of the debug region at every message.
143+
// NewDebugLogger returns a new logger which includes the name of the product
144+
// debug region at every message. Debugf and Tracef only occur when the
145+
// product debug region is enabled.
146+
//
147+
// Logging occurs only when enabled for region.
127148
func NewDebugLogger(region ProductRegion) *debugLogger {
128149
lgr := DefaultLogger()
129150

151+
regionName := RegionName(region)
130152
entry := lgr.WithFields(Fields{
131-
"region": regionNames[region],
153+
"region": regionName,
132154
})
133155

134156
dbglgr := &debugLogger{
135-
Logger: entry,
136-
region: region,
137-
enabled: Enabled(region),
157+
Logger: entry,
158+
region: region,
138159
}
139160

140-
registerLoggerCb(region, dbglgr.enable)
141-
142161
return dbglgr
143162
}
144163

145-
func registerLoggerCb(region ProductRegion, cb func(bool)) {
146-
debugMutex.Lock()
147-
defer debugMutex.Unlock()
148-
149-
regionCallbacks[region] = append(regionCallbacks[region], cb)
150-
}
151-
152-
// Enabled returns true if debug logging is enabled for this rslog.
164+
// Enabled returns true if debug logging is enabled for the associated product
165+
// debug region.
153166
func (l *debugLogger) Enabled() bool {
154167
return Enabled(l.region)
155168
}
156169

170+
// Debugf logs a message when debug logging is enabled for the associated
171+
// product debug region.
157172
func (l *debugLogger) Debugf(message string, args ...interface{}) {
158-
debugMutex.RLock()
159-
defer debugMutex.RUnlock()
160-
161-
if l.enabled {
173+
if l.Enabled() {
162174
l.Logger.Debugf(message, args...)
163175
}
164176
}
165177

178+
// Tracef logs a message when debug logging is enabled for the associated
179+
// product debug region.
166180
func (l *debugLogger) Tracef(message string, args ...interface{}) {
167-
debugMutex.RLock()
168-
defer debugMutex.RUnlock()
169-
170-
if l.enabled {
181+
if l.Enabled() {
171182
l.Logger.Tracef(message, args...)
172183
}
173184
}
174185

175-
// Set fields to be logged
186+
// WithFields returns a new logger having additional fields. The returned
187+
// logger is associated with the same product debug region.
176188
func (l *debugLogger) WithFields(fields Fields) DebugLogger {
177189
newLgr := l.Logger.WithFields(fields)
178190
dbglgr := &debugLogger{
179-
Logger: newLgr,
180-
region: l.region,
181-
enabled: l.enabled,
191+
Logger: newLgr,
192+
region: l.region,
182193
}
183-
registerLoggerCb(l.region, dbglgr.enable)
184194
return dbglgr
185195
}
186196

187-
// WithSubRegion returns a debug logger with further specificity
188-
// via sub_region key:value. E.g "region": "LDAP", "sub_region": "membership scanner"
197+
// WithSubRegion returns a debug logger having an additional "sub_region"
198+
// field. The returned logger is associated with the same product debug
199+
// region.
200+
//
201+
// Equivalent to `debugLogger.WithField("sub_region", subregion)`
189202
func (l *debugLogger) WithSubRegion(subregion string) DebugLogger {
190203
newLgr := l.Logger.WithField("sub_region", subregion)
191204
dbglgr := &debugLogger{
192-
Logger: newLgr,
193-
region: l.region,
194-
enabled: l.enabled,
205+
Logger: newLgr,
206+
region: l.region,
195207
}
196-
registerLoggerCb(l.region, dbglgr.enable)
197208
return dbglgr
198209
}
199-
200-
// Enable or disable this region debug logging instance
201-
func (l *debugLogger) enable(enabled bool) {
202-
l.enabled = enabled
203-
}

0 commit comments

Comments
 (0)