[Research] Performance Overhead of Tracing Data in Async Loggers: Map-Injection vs Native Fields #4179
ramanathan1504
started this conversation in
Ideas
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
Following discussions on Slack regarding Issue #1976 and PR #4171, PR #4175 with @ppkarwasz and @vy, I wanted to open this thread to gather research on how different observability frameworks currently pass distributed tracing data (
traceId,spanId,traceFlags) to Log4j across asynchronous boundaries.The core question we need to figure out: Do existing Map-based APIs (like
ContextDataProvideror SLF4J MDC) handle async thread handoffs efficiently enough, or does Log4j need a new native fast-path (like aTraceContextProviderSPI with nativeLogEventfields) to achieve zero-allocation tracing?The "Baggage" Reality
Before diving into the data, it's important to call out one key reality upfront: frameworks like OpenTelemetry don't just inject Trace IDs—they also inject "Baggage" (dynamic user-defined tags). Because native fields can't handle dynamic baggage, any complete solution must gracefully handle both a fast-path for the standard W3C IDs, and a map-fallback for Baggage.
Here is the verified state of the ecosystem today:
1. Micrometer Tracing / Spring Boot (The SLF4J MDC Path)
Frameworks like Micrometer (the default in Spring Boot 3) rely heavily on the SLF4J
MDCAdapter, which pushes trace IDs directly into Log4j'sThreadContextmap.ThreadContextmap to safely hand the data over to the background thread. Under high throughput, this generates massive JVM heap garbage and triggers frequent GC pauses.Jonatan Ivanov(Micrometer/Spring Boot maintainer). He was very supportive of a native SPI to bypass the MDC, noting that Spring Boot already implements a similar native interface (SpanContextSupplier) specifically to fetch Trace/Span IDs natively for Prometheus exemplars without map allocations.2. OpenTelemetry & APMs (The
ContextDataProviderPath)To avoid the
ThreadContextdeep-copy issue, modern APM agents (like OpenTelemetry and Elastic APM) bypass the MDC by implementing Log4j'sContextDataProviderSPI.OpenTelemetryContextDataProvider.java, the agent is forced to allocate anew StringMap()(and its backing arrays) for every single log event to supply the data.ContextDataInjectormust safely merge this data. In an Async environment, if the RingBuffer slot's map is frozen, Log4j must allocate a new map to safely complete the merge, resulting in heap allocations andO(log N)binary search overhead on the hot path.Lauri Tulmin). He confirmed that while native fields are great for the core IDs, OTel still needs the map injection anyway to support dynamic Baggage.3. The Benchmark Data (Map-merging vs. Native Fields)
To quantify the overhead of these current approaches, I ran a JMH GC Allocation profile (
-prof gc) simulating the Async RingBuffer handoff.baseline(No tracing)1.210 ops/us1280 B/opnativeTracing(Native Fields SPI)1.193 ops/us1280 B/op(+0 Bytes)threadContextTracing(SLF4J / MDC)1.071 ops/us1552 B/op(+272 Bytes)contextDataProviderTracing(OTel Map)0.668 ops/us2752 B/op(+1472 Bytes)Note: The
contextDataProvidersimulation accounts for both the OTel Map instantiation and the Log4j internalContextDataInjectormerge/unfreeze allocations.Where Does This Leave Us?
The data and maintainer feedback reveal a difficult reality: As long as core tracing metadata is injected into a Map-based structure, we incur heavy allocation and merging overhead during asynchronous logging boundaries (cutting throughput by ~45% and generating +1,472 bytes of garbage per event).
However, as Volkan and the OTel team pointed out, adding native fields to
LogEventdoesn't magically solve everything if agents still have to inject dynamic Baggage via maps anyway.So, what is the best path forward for Log4j?
ContextDataProviderandContextDataInjectorto be 100% garbage-free when merging maps into frozen async events?LogEventto guarantee a zero-allocation fast-path for the IDs, even if dynamic Baggage remains relegated to the map?Looking forward to the community's thoughts!
Beta Was this translation helpful? Give feedback.
All reactions