Skip to content

Conversation

@aronatkins
Copy link
Contributor

@aronatkins aronatkins commented Jan 24, 2025

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.

This change is associated with Connect issue 29616

// values.
var regionNames map[ProductRegion]string
// debugMutex protects access to product debug region/enabled information.
var debugMutex sync.RWMutex
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed the globals to clearly indicate that they are only for debug log handling.

"sync"
)

// ProductRegion is a numerical value assigned to an area of the product.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added docs throughout the file.

// startup.
func RegisterRegions(regions map[ProductRegion]string) {
regionNames = regions
debugMutex.Lock()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Used the mutex for ALL debugRegions and debugEnabled accesses. We no longer assume that some functions are only called at program startup. Consistent use of the mutex is easier to explain that implicit conventions.

regionsEnabled[region] = true
regionName := RegionName(region)
debugEnabled[region] = true
regionName := debugRegions[region]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

InitDebugLogs() directly accesses debugRegions because RegionName() now uses debugMutex; we need InitDebugLogs() to hold the mutex until its work is complete.

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.
//
// Equivalent to `debugLogger.WithField("sub_region", subregion)`
func (l *debugLogger) WithSubRegion(subregion string) DebugLogger {
newLgr := l.Logger.WithField("sub_region", subregion)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't really relevant for this PR but I don't understand why WithSubRegion exists. Why not just call WithFields() like we do in the tests down below?

                gr.WithFields(Fields{
			"region":     "alfa",
			"sub_region": "drinks",
		})

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not want to alter the public API.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The API exists because folks wanted a well-known field name.

@aronatkins aronatkins merged commit 4a2add1 into main Jan 24, 2025
3 checks passed
@aronatkins aronatkins deleted the aron-leaky-debug branch January 25, 2025 00:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants