Save and restore only the touched MDC keys in the SLF4J handler#14
Merged
Conversation
emitWithMdc() copied the entire MDC map on every structured event: getCopyOfContextMap() on entry, and setContextMap() on exit (another full copy inside the adapter). The cost scaled with the ambient MDC size - request ids, trace ids, etc. - rather than with the event. A small MdcRestore helper now records the prior value of each key the event writes (two parallel arrays sized to the event) and restores in reverse order, so duplicate keys across the chain land back on the first-seen ambient value without any dedup bookkeeping. slog no longer performs any whole-map copies of its own: O(event attrs) instead of O(MDC size). One documented edge: an ambient value that was explicitly null is restored as absent - the two are indistinguishable through MDC.get(). Add Slf4jMdcRestoreTest: five tests running through the slf4j->log4j2 bridge, asserting what the backend captured during the call and the caller-visible MDC after it. This path previously had no test coverage.
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
emitWithMdc()copied the entire MDC map on every structured event:getCopyOfContextMap()on entry (fullHashMapcopy), andsetContextMap()on exit (another full copy inside the adapter). The cost scaled with the ambient MDC size — request ids, trace ids, tenant, etc. — rather than with the event being logged, on every structured call. The empty-MDC case was cheap, which is exactly why the existing benchmarks never showed it.A small
MdcRestorehelper now records the prior value of each key the event writes (two parallel arrays sized to the event, grown on demand) and restores in reverse order, so duplicate keys across the chain (logger context attr + per-event attr + ambient MDC entry) land back on the first-seen ambient value with no dedup bookkeeping. slog no longer performs any whole-map copies of its own: O(event attrs) instead of O(MDC size).Honest cost framing: on logback, its internal copy-on-write (triggered by any MDC write after a logging event captured the live map) remains — that's logback semantics every MDC writer pays. Everything attributable to slog is gone; on plain-HashMap adapters the win is total.
One documented edge: an ambient value that was explicitly
nullis restored as absent — the two are indistinguishable throughMDC.get().Testing
New
Slf4jMdcRestoreTest— the first coverage this path has had. Five tests run end-to-end through the slf4j→log4j2 bridge, so the during-the-call assertions check what the backend actually captured (event context data) and the after assertions check the caller-visible MDC:durationMsdoes not leak into the caller MDCFull
checkpasses (all test tasks).