This is an automated email from the ASF dual-hosted git repository.
ramanathan1504 pushed a commit to branch 2.x
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
The following commit(s) were added to refs/heads/2.x by this push:
new 38889a881f Include free-form message when encoding
StructuredDataMessage to XML (#4180)
38889a881f is described below
commit 38889a881f341a2d9a6d6835eb76435673ffc421
Author: Kamil Krzywanski <[email protected]>
AuthorDate: Sat Jul 18 09:44:49 2026 +0200
Include free-form message when encoding StructuredDataMessage to XML (#4180)
* Include free-form message when encoding StructuredDataMessage to XML
StructuredDataMessage.asXml omitted the constructor message field. Encode
it as a distinct <message> element so it is not conflated with a map entry
keyed "message". Fixes #4141.
* apply spotless formatting
* update pull id in changelog
---------
Co-authored-by: Ramanathan <[email protected]>
---
.../log4j/message/StructuredDataMessageTest.java | 40 +++++++++++++++++++---
.../log4j/message/StructuredDataMessage.java | 9 +++++
.../fix-StructuredDataMessage-XML-message.xml | 13 +++++++
3 files changed, 58 insertions(+), 4 deletions(-)
diff --git
a/log4j-api-test/src/test/java/org/apache/logging/log4j/message/StructuredDataMessageTest.java
b/log4j-api-test/src/test/java/org/apache/logging/log4j/message/StructuredDataMessageTest.java
index 3d3f403bef..b8bf55bc1e 100644
---
a/log4j-api-test/src/test/java/org/apache/logging/log4j/message/StructuredDataMessageTest.java
+++
b/log4j-api-test/src/test/java/org/apache/logging/log4j/message/StructuredDataMessageTest.java
@@ -64,6 +64,7 @@ class StructuredDataMessageTest {
final String expected = "<StructuredData>\n"
+ "<type>Alert</type>\n"
+ "<id>MsgId@12345</id>\n"
+ + "<message>Test message {}</message>\n"
+ "<Map>\n"
+ " <Entry key=\"memo\">This is a very long test memo to
prevent regression of LOG4J2-114</Entry>\n"
+ " <Entry key=\"message\">Test message {}</Entry>\n"
@@ -73,12 +74,44 @@ class StructuredDataMessageTest {
assertEquals(expected, result);
}
+ @Test
+ void testMsgXmlIncludesConstructorMessage() {
+ // #4141: constructor message must appear (and be escaped) even when
not put into the map
+ final StructuredDataMessage msg = new StructuredDataMessage("an id",
"a <msg> & more", "a type");
+ final String result = msg.getFormattedMessage(new String[] {"XML"});
+ final String expected = "<StructuredData>\n"
+ + "<type>a type</type>\n"
+ + "<id>an id</id>\n"
+ + "<message>a <msg> & more</message>\n"
+ + "<Map>\n"
+ + "</Map>\n"
+ + "</StructuredData>\n";
+ assertEquals(expected, result);
+ }
+
+ @Test
+ void testMsgXmlDistinguishesConstructorMessageFromMapEntry() {
+ // #4141: free-form message and a map entry keyed "message" are
independent
+ final StructuredDataMessage msg = new StructuredDataMessage("an id",
"a message", "a type");
+ msg.put("message", "foo");
+ final String result = msg.getFormattedMessage(new String[] {"XML"});
+ final String expected = "<StructuredData>\n"
+ + "<type>a type</type>\n"
+ + "<id>an id</id>\n"
+ + "<message>a message</message>\n"
+ + "<Map>\n"
+ + " <Entry key=\"message\">foo</Entry>\n"
+ + "</Map>\n"
+ + "</StructuredData>\n";
+ assertEquals(expected, result);
+ }
+
@Test
void testXmlEncodingOfIdAndType1() {
final String id = "i<&d>" + XmlFixture.TEXT;
final String type = "t>yp<e&" + XmlFixture.TEXT;
- final String actualXml =
- new StructuredDataMessage(id, "discarded message",
type).getFormattedMessage(new String[] {"XML"});
+ // null message: keep this test focused on id/type escaping (and
covers omission of <message>)
+ final String actualXml = new StructuredDataMessage(id, null,
type).getFormattedMessage(new String[] {"XML"});
final String expectedXml = "<StructuredData>\n"
+ "<type>t>yp<e&" + XmlFixture.ENCODED_TEXT
+ "</type>\n"
@@ -100,8 +133,7 @@ class StructuredDataMessageTest {
final String type = "t>yp<e&" + XmlFixture.TEXT;
final StructuredDataId id =
new StructuredDataId(idName, idEnterpriseNumber, idRequired,
idOptional, Integer.MAX_VALUE);
- final String actualXml =
- new StructuredDataMessage(id, "discarded message",
type).getFormattedMessage(new String[] {"XML"});
+ final String actualXml = new StructuredDataMessage(id, null,
type).getFormattedMessage(new String[] {"XML"});
final String expectedXml = "<StructuredData>\n"
+ "<type>t>yp<e&" + XmlFixture.ENCODED_TEXT
+ "</type>\n"
diff --git
a/log4j-api/src/main/java/org/apache/logging/log4j/message/StructuredDataMessage.java
b/log4j-api/src/main/java/org/apache/logging/log4j/message/StructuredDataMessage.java
index 69fa3fb8cb..748c975c5a 100644
---
a/log4j-api/src/main/java/org/apache/logging/log4j/message/StructuredDataMessage.java
+++
b/log4j-api/src/main/java/org/apache/logging/log4j/message/StructuredDataMessage.java
@@ -373,6 +373,15 @@ public class StructuredDataMessage extends
MapMessage<StructuredDataMessage, Str
StringBuilders.escapeXml(sb, start);
sb.append("</id>\n");
+ // Encode message as its own element (distinct from a map entry keyed
"message")
+ if (message != null) {
+ sb.append("<message>");
+ start = sb.length();
+ sb.append(message);
+ StringBuilders.escapeXml(sb, start);
+ sb.append("</message>\n");
+ }
+
// Encode the rest
super.asXml(sb);
diff --git a/src/changelog/.2.x.x/fix-StructuredDataMessage-XML-message.xml
b/src/changelog/.2.x.x/fix-StructuredDataMessage-XML-message.xml
new file mode 100644
index 0000000000..6060f15076
--- /dev/null
+++ b/src/changelog/.2.x.x/fix-StructuredDataMessage-XML-message.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<entry xmlns="https://logging.apache.org/xml/ns"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="
+ https://logging.apache.org/xml/ns
+ https://logging.apache.org/xml/ns/log4j-changelog-0.xsd"
+ type="fixed">
+ <issue id="4141"
link="https://github.com/apache/logging-log4j2/issues/4141"/>
+ <issue id="4180" link="https://github.com/apache/logging-log4j2/pull/4180"/>
+ <description format="asciidoc">
+ Include the free-form `message` field when encoding
`StructuredDataMessage` to XML
+ </description>
+</entry>