Skip to content

Conversation

@sedkis
Copy link
Contributor

@sedkis sedkis commented Oct 24, 2025

User description

  1. Replace chained withFields to use a single WithFields
  2. check for debug log enabled before invoking debug logs
  3. store request logger in the context to minimize amount of instantiation calls.

Description

Related Issue

Motivation and Context

How This Has Been Tested

Screenshots (if appropriate)

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Refactoring or add test (improvements in base code or adds test coverage to functionality)

Checklist

  • I ensured that the documentation is up to date
  • I explained why this PR updates go.mod in detail with reasoning why it's required
  • I would like a code coverage CI quality gate exception and have explained why

PR Type

Enhancement


Description

  • Add context-cached request logger

  • Reduce debug log allocations

  • Use batched WithFields calls

  • Guard debug logs with level checks


Diagram Walkthrough

flowchart LR
  Ctx["Add ctx key: `RequestLogger`"] -- used by --> GW["Gateway logger helpers"]
  GW -- provides --> GetOrCreate["`getOrCreateRequestLogger(r, key)`"]
  GetOrCreate -- caches in --> Ctx
  Middlewares["Middlewares and decorators"] -- use --> GetOrCreate
  DebugChecks["Debug-level guards"] -- wrap --> Logs["Start/Finish debug logs"]
Loading

File Walkthrough

Relevant files
Enhancement
9 files
ctx.go
Introduce `RequestLogger` context key                                       
+1/-0     
api.go
Add getters/setters for request logger in context               
+13/-0   
log_helpers.go
Cache per-request logger via context utility                         
+15/-0   
middleware.go
Guard debug logs; use context logger in BaseMiddleware     
+21/-11 
middleware_decorators.go
Batch log fields and guard debug timings                                 
+11/-3   
mw_granular_access.go
Batch fields for structured logging                                           
+5/-1     
mw_url_rewrite.go
Use WithFields for error context                                                 
+5/-1     
proxy_muxer.go
Consolidate 404 logs with WithFields                                         
+4/-2     
reverse_proxy.go
Add debug-level guards for start/finish logs                         
+15/-5   

1. Replace chained withFields to use a single WithFields
2. check for debug log enabled before invoking debug logs
3. store request logger in the context to minimize amount of instantiation calls.
@buger
Copy link
Member

buger commented Oct 24, 2025

A JIRA Issue ID is missing from your branch name, PR title and PR description! 🦄

Your branch: performance/debug-log-improvements

Your PR title: misc performance optimizations

Your PR description: 1. Replace chained withFields to use a single WithFields 2. check for debug log enabled before invoking debug logs 3. store request logger in the context to minimize amount of instantiation calls.

Description

Related Issue

Motivation and Context

How This Has Been Tested

Screenshots (if appropriate)

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Refactoring or add test (improvements in base code or adds test coverage to functionality)

Checklist

  • I ensured that the documentation is up to date
  • I explained why this PR updates go.mod in detail with reasoning why it's required
  • I would like a code coverage CI quality gate exception and have explained why

If this is your first time contributing to this repository - welcome!


Please refer to jira-lint to get started.

Without the JIRA Issue ID in your branch name you would lose out on automatic updates to JIRA via SCM; some GitHub status checks might fail.

Valid sample branch names:

‣ feature/shiny-new-feature--mojo-10'
‣ 'chore/changelogUpdate_mojo-123'
‣ 'bugfix/fix-some-strange-bug_GAL-2345'

@github-actions
Copy link
Contributor

API Changes

--- prev.txt	2025-10-24 18:50:21.276100781 +0000
+++ current.txt	2025-10-24 18:50:16.932071944 +0000
@@ -7749,6 +7749,7 @@
 	CacheOptions
 	OASDefinition
 	SelfLooping
+	RequestLogger
 )
 # Package: ./dlpython
 

@github-actions
Copy link
Contributor

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Type Assertion Risk

Adding RequestLogger to the context introduces a new type to assert elsewhere; ensure all retrievals handle unexpected types or nil safely and the context key is unique to avoid collisions.

	RequestLogger
)
Debug Guard Pattern

The new debug logging guards check logger.Logger.IsLevelEnabled, which assumes logger and its Logger are non-nil. Validate that logger is always a non-nil entry and Logger is initialized in all code paths.

if logger.Logger.IsLevelEnabled(logrus.DebugLevel) {
	logger.WithFields(logrus.Fields{
		"ts": startTime.UnixNano(),
		"mw": mw.Name(),
	}).Debug("Started")
}
Logger Reuse

Using logger.WithFields for origin.setLogger is good; confirm that the returned entry isn’t stored globally and is scoped per request to prevent field leakage across requests.

origin.setLogger(logger.WithFields(logrus.Fields{
	"mw":   origin.Name(),
	"type": "response",
}))

@github-actions
Copy link
Contributor

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Add nil checks before logging

Guard logger against being nil before dereferencing logger.Logger, as some call
paths may set a nil logger or return nil when context retrieval fails. Add a fast
nil check to avoid a panic at high throughput.

gateway/middleware.go [164-169]

-if logger.Logger.IsLevelEnabled(logrus.DebugLevel) {
+if logger != nil && logger.Logger != nil && logger.Logger.IsLevelEnabled(logrus.DebugLevel) {
 	logger.WithFields(logrus.Fields{
 		"ts": startTime.UnixNano(),
 		"mw": mw.Name(),
 	}).Debug("Started")
 }
Suggestion importance[1-10]: 6

__

Why: Adding nil guards around logger and its underlying Logger can prevent a panic if a nil logger ever propagates; impact is moderate since the PR assumes a valid logger but the check is low-cost and safe.

Low
Avoid nil dereference in decorator

Ensure the decorator does not panic when d.logger() returns nil or has a nil
underlying Logger. Add defensive checks before accessing Logger to keep response
handling robust under edge cases.

gateway/middleware_decorators.go [58-61]

 logger := d.logger()
-if logger.Logger.IsLevelEnabled(logrus.DebugLevel) {
+if logger != nil && logger.Logger != nil && logger.Logger.IsLevelEnabled(logrus.DebugLevel) {
 	logger.WithField("ts", start.UnixNano()).Debug("Started")
 }
Suggestion importance[1-10]: 6

__

Why: Defensive nil checks around d.logger() and logger.Logger reduce risk of panics in edge cases; while the code likely provides a logger, the guard is a reasonable robustness improvement.

Low
Prevent cross-request logger mutation

Avoid storing a pointer in request context that might outlive the request or be
mutated later. Instead, store a shallow copy of the entry with request-scoped fields
to prevent accidental cross-request field leakage and data races under concurrent
use.

gateway/log_helpers.go [72-82]

 func (gw *Gateway) getOrCreateRequestLogger(r *http.Request, key string) *logrus.Entry {
-	// Check if logger already exists in context
 	if logger := ctxGetRequestLogger(r); logger != nil {
 		return logger
 	}
-
-	// Create new logger and cache it in context
-	logger := gw.getLogEntryForRequest(logrus.NewEntry(log), r, key, nil)
-	ctxSetRequestLogger(r, logger)
-	return logger
+	// Create a fresh entry and avoid sharing mutable state across requests
+	base := logrus.NewEntry(log)
+	logger := gw.getLogEntryForRequest(base, r, key, nil)
+	// store a copy to avoid unintended mutations leaking across middlewares
+	entry := logger.WithFields(logrus.Fields{})
+	ctxSetRequestLogger(r, entry)
+	return entry
 }
Suggestion importance[1-10]: 4

__

Why: The code does cache a logger in the request context, and suggesting storing a shallow copy to avoid mutation is a minor safety/readability improvement; however, logrus.Entry fields are typically set per call, and the proposal offers limited concrete benefit here.

Low

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants