Skip to content

Commit 4a2add1

Browse files
authored
Merge pull request #209 from rstudio/aron-leaky-debug
debug logger: remove logger callbacks
2 parents 7f26097 + ca4e3d8 commit 4a2add1

File tree

5 files changed

+280
-113
lines changed

5 files changed

+280
-113
lines changed

pkg/rslog/NEWS.md

Lines changed: 3 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,12 @@
11
# `rslog` package
22

3-
Unreleased
3+
pkg/rslog/v1.6.1
44
--------------------------------------------------------------------------------
55

6-
<!--
7-
### New
8-
9-
* Uncomment when items are available.
10-
-->
11-
12-
<!--
136
### Fixed
147

15-
* Uncomment when items are available.
16-
-->
17-
18-
<!--
19-
### Breaking
20-
21-
* Uncomment when items are available.
22-
-->
23-
24-
<!--
25-
### Deprecated / Removed
26-
27-
* Uncomment when items are available.
28-
-->
29-
30-
<!--
31-
### New Contributors
32-
33-
* Uncomment when items are available.
34-
-->
8+
* Debug loggers are no longer attached to a global set of callbacks, which
9+
means that those loggers are available for garbage collection.
3510

3611

3712
pkg/rslog/v1.6.0

pkg/rslog/debug.go

Lines changed: 87 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,111 +1,130 @@
11
package rslog
22

3-
// Copyright (C) 2022 by RStudio, PBC.
3+
// Copyright (C) 2025 by Posit Software, PBC.
44

55
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, regionName := range debugRegions {
67+
if name == regionName {
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)