MaxFreedomPollard opened a new pull request, #4420:
URL: https://github.com/apache/logging-log4j2/pull/4420

   ## What breaks
   
   `Rfc5424Layout` merges a `StructuredDataMessage` into an element that 
already uses the same SD-ID: the MDC element, a `LoggerFields` element, or an 
earlier message of a `StructuredDataCollectionMessage`. That merge path throws 
instead of merging:
   
   ```java
   StructuredDataMessage first = new StructuredDataMessage("Transfer", 
"Transfer Complete", "Audit");
   first.put("Amount", "200.00");
   StructuredDataMessage second = new StructuredDataMessage("Transfer", null, 
"Audit");
   second.put("ToAccount", "123456");
   LogEvent event = Log4jLogEvent.newBuilder()
           .setMessage(new StructuredDataCollectionMessage(Arrays.asList(first, 
second)))
           .build();
   Rfc5424Layout.newBuilder().build().toSerializable(event);
   // java.lang.NullPointerException
   //     at 
org.apache.logging.log4j.core.layout.Rfc5424Layout.addStructuredData(Rfc5424Layout.java:446)
   ```
   
   With `"Transfer@32473"` as the ID it throws `UnsupportedOperationException` 
instead. A single `new StructuredDataMessage("mdc", ...)` logged with a 
non-empty thread context also throws the `NullPointerException`, because its 
SD-ID matches the default MDC element.
   
   ## Cause
   
   Two problems in the merge path of 
`log4j-core/src/main/java/org/apache/logging/log4j/core/layout/Rfc5424Layout.java`:
   
   1. `addStructuredData` checks `sdElements.containsKey(sdId)`, where `sdId` 
comes from `getId(id)`, but then fetches the element with 
`sdElements.get(id.toString())`. For an ID without an enterprise number, 
`getId` appends the layout's enterprise number (`Transfer@32473`) and 
`StructuredDataId.toString()` does not (`Transfer`), so the lookup returns 
`null`.
   2. An element created from a `StructuredDataMessage` keeps the map returned 
by `MapMessage.getData()`, which is unmodifiable, so 
`StructuredDataElement.union` fails on `putAll` when a second message with the 
same SD-ID is merged into it.
   
   ## Fix
   
   Fetch the element by `sdId`, and let `StructuredDataElement.union` copy the 
fields into a new `HashMap` before adding the new ones. The copy only happens 
when two elements are merged. The same code is on `main`.
   
   ## Testing
   
   Two tests in `Rfc5424LayoutTest`:
   
   - `testCollectionMergesElementsWithSameId`, parameterized with `Transfer` 
and `Transfer@32473`, expects `[Transfer@32473 Amount="200.00" 
ToAccount="123456"]`.
   - `testMdcElementMergesStructuredDataWithSameId` expects `[mdc@32473 
Amount="200.00" loginId="JohnDoe"]`.
   
   I could not run Maven in my environment, so `./mvnw verify` (including 
Spotless) and the real JUnit run have not been done. Instead I compiled 
`Rfc5424Layout` and `Rfc5424LayoutTest` with `javac` (JDK 17) against the 
`log4j-api`, `log4j-core` and `log4j-core-test` sources. JUnit and AssertJ were 
replaced by small stand-ins, and the `Log4j2Plugins.dat` was generated with 
`PluginProcessor`. I then ran every test method of `Rfc5424LayoutTest` through 
a reflection-based runner. On `2.x` at 8d7d3c5d1c, 35 of 38 invocations pass, 
and the 3 failures are the new ones (the two `NullPointerException`s and the 
`UnsupportedOperationException` above). With the fix, all 38 pass.
   
   ## Checklist
   
   * [x] Base your changes on `2.x` branch if you are targeting Log4j 2; use 
`main` otherwise
   * [ ] `./mvnw verify` succeeds ([the build 
instructions](https://logging.apache.org/log4j/2.x/development.html#building)): 
not run, see Testing
   * [x] Non-trivial changes contain an entry file in the 
`src/changelog/.2.x.x` directory
   * [x] Tests are provided
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to