perf: fix unconditional logging overhead in plugin framework (2-5x speedup)#2085
Merged
crivetimihai merged 1 commit intomainfrom Jan 14, 2026
Merged
Conversation
518549e to
5205760
Compare
Member
Author
|
@crivetimihai please merge #2065 first. |
- Auto-wrap GlobalContext in PluginContext in invoke_hook_for_plugin() to prevent AttributeError exceptions on every invocation - Change f-string to lazy logger formatting in debug statement This eliminates unnecessary logger.error() calls that were triggered by a type mismatch when GlobalContext was passed directly, resulting in 2-5x performance improvement for plugin execution. Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
5205760 to
1217de2
Compare
crivetimihai
approved these changes
Jan 14, 2026
kcostell06
pushed a commit
to kcostell06/mcp-context-forge
that referenced
this pull request
Feb 24, 2026
- Auto-wrap GlobalContext in PluginContext in invoke_hook_for_plugin() to prevent AttributeError exceptions on every invocation - Change f-string to lazy logger formatting in debug statement This eliminates unnecessary logger.error() calls that were triggered by a type mismatch when GlobalContext was passed directly, resulting in 2-5x performance improvement for plugin execution. Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes a performance regression in the plugin framework where logger.error() was being called on every plugin invocation due to a type mismatch. This caused 30-60% of execution time to be spent on logging, even for successful plugin executions.
Impact: 2-5x performance improvement across all plugins, with minimal plugins seeing up to 4.9x speedup.
Fix #2084
Problem
The plugin performance profiling revealed that
logger.error()was being called 1000 times for 1000 plugin invocations, adding 20-22μs of logging overhead per call. This overhead accounted for:Root Cause
The issue was caused by a type mismatch in
invoke_hook_for_plugin():context: PluginContextGlobalContextinsteadexecute_plugin()tried to accesslocal_context.global_context(line 228), it raisedAttributeErrorexcept Exceptionhandler (line 287-290), triggeringlogger.error()on every invocationBefore (with exception on every call):
Solution
Changes Made
1. Auto-wrap GlobalContext in PluginContext (
manager.py:690-735)Updated
invoke_hook_for_plugin()to accept bothPluginContextandGlobalContext, with automatic wrapping:Benefits:
PluginContextcontinues to workGlobalContextdirectly (common in tests/benchmarks)2. Fixed f-string in logger.debug (
manager.py:361)Changed from eager f-string formatting to lazy logger formatting:
Benefits:
Performance Impact
Benchmark Results
Performance profiling with 1000 iterations per plugin-hook combination:
Average Improvements by Plugin Category
Real-World Impact
Simple request (5 plugins × 2 hooks = 10 hook calls):
Complex request (20 plugins × 4 hooks = 80 hook calls):
Testing
Verification Steps
Full performance profiling (31 plugins, 1000 iterations each):
make -C tests/performance test-plugins - All plugins show 2-5x improvement - No error logs in output (logger.error only on real failures)Profile analysis:
logger.error()in every profilelogger.error()(only actual errors logged)Test Coverage
PluginContextunaffectedGlobalContextauto-wrapping works correctlyTechnical Details
Why This Happened
GlobalContexttoinvoke_hook_for_plugin()PluginContextbut didn't validate the typeexecute_plugin(), accessinglocal_context.global_contextfailed silentlyWhy It's Fixed Now
Current Performance Breakdown
After this fix, typical plugin execution time is spent on:
Migration Guide
For Plugin Authors
No changes required. This fix is transparent to plugin implementations.
For Framework Users
If you're calling
invoke_hook_for_plugin()directly:Before (still works):
After (now also works):
Checklist
Files Changed
mcpgateway/plugins/framework/manager.py:invoke_hook_for_plugin()signature to accept both context types (line 695)Additional Notes
Combined with previous fix (#2065):
exc_inforemoval: 0.032-0.104ms per hook (3-6x faster)Complete comparison analysis to baseline: