fix(logging): do not unlink log record factories chained after ours - #4905
Open
UTKARSH698 wants to merge 2 commits into
Open
fix(logging): do not unlink log record factories chained after ours#4905UTKARSH698 wants to merge 2 commits into
UTKARSH698 wants to merge 2 commits into
Conversation
_uninstrument restored _old_factory unconditionally. Python's log record factory is a single global slot that callers chain by closing over the previous value, so any factory installed after LoggingInstrumentor was silently cut out of the chain. Track the factory we installed and only restore while we are still the head of the chain. When something has been chained on top, leave the chain alone and warn: a node cannot be removed from the middle without the cooperation of the factory that wrapped it. Fixes open-telemetry#3808
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.
Fixes #3808
Problem
logging.setLogRecordFactoryis a single global slot. The convention is to chain: read the current factory, close over it, install a wrapper.LoggingInstrumentor._instrumentdoes exactly that._uninstrumentdid not:Restoring
_old_factoryunconditionally assumes we are still the head of the chain. If an application or another library installed a factory after us, that factory is silently unlinked:Reproduced on
main, instrumenting and then chaining an app factory on top:The app's factory is gone, and every enrichment it performed is silently lost. As the issue notes, this also bites via
instrument(), which calls_uninstrument()internally.Change
Track the factory we install as
_our_factory, and only restore_old_factorywhile we are still the head of the chain. If something has been chained on top, leave the chain intact and warn — a node cannot be removed from the middle of the chain without the cooperation of the factory that wrapped it, so the honest options are "leave it" or "corrupt it".This means OTel attributes may persist on records after
uninstrument()in the chained case. That is a deliberate trade: the alternative is dropping someone else's factory. The warning explains it.The unchained case — by far the common one, and the one the existing tests cover — is unchanged: the original factory is fully restored.
Tests
Two tests, both in
TestLoggingInstrumentor:test_uninstrument_keeps_factories_chained_after_ours— installs an app factory on top, uninstruments, and asserts the app factory is still the head and still enriches records. Fails on unpatchedmain(verified by stashing only the source change:1 failed, 1 passed).test_uninstrument_restores_factory_when_nothing_chained— regression guard for the common path; passes before and after.pytest tests/test_logging.pygoes from6 failed, 19 passedto6 failed, 21 passed. The 6 failures are pre-existing on a clean checkout ofmainin my environment (I had to install releasedopentelemetry-api/sdkrather than the unreleased0.66b0.devcore, so there is some version skew locally); they are untouched by this change.ruff checkandruff format --checkclean on both files with the pinnedruff==0.14.1.Credit
The approach here — tracking
_our_factoryand only restoring when still at the head — is the one proposed by @stark256-spec in #4651. That PR was reviewed by @xrmx, who asked for a test case and a changelog entry, and was then closed by stale-bot before the author could follow up. This PR reimplements that fix and supplies both missing pieces.