Skip to content

Conversation

@sedkis
Copy link
Contributor

@sedkis sedkis commented Oct 24, 2025

  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
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.
@github-actions
Copy link
Contributor

🚨 Jira Linter Failed

Commit: 8c53f7a
Failed at: 2025-10-24 17:33:47 UTC

The Jira linter failed to validate your PR. Please check the error details below:

🔍 Click to view error details
failed to validate branch and PR title rules: branch name 'feat/misc-performance-optimizations' must contain a valid Jira ticket ID (e.g., ABC-123)

Next Steps

  • Ensure your branch name contains a valid Jira ticket ID (e.g., ABC-123)
  • Verify your PR title matches the branch's Jira ticket ID
  • Check that the Jira ticket exists and is accessible

This comment will be automatically deleted once the linter passes.

@github-actions
Copy link
Contributor

API Changes

--- prev.txt	2025-10-24 17:34:40.996472121 +0000
+++ current.txt	2025-10-24 17:34:31.237283261 +0000
@@ -8096,6 +8096,7 @@
 	CacheOptions
 	OASDefinition
 	SelfLooping
+	RequestLogger
 )
 # Package: ./dlpython
 
@probelabs
Copy link

probelabs bot commented Oct 24, 2025

🔍 Code Analysis Results

This PR introduces several performance optimizations related to logging within the Tyk gateway, aiming to reduce CPU usage and memory allocations during request processing.

The changes focus on three areas:

  1. Consolidating Log Fields: Chained .WithField() calls are replaced with a single .WithFields() call to reduce overhead.
  2. Conditional Debug Logging: Debug-level log statements are now wrapped in a check (logger.Logger.IsLevelEnabled(logrus.DebugLevel)) to avoid the cost of preparing log data when debug logging is disabled.
  3. Request Logger Caching: A request-scoped logger is now cached in the http.Request context. This avoids repeated logger instantiation and field population in each middleware, significantly reducing allocations for every request that traverses the middleware chain.

Files Changed Analysis

  • ctx/ctx.go: Adds a new context key RequestLogger to support caching the logger.
  • gateway/api.go: Introduces helper functions ctxSetRequestLogger and ctxGetRequestLogger to manage the logger in the request context.
  • gateway/log_helpers.go: Implements the core caching logic in getOrCreateRequestLogger, which retrieves the logger from the context or creates and stores a new one.
  • gateway/middleware.go: The BaseMiddleware.SetRequestLogger is updated to use the new context-based caching mechanism, removing the previous mutex-based implementation. This is the central change that enables logger reuse across middlewares. It also implements conditional debug logging and WithFields consolidation.
  • gateway/middleware_decorators.go, gateway/mw_granular_access.go, gateway/mw_url_rewrite.go, gateway/proxy_muxer.go, gateway/reverse_proxy.go: These files are updated to apply the logging optimizations (conditional debug logging and using WithFields).

The changes consistently apply performance best practices for the logrus library across the gateway's request-handling code.

Architecture & Impact Assessment

What this PR accomplishes

This PR improves the performance of the Tyk gateway by optimizing its logging infrastructure. By reducing unnecessary allocations and CPU cycles spent on logging, especially for high-throughput scenarios, the changes contribute to lower latency and better resource utilization.

Key technical changes introduced

  1. Context-based Logger Caching: The most significant change is the introduction of a request-scoped logger. Previously, each middleware would potentially create and configure its own logger instance. Now, the first middleware creates a logger, attaches request-specific fields (like request ID), and stores it in the request context. Subsequent middlewares reuse this instance.
  2. Logrus Optimizations: The PR applies two standard logrus optimizations:
    • Checking the log level before preparing debug messages avoids wasted work when the log level is info or higher.
    • Using a single WithFields call is more efficient than chaining multiple WithField calls.

Affected system components

The primary component affected is the Gateway's middleware processing pipeline. Since nearly all requests pass through multiple middlewares, and each middleware performs logging, the impact of these optimizations is system-wide for all API traffic.

Visualization

The following diagram illustrates the change in the logger lifecycle for a single request.

graph TD
    subgraph Before
        A[Request In] --> MW1;
        MW1 -- "Creates Logger A" --> MW2;
        MW2 -- "Creates Logger B" --> MW3;
        MW3 -- "Creates Logger C" --> Response;
    end

    subgraph After
        B[Request In] --> MW1_New[MW1];
        MW1_New -- "Creates Logger X & Caches in Context" --> MW2_New[MW2];
        MW2_New -- "Reuses Logger X from Context" --> MW3_New[MW3];
        MW3_New -- "Reuses Logger X from Context" --> Response_New[Response];
    end

    style MW1 fill:#f9f,stroke:#333,stroke-width:2px
    style MW2 fill:#f9f,stroke:#333,stroke-width:2px
    style MW3 fill:#f9f,stroke:#333,stroke-width:2px
    style MW1_New fill:#ccf,stroke:#333,stroke-width:2px
    style MW2_New fill:#ccf,stroke:#333,stroke-width:2px
    style MW3_New fill:#ccf,stroke:#333,stroke-width:2px
Loading

Scope Discovery & Context Expansion

The scope of this change is well-contained within the gateway's request handling logic. The modification to BaseMiddleware.SetRequestLogger ensures that any middleware embedding BaseMiddleware (which is the standard pattern in this codebase) will automatically benefit from the logger caching.

While the PR applies these optimizations in many places, there may be other opportunities for similar improvements. For instance, a quick search reveals other locations that could be converted from chained .WithField calls to a single .WithFields call, such as in gateway/session_manager.go. This PR establishes a strong pattern that can be applied more broadly in the future. The core architectural improvement—caching the logger in the context—is the most impactful and has been implemented effectively.

Metadata
  • Review Effort: 2 / 5
  • Primary Label: enhancement

Powered by Visor from Probelabs

Last updated: 2025-10-24T17:40:05.579Z | Triggered by: opened | Commit: 8c53f7a

💡 TIP: You can chat with Visor using /visor ask <your question>

@probelabs
Copy link

probelabs bot commented Oct 24, 2025

🔍 Code Analysis Results

✅ Security Check Passed

No security issues found – changes LGTM.

✅ Architecture Check Passed

No architecture issues found – changes LGTM.

✅ Performance Check Passed

No performance issues found – changes LGTM.

Quality Issues (1)

Severity Location Issue
🟡 Warning gateway/mw_granular_access.go:72-77
The refactoring from `logger.WithError(err)` to `logger.WithFields(logrus.Fields{"error": err, ...})` alters logging behavior when `err` is `nil`. `WithError(err)` is a no-op for a `nil` error, but `WithFields` adds an `error` field with a `nil` value. This occurs when the log level is 'debug' and no error is present, adding unnecessary `error: null` fields to debug logs.
💡 SuggestionTo maintain the original behavior, either retain `WithError(err)` or conditionally add the 'error' field. For example: ```go fields := logrus.Fields{ "pattern": pattern, "match": match, } if err != nil { fields["error"] = err } logger = logger.WithFields(fields) ```

✅ Dependency Check Passed

No dependency issues found – changes LGTM.

✅ Connectivity Check Passed

No connectivity issues found – changes LGTM.


Powered by Visor from Probelabs

Last updated: 2025-10-24T17:40:06.464Z | Triggered by: opened | Commit: 8c53f7a

💡 TIP: You can chat with Visor using /visor ask <your question>

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