This is an automated email from the ASF dual-hosted git repository.

vy pushed a commit to branch doc/2.x/structured-logging
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit 178d579b4c1f15a52d766f396ccab38a068a64ad
Author: Volkan Yazıcı <[email protected]>
AuthorDate: Fri Jun 14 16:56:59 2024 +0200

    Improve documentation on structured logging
---
 .../java/org/apache/logging/log4j/EventLogger.java |   5 +-
 ...cate_duration.xml => deprecate_EventLogger.xml} |   4 +-
 src/changelog/.2.x.x/deprecate_duration.xml        |   4 +-
 .../deprecate_log4j2_default_status_level.xml      |   2 +-
 src/changelog/.2.x.x/deprecate_log4j_mongodb4.xml  |   4 +-
 src/site/antora/modules/ROOT/pages/manual/api.adoc |   9 +-
 .../modules/ROOT/pages/manual/eventlogging.adoc    | 241 ++-------------------
 .../antora/modules/ROOT/pages/manual/layouts.adoc  |  15 +-
 .../antora/modules/ROOT/pages/manual/messages.adoc | 153 ++++++++-----
 .../ROOT/partials/manual/structured-logging.adoc   |  24 ++
 10 files changed, 178 insertions(+), 283 deletions(-)

diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/EventLogger.java 
b/log4j-api/src/main/java/org/apache/logging/log4j/EventLogger.java
index c2bc874404..9b08fa2d85 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/EventLogger.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/EventLogger.java
@@ -20,8 +20,11 @@ import 
org.apache.logging.log4j.message.StructuredDataMessage;
 import org.apache.logging.log4j.spi.ExtendedLogger;
 
 /**
- *  Logs "Events" that are represented as {@link StructuredDataMessage}.
+ * Convenience to log {@link StructuredDataMessage}s.
+ *
+ * @deprecated {@link Logger} accepts {@link StructuredDataMessage}s, users 
should use to that instead.
  */
+@Deprecated
 public final class EventLogger {
 
     /**
diff --git a/src/changelog/.2.x.x/deprecate_duration.xml 
b/src/changelog/.2.x.x/deprecate_EventLogger.xml
similarity index 77%
copy from src/changelog/.2.x.x/deprecate_duration.xml
copy to src/changelog/.2.x.x/deprecate_EventLogger.xml
index f5eae02e73..6731db5941 100644
--- a/src/changelog/.2.x.x/deprecate_duration.xml
+++ b/src/changelog/.2.x.x/deprecate_EventLogger.xml
@@ -2,6 +2,6 @@
 <entry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
        xmlns="https://logging.apache.org/xml/ns";
        xsi:schemaLocation="https://logging.apache.org/xml/ns 
https://logging.apache.org/xml/ns/log4j-changelog-0.xsd";
-       type="changed">
-  <description format="asciidoc">Deprecate 
`org.apache.logging.log4j.core.appender.rolling.action.Duration` class for 
removal.</description>
+       type="deprecated">
+  <description format="asciidoc">Deprecate 
`org.apache.logging.log4j.EventLogger` for removal</description>
 </entry>
diff --git a/src/changelog/.2.x.x/deprecate_duration.xml 
b/src/changelog/.2.x.x/deprecate_duration.xml
index f5eae02e73..345bd03cdd 100644
--- a/src/changelog/.2.x.x/deprecate_duration.xml
+++ b/src/changelog/.2.x.x/deprecate_duration.xml
@@ -2,6 +2,6 @@
 <entry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
        xmlns="https://logging.apache.org/xml/ns";
        xsi:schemaLocation="https://logging.apache.org/xml/ns 
https://logging.apache.org/xml/ns/log4j-changelog-0.xsd";
-       type="changed">
-  <description format="asciidoc">Deprecate 
`org.apache.logging.log4j.core.appender.rolling.action.Duration` class for 
removal.</description>
+       type="deprecated">
+  <description format="asciidoc">Deprecate 
`org.apache.logging.log4j.core.appender.rolling.action.Duration` class for 
removal</description>
 </entry>
diff --git a/src/changelog/.2.x.x/deprecate_log4j2_default_status_level.xml 
b/src/changelog/.2.x.x/deprecate_log4j2_default_status_level.xml
index fe8e5d3ffb..d97b850520 100644
--- a/src/changelog/.2.x.x/deprecate_log4j2_default_status_level.xml
+++ b/src/changelog/.2.x.x/deprecate_log4j2_default_status_level.xml
@@ -3,5 +3,5 @@
        xmlns="https://logging.apache.org/xml/ns";
        xsi:schemaLocation="https://logging.apache.org/xml/ns 
https://logging.apache.org/xml/ns/log4j-changelog-0.xsd";
        type="changed">
-  <description format="asciidoc">Deprecate `log4j2.defaultStatusLevel` 
property in Log4j Core in favor of `log4j2.statusLoggerLevel`.</description>
+  <description format="asciidoc">Deprecate `log4j2.defaultStatusLevel` 
property in Log4j Core in favor of `log4j2.statusLoggerLevel`</description>
 </entry>
diff --git a/src/changelog/.2.x.x/deprecate_log4j_mongodb4.xml 
b/src/changelog/.2.x.x/deprecate_log4j_mongodb4.xml
index e83cd2e7f1..cb5e081a49 100644
--- a/src/changelog/.2.x.x/deprecate_log4j_mongodb4.xml
+++ b/src/changelog/.2.x.x/deprecate_log4j_mongodb4.xml
@@ -2,6 +2,6 @@
 <entry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
        xmlns="https://logging.apache.org/xml/ns";
        xsi:schemaLocation="https://logging.apache.org/xml/ns 
https://logging.apache.org/xml/ns/log4j-changelog-0.xsd";
-       type="updated">
-  <description format="asciidoc">Deprecate the log4j-mongodb4 module in favor 
of log4j-mongodb.</description>
+       type="deprecated">
+  <description format="asciidoc">Deprecate the `log4j-mongodb4` module in 
favor of `log4j-mongodb`</description>
 </entry>
diff --git a/src/site/antora/modules/ROOT/pages/manual/api.adoc 
b/src/site/antora/modules/ROOT/pages/manual/api.adoc
index 92e7b528b5..50a0c5e0e4 100644
--- a/src/site/antora/modules/ROOT/pages/manual/api.adoc
+++ b/src/site/antora/modules/ROOT/pages/manual/api.adoc
@@ -46,6 +46,7 @@ Did you know that Log4j provides specialized APIs for Kotlin 
and Scala?
 Check out {logging-services-url}/log4j/kotlin[Log4j Kotlin] and 
{logging-services-url}/log4j/scala[Log4j Scala] projects for details.
 ====
 
+[#intro]
 == Introduction
 
 include::partial$manual/api-intro.adoc[leveloffset=+1]
@@ -205,7 +206,13 @@ xref:manual/resource-logger.adoc[Read more on resource 
loggers...]
 [#event-logger]
 === Event logger
 
-link:../javadoc/log4j-api/org/apache/logging/log4j/EventLogger.html[`EventLogger`]
 provides a simple way to log structured events conforming with the 
`STRCUTURED-DATA` format defined in https://tools.ietf.org/html/rfc5424[RFC 
5424 (The Syslog Protocol)].
+link:../javadoc/log4j-api/org/apache/logging/log4j/EventLogger.html[`EventLogger`]
 is a convenience to log 
xref:manual/messages.adoc#StructuredDataMessage[`StructuredDataMessage`]s, 
which format their content in a way compliant with 
https://datatracker.ietf.org/doc/html/rfc5424#section-6[the Syslog message 
format described in RFC 5424].
+
+[WARNING]
+====
+*Event Logger is deprecated for removal!*
+We advise users to switch to plain `Logger` instead.
+====
 
 xref:manual/eventlogging.adoc[Read more on event loggers...]
 
diff --git a/src/site/antora/modules/ROOT/pages/manual/eventlogging.adoc 
b/src/site/antora/modules/ROOT/pages/manual/eventlogging.adoc
index 31dbbc4efc..3d8a41acab 100644
--- a/src/site/antora/modules/ROOT/pages/manual/eventlogging.adoc
+++ b/src/site/antora/modules/ROOT/pages/manual/eventlogging.adoc
@@ -17,236 +17,35 @@
 
 = Event Logger
 
-The `EventLogger` class provides a mechanism for logging significant events 
-in an application using structured data. This approach is beneficial for 
-tracking user actions, monitoring system behavior, and debugging issues.
+link:../javadoc/log4j-api/org/apache/logging/log4j/EventLogger.html[`EventLogger`]
 is a convenience to log 
xref:manual/messages.adoc#StructuredDataMessage[`StructuredDataMessage`]s, 
which format their content in a way compliant with 
https://datatracker.ietf.org/doc/html/rfc5424#section-6[the Syslog message 
format described in RFC 5424].
 
-Theoretically, every `Logger` can be used to perform this kind of action;
-however, the `EventLogger` class provides a shortcut to log events with 
structured data
-since it allows for a static method to log events.
+[WARNING]
+====
+*Event Logger is deprecated for removal!*
+We advise users to switch to plain `Logger` instead.
+Refer to xref:manual/api.adoc[] on how to use `Logger`.
+====
 
-== Advantages of Structured Logging
+Compared to using 
link:../javadoc/log4j-api/org/apache/logging/log4j/Logger.html[a plain 
`Logger`], `EventLogger`
 
-Structured logging means events Log4j records events with detailed and 
structured information.
-That way, logs are easier to read and process. They provide better context and
-are also more consistent than plain text logs.
+* attaches an `EVENT` xref:manual/markers.adoc[marker], and
+* sets the xref:manual/customloglevels.adoc[level] to `OFF`, unless one is 
explicitly provided.
 
-== Integration with Syslog
+That is, following `EventLogger` usages:
 
-Log4j complies with Syslogs RFC5424 standard. 
-This feature allows for easy integration with existing log management and 
monitoring systems.
-
-== Example Configuration
-
-To configure Log4j to output logs in Syslog (RFC5424) format, one needs to use 
the xref:manual/layouts.adoc#RFC5424Layout[`Rfc5424Layout`] layout.
-Developers can use the following configuration to log events to a local Syslog 
server:
-
-[source, xml]
-----
-<Appenders>
-    <Syslog name="Syslog" host="localhost" port="514"> <!--1-->
-        <Rfc5424Layout/> <!--2-->
-    </Syslog>
-</Appenders>
-
-<Loggers>
-    <Logger name="MyApp" level="info" additivity="false">
-        <AppenderRef ref="Syslog"/>
-    </Logger>
-</Loggers>
-----
-<1> The `Syslog` appender sends logs to a local Syslog server.
-<2> The `StructuredDataLayout` layout formats logs in RFC5424 format.
-
-Of course, sending logs to a Syslog server is unnecessary. 
-Developers can use the `StructuredDataLayout` layout with any other appender, 
such as `FileAppender` or `ConsoleAppender`.
-
-As an example, the output could look like this:
-
-[source, text]
-----
-<165>1 2024-05-16T12:34:56.789Z myapp MyApp - ID47 [transfer@12345 
toAccount="123456" fromAccount="654321" amount="1000"] User 654321 has 
transferred 1000 to account 123456
-----
-
-== Using the `EventLogger`
-
-The `EventLogger` class provides a simple way to log structured events.
-It uses the `StructuredDataMessage` class to create structured log messages.
-
-Assume a simple application that performs funds transfers between accounts.
-This application should send a certain amount of funds from one account to 
another and log the event.
-
-The account class is defined as follows, with a unique ID and a balance:
-
-[source, java]
-----
-class Account {
-    private String id;
-    private long balance;
-    // Getters and setters omitted for brevity
-}
-----
-
-The `transfer()` method transfers funds between two accounts and logs the 
event.
-It needs to take two accounts and the amount to transfer as parameters.
-
-Apart from the key-value pairs provided in the map of the 
`StructuredDataMessage,`
-the `StructuredDataMessage` also takes a unique ID, a free-form message, and a 
type as parameters.
-
-The free-form message is a human-readable description of the event. 
-This message is good for operators who need to understand the event quickly, 
-but not so much for automated processing.
-
-[source, java]
-----
-public static String transferFunds(Account toAccount, Account fromAccount, 
long amount) {
-    toAccount.deposit(amount);
-    fromAccount.withdraw(amount);
-
-    // Create a unique ID for the transaction
-    String confirm = UUID.randomUUID().toString();
-
-    String freeFormMessage = "User " + fromAccount.getId() + " has transferred 
" + amount + " to account " + toAccount.getId(); <1>
-
-    // Create the StructuredDataMessage
-    StructuredDataMessage msg = new StructuredDataMessage(confirm, 
freeFormMessage, "transfer"); <2>
-    msg.put("toAccount", toAccount.getId()); <3>
-    msg.put("fromAccount", fromAccount.getId());
-    msg.put("amount", amount);
-
-    // Log the event
-    EventLogger.logEvent(msg); <4>
-
-    return confirm;
-}
-----
-<1> The free-form message is a human-readable description of the event.
-<2> The `StructuredDataMessage` constructor takes an ID, the free-form 
message, and a type.
-<3> Developers can add key-value pairs to the message.
-<4> The `EventLogger` logs the event.
-
-That way, the `transferFunds()` method logs the event with structured data
-by using the `EventLogger`.
-
-== Web Application Example
-
-In a web application, developers can use a servlet filter to populate the 
-`ThreadContext` map with data related to the request.
-
-The following example demonstrates how a `Filter` could investigate the request
-and populate the `ThreadContext` map with data such as the user's IP address,
-the user's login ID, the server's hostname, the product name, the locale, and 
the timezone.
-
-[source, java]
-----
-import org.apache.logging.log4j.ThreadContext;
-import org.apache.commons.lang.time.DateUtils;
-
-import javax.servlet.*;
-import javax.servlet.http.*;
-import java.io.IOException;
-import java.util.TimeZone;
-
-public class RequestFilter implements Filter {
-    private FilterConfig filterConfig;
-    private static String TZ_NAME = "timezoneOffset";
-
-    // Other methods ommitted for brevity
-
-    /**
-     * Sample filter that populates the MDC on every request.
-     */
-    public void doFilter(ServletRequest servletRequest, ServletResponse 
servletResponse, FilterChain filterChain)
-            throws IOException, ServletException {
-        HttpServletRequest request = (HttpServletRequest)servletRequest;
-        
-        ThreadContext.put("ipAddress", request.getRemoteAddr()); <1>
-
-        HttpSession session = request.getSession(false);
-        if (session != null) {
-            // Assuming, an authentication filter has already populated the 
loginId in the session
-            String loginId = (String)session.getAttribute("loginId");
-            if (loginId != null) {
-                ThreadContext.put("loginId", loginId);
-            }
-        }
-
-        ThreadContext.put("hostname", servletRequest.getServerName());
-        ThreadContext.put("productName", 
filterConfig.getInitParameter("ProductName"));
-        ThreadContext.put("locale", 
servletRequest.getLocale().getDisplayName());
-        ThreadContext.put("timezone", TimeZone.getDefault().getDisplayName());
-
-        filterChain.doFilter(servletRequest, servletResponse);
-        ThreadContext.clear();
-    }
-}
+[source,java]
 ----
-<1> The `doFilter()` method populates the `ThreadContext` map with data 
related to the request.
-
-The `Filter` needs to be registered in your `web.xml` file:
-
-[source, xml]
-----
-<filter>
-    <filter-name>RequestFilter</filter-name>
-    <filter-class>com.example.RequestFilter</filter-class>
-    <init-param>
-        <param-name>ProductName</param-name>
-        <param-value>YourProductName</param-value>
-    </init-param>
-</filter>
-<filter-mapping>
-    <filter-name>RequestFilter</filter-name>
-    <url-pattern>/*</url-pattern> <1>
-</filter-mapping>
+EventLogger.logEvent(new StructuredDataMessage(...));
+EventLogger.logEvent(new StructuredDataMessage(...), Level.INFO);
 ----
-<1> The `RequestFilter` is mapped to all requests.
 
-Eventually, a `Servlet` or any other related class, such as a Spring 
Controller, can be used to log events with structured data. 
-The following example uses a `Servlet` to call the `EventLogger` and log a 
user action.
+are equivalent to the following plain `Logger` usages:
 
-[source, java]
+[source,java]
 ----
-import javax.servlet.*;
-import javax.servlet.http.*;
-import java.io.IOException;
-
-public class UserActionServlet extends HttpServlet {
-    
-    protected void doPost(HttpServletRequest request, HttpServletResponse 
response)
-            throws ServletException, IOException {
-        String userId = request.getParameter("userId");
-        String action = request.getParameter("action");
-        String details = request.getParameter("details");
+private static final Marker EVENT_MARKER = MarkerManager.getMarker("EVENT");
+private static final Logger LOGGER = LogManager.getLogger();
 
-        // Perform and log the user action
-        String message = "User " + userId + " performed action: " + action;
-        StructuredDataMessage msg = new 
StructuredDataMessage(UUID.randomUUID().toString(), message, "userAction"); <1>
-        msg.put("userId", userId);
-        msg.put("action", action);
-        msg.put("details", details);
-
-        // Log the event
-        EventLogger.logEvent(msg); 
-
-        // Respond to the client
-        response.getWriter().write("Action logged successfully");
-    }
-}
+LOGGER.log(Level.OFF, EVENT_MARKER, new StructuredDataMessage(...));
+LOGGER.info(EVENT_MARKER, new StructuredDataMessage(...));
 ----
-<1> `userAction` is the name of the current transaction
-
-That way, not only the data provided to the `EventLogger` is used, but also 
all the 
-data populated in the `ThreadContext` map is included in the log message.
-
-== Benefits of Structured Logging
-
-1. **Improved Readability and Context:** 
-   Structured logs include detailed information, making them easier to 
understand and analyze.
-2. **Better for Automated Processing:**
-   Structured logs are easily parsed by existing log management tools.
-3. **Consistency:**
-   Structured logging enforces a consistent format, helping to identify 
patterns in logs.
-4. **Performance Optimization:** 
-   Structured messages are - as all messages - only constructed when 
necessary, keeping overhead low.
-
diff --git a/src/site/antora/modules/ROOT/pages/manual/layouts.adoc 
b/src/site/antora/modules/ROOT/pages/manual/layouts.adoc
index 17a06a8c4f..d9aa0dcc75 100644
--- a/src/site/antora/modules/ROOT/pages/manual/layouts.adoc
+++ b/src/site/antora/modules/ROOT/pages/manual/layouts.adoc
@@ -29,10 +29,20 @@ This page will try to answer following questions:
 
 This section introduces you to some common concerns shared by almost all 
<<collection,predefined layouts>> that you need to be aware of while using them.
 
+[#structured-logging]
+=== Structured logging
+
+Log4j strives to provide top of the class support for *structured logging*.
+To create an end-to-end experience, it provides several 
xref:manual/messages.adoc#collection-structured[structured message types] along 
with layouts supporting structured logging.
+
+include::partial$manual/structured-logging.adoc[]
+
+We recommend xref:manual/json-template-layout.adoc[] for structured logging 
purposes.
+
 [#charset]
 === Character encoding
 
-All <<collection[predefined layouts] produce `String` that eventually get 
converted into a `byte>>` using the 
https://docs.oracle.com/javase/{java-target-version}/docs/api/java/nio/charset/Charset.html[`Charset`]
 configured.
+All <<collection,predefined layouts>> produce `String` that eventually get 
converted into a `byte` using the 
https://docs.oracle.com/javase/{java-target-version}/docs/api/java/nio/charset/Charset.html[`Charset`]
 configured.
 While doing so, unless an explicit encoding configuration is stated, they use 
`UTF-8` by default.
 If you want all your log events to be formatted in a certain character 
encoding that is different from what the employed layout defaults to, make sure 
to configure the layout's character encoding as needed.
 
@@ -834,6 +844,9 @@ This attribute only applies to RFC 5424 Syslog records.
 |The string that should be used to replace newlines within the message text
 |===
 
+RFC 5424 Layout has specialized handling for 
xref:manual/messages.adoc#StructuredDataMessage[`StructuredDataMessage`]s.
+By combining two, users can have complete control on how their message is 
encoded in a way compliant with RFC 5424, while RFC 5424 Layout will make sure 
the rest of the information attached to the log event is properly injected.
+
 [#SerializedLayout]
 === Serialized Layout
 
diff --git a/src/site/antora/modules/ROOT/pages/manual/messages.adoc 
b/src/site/antora/modules/ROOT/pages/manual/messages.adoc
index 023dda25a7..3dbd3f972f 100644
--- a/src/site/antora/modules/ROOT/pages/manual/messages.adoc
+++ b/src/site/antora/modules/ROOT/pages/manual/messages.adoc
@@ -80,9 +80,18 @@ 
include::example$manual/messages/MessagesExample.java[tag=complex-message]
 == Collection
 
 This section explains predefined Log4j `Message` implementations addressing 
certain use cases.
+We will group this collection into following titles:
+
+* <<collection-string,Types intended for plain `String`-based messages>>
+* <<collection-structured,Types intended for structured logging>>
+
+[#collection-string]
+=== String-based types
+
+This section explains message types intended for human-readable `String`-typed 
output.
 
 [#FormattedMessage]
-=== `FormattedMessage`
+==== `FormattedMessage`
 
 
link:../javadoc/log4j-api/org/apache/logging/log4j/message/FormattedMessage.html[`FormattedMessage`]
 is intended as a generic entry point to actual message implementations that 
use pattern-based formatting.
 It works as follows:
@@ -97,7 +106,7 @@ Due to checks involved, `FormattedMessage` has an extra 
performance overhead com
 ====
 
 [#LocalizedMessage]
-=== LocalizedMessage
+==== LocalizedMessage
 
 
link:../javadoc/log4j-api/org/apache/logging/log4j/message/LocalizedMessage.html[`LocalizedMessage`]
 incorporates a `ResourceBundle`, and allows the message pattern parameter to 
be the key to the message pattern in the bundle.
 If no bundle is specified, `LocalizedMessage` will attempt to locate a bundle 
with the name of the `Logger` used to log the event.
@@ -109,32 +118,8 @@ The message retrieved from the bundle will be formatted 
using a <<FormattedMessa
 We advise you to perform log message localization at the representation layer 
of your application, e.g., the client UI.
 ====
 
-[#MapMessage]
-=== `MapMessage`
-
-link:../javadoc/log4j-api/org/apache/logging/log4j/message/MapMessage.html[`MapMessage`]
 is a `Message` implementation that models a Java `Map` with `String`-typed 
keys and values.
-*It is an ideal generic message type for passing structured data.*
-
-`MapMessage` implements 
link:../javadoc/log4j-api/org/apache/logging/log4j/message/MultiformatMessage.html[`MultiformatMessage`]
 to facilitate encoding of its content in multiple formats.
-It supports following formats:
-
-[%header,cols="1m,5"]
-|===
-|Format |Description
-|XML |format as XML
-|JSON |format as JSON
-|JAVA |format as `Map#toString()` (the default)
-|JAVA_UNQUOTED |format as `Map#toString()`, but without quotes
-|===
-
-Some appenders handle ``MapMessage``s differently when there is no layout:
-
-* JMS Appender converts to a JMS `javax.jms.MapMessage`
-* xref:manual/appenders.adoc#JDBCAppender[JDBC Appender] converts to values in 
an `SQL INSERT` statement
-* xref:manual/appenders.adoc#NoSQLAppenderMongoDB[MongoDB NoSQL provider] 
converts to fields in a MongoDB object
-
 [#MessageFormatMessage]
-=== `MessageFormatMessage`
+==== `MessageFormatMessage`
 
 
link:../javadoc/log4j-api/org/apache/logging/log4j/message/MessageFormatMessage.html[`MessageFormatMessage`]
 formats its input using 
https://docs.oracle.com/javase/{java-target-version}/docs/api/java/text/MessageFormat.html[Java's
 `MessageFormat`].
 
@@ -146,43 +131,58 @@ You are recommended to use `ParameterizedMessage` for 
performance-sensitive setu
 ====
 
 [#ObjectMessage]
-=== `ObjectMessage`
+==== `ObjectMessage`
 
 
link:../javadoc/log4j-api/org/apache/logging/log4j/message/ObjectMessage.html[`ObjectMessage`]
 is a wrapper `Message` implementation to log custom domain model instances.
 It formats an input `Object` by calling its `toString()` method.
 If the object is found to be extending from <<StringBuilderFormattable>>, it 
uses `formatTo(StringBuilder)` instead.
 
-[#ParameterizedMessage]
-=== `ParameterizedMessage`
+`ObjectMessage` can be thought as a convenience for <<ParameterizedMessage>> 
such that the following message instances are analogous:
 
-link:../javadoc/log4j-api/org/apache/logging/log4j/message/ParameterizedMessage.html[`ParameterizedMessage`]
 accepts a formatting pattern containing `{}` placeholders and a list of 
arguments.
-It formats the message such that each `{}` placeholder in the pattern is 
replaced with the corresponding argument.
+* `new ObjectMessage(obj)`
+* `new ParameterizedMessage("{}", obj)`
 
-[#ReusableObjectMessage]
-=== `ReusableObjectMessage`
+That is,
 
-link:../javadoc/log4j-api/org/apache/logging/log4j/message/ReusableObjectMessage.html[`ReusableObjectMessage`]
 provides functionally equivalent to <<ObjectMessage[], plus methods to replace 
its content to enable xref:manual/garbagefree.adoc>>.
-When garbage-free logging is enabled, xref:manual/api.adoc#loggers[loggers] 
will use this instead of <<ObjectMessage>>.
+* They will both be formatted in the same way
+* `Message#getParameters()` will return an `Object[]` containing only `obj`
 
-[#ReusableParameterizedMessage]
-=== `ReusableParameterizedMessage`
+Hence, `ObjectMessage` is intended more as a marker interface to indicate the 
single value it encapsulates.
 
-link:../javadoc/log4j-api/org/apache/logging/log4j/message/ReusableParameterizedMessage.html[`ReusableParameterizedMessage`]
 provides functionally equivalent to <<ParameterizedMessage[], plus methods to 
replace its content to enable xref:manual/garbagefree.adoc>>.
-When garbage-free logging is enabled, xref:manual/api.adoc#loggers[loggers] 
will use this instead of <<ParameterizedMessage>>.
+[#ReusableObjectMessage]
+[NOTE]
+====
+link:../javadoc/log4j-api/org/apache/logging/log4j/message/ReusableObjectMessage.html[`ReusableObjectMessage`]
 provides functionally equivalent to <<ObjectMessage>>, plus methods to replace 
its content to enable xref:manual/garbagefree.adoc[].
+When garbage-free logging is enabled, xref:manual/api.adoc#loggers[loggers] 
will use this instead of <<ObjectMessage>>.
+====
 
-[#ReusableSimpleMessage]
-=== `ReusableSimpleMessage`
+[#ParameterizedMessage]
+==== `ParameterizedMessage`
 
-link:../javadoc/log4j-api/org/apache/logging/log4j/message/ReusableSimpleMessage.html[`ReusableSimpleMessage`]
 provides functionally equivalent to <<SimpleMessage[], plus methods to replace 
its content to enable xref:manual/garbagefree.adoc>>.
-When garbage-free logging is enabled, xref:manual/api.adoc#loggers[loggers] 
will use this instead of <<SimpleMessage>>.
+link:../javadoc/log4j-api/org/apache/logging/log4j/message/ParameterizedMessage.html[`ParameterizedMessage`]
 accepts a formatting pattern containing `{}` placeholders and a list of 
arguments.
+It formats the message such that each `{}` placeholder in the pattern is 
replaced with the corresponding argument.
+
+[#ReusableParameterizedMessage]
+[NOTE]
+====
+link:../javadoc/log4j-api/org/apache/logging/log4j/message/ReusableParameterizedMessage.html[`ReusableParameterizedMessage`]
 provides functionally equivalent to <<ParameterizedMessage>>, plus methods to 
replace its content to enable xref:manual/garbagefree.adoc[].
+When garbage-free logging is enabled, xref:manual/api.adoc#loggers[loggers] 
will use this instead of <<ParameterizedMessage>>.
+====
 
 [#SimpleMessage]
-=== `SimpleMessage`
+==== `SimpleMessage`
 
 
link:../javadoc/log4j-api/org/apache/logging/log4j/message/SimpleMessage.html[`SimpleMessage`]
 encapsulates a `String` or `CharSequence` that requires no formatting.
 
+[#ReusableSimpleMessage]
+[NOTE]
+====
+link:../javadoc/log4j-api/org/apache/logging/log4j/message/ReusableSimpleMessage.html[`ReusableSimpleMessage`]
 provides functionally equivalent to <<SimpleMessage>>, plus methods to replace 
its content to enable xref:manual/garbagefree.adoc[].
+When garbage-free logging is enabled, xref:manual/api.adoc#loggers[loggers] 
will use this instead of <<SimpleMessage>>.
+====
+
 [#StringFormattedMessage]
-=== `StringFormattedMessage`
+==== `StringFormattedMessage`
 
 
link:../javadoc/log4j-api/org/apache/logging/log4j/message/StringFormattedMessage.html[`StringFormattedMessage`]
 accepts a 
https://docs.oracle.com/javase/{java-target-version}/docs/api/java/util/Formatter.html#syntax[format
 string] and a list of arguments.
 It formats the message using 
https://docs.oracle.com/javase/{java-target-version}/docs/api/java/lang/String.html#format(java.lang.String,%20java.lang.Object...)[`java.lang.String#format()`].
@@ -194,16 +194,65 @@ the latter is engineered for performance, e.g., it is 
xref:manual/garbagefree.ad
 You are recommended to use `ParameterizedMessage` for performance-sensitive 
setups.
 ====
 
+[#ThreadDumpMessage]
+==== `ThreadDumpMessage`
+
+If a 
link:../javadoc/log4j-api/org/apache/logging/log4j/message/ThreadDumpMessage.html[`ThreadDumpMessage`]
 is logged, Log4j generates stack traces for all threads.
+These stack traces will include any held locks.
+
+[#collection-structured]
+=== Structured types
+
+Log4j strives to provide top of the class support for *structured logging*.
+It complements xref:manual/layouts.adoc#structured-logging[structured layouts] 
with message types allowing users to create structured messages effectively 
resulting in an end-to-end structured logging experience.
+This section will introduce the predefined structured message types.
+
+include::partial$manual/structured-logging.adoc[]
+
+[#MapMessage]
+==== `MapMessage`
+
+link:../javadoc/log4j-api/org/apache/logging/log4j/message/MapMessage.html[`MapMessage`]
 is a `Message` implementation that models a Java `Map` with `String`-typed 
keys and values.
+*It is an ideal generic message type for passing structured data.*
+
+`MapMessage` implements 
link:../javadoc/log4j-api/org/apache/logging/log4j/message/MultiformatMessage.html[`MultiformatMessage`]
 to facilitate encoding of its content in multiple formats.
+It supports following formats:
+
+[%header,cols="1m,5"]
+|===
+|Format |Description
+|XML |format as XML
+|JSON |format as JSON
+|JAVA |format as `Map#toString()` (the default)
+|JAVA_UNQUOTED |format as `Map#toString()`, but without quotes
+|===
+
+Some appenders handle ``MapMessage``s differently when there is no layout:
+
+* JMS Appender converts to a JMS `javax.jms.MapMessage`
+* xref:manual/appenders.adoc#JDBCAppender[JDBC Appender] converts to values in 
an `SQL INSERT` statement
+* xref:manual/appenders.adoc#NoSQLAppenderMongoDB[MongoDB NoSQL provider] 
converts to fields in a MongoDB object
+
+[#MapMessage-JsonTemplateLayout]
+===== JSON Template Layout
+
+xref:manual/json-template-layout.adoc[] has a specialized handling for 
``MapMessage``s to properly encode them as JSON objects.
+
 [#StructuredDataMessage]
-=== `StructuredDataMessage`
+==== `StructuredDataMessage`
 
 
link:../javadoc/log4j-api/org/apache/logging/log4j/message/StructuredDataMessage.html[`StructuredDataMessage`]
 formats its content in a way compliant with 
https://datatracker.ietf.org/doc/html/rfc5424#section-6[the Syslog message 
format described in RFC 5424].
 
-[#ThreadDumpMessage]
-=== `ThreadDumpMessage`
+[#StructuredDataMessage-Rfc5424Layout]
+===== RFC 5424 Layout
 
-If a 
link:../javadoc/log4j-api/org/apache/logging/log4j/message/ThreadDumpMessage.html[`ThreadDumpMessage`]
 is logged, Log4j generates stack traces for all threads.
-These stack traces will include any held locks.
+`StructuredDataMessage` is mostly intended to be used in combination with 
xref:manual/layouts.adoc#RFC5424Layout[RFC 5424 Layout], which has specialized 
handling for ``StructuredDataMessage``s.
+By combining two, users can have complete control on how their message is 
encoded in a way compliant with RFC 5424, while RFC 5424 Layout will make sure 
the rest of the information attached to the log event is properly injected.
+
+[#StructuredDataMessage-JsonTemplateLayout]
+===== JSON Template Layout
+
+Since `StructuredDataMessage` extends from <<MapMessage>>, which 
xref:manual/json-template-layout.adoc[] has a specialized handling for, 
``StructuredDataMessage``s will be properly encoded by JSON Template Layout too.
 
 [#performance]
 == Performance
@@ -217,7 +266,7 @@ In such a scenario, if you also have custom message types, 
consider implementing
 [#extending]
 == Extending
 
-If <<collection[predefined message types] fall short of addressing your needs, 
you can extend from the 
link:../javadoc/log4j-api/org/apache/logging/log4j/message/Message.html,`Message`>>
 interface to either create your own message types or make your domain models 
take control of the message formatting.
+If <<collection,predefined message types>> fall short of addressing your 
needs, you can extend from the 
link:../javadoc/log4j-api/org/apache/logging/log4j/message/Message.html[`Message`]
 interface to either create your own message types or make your domain models 
take control of the message formatting.
 
 .Example custom message class
 [%collapsible]
diff --git 
a/src/site/antora/modules/ROOT/partials/manual/structured-logging.adoc 
b/src/site/antora/modules/ROOT/partials/manual/structured-logging.adoc
new file mode 100644
index 0000000000..8710f4f6ad
--- /dev/null
+++ b/src/site/antora/modules/ROOT/partials/manual/structured-logging.adoc
@@ -0,0 +1,24 @@
+////
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+////
+
+.What is *structured logging*?
+[%collapsible]
+====
+In almost any modern production deployment, logs are no more written to files 
read by engineers while troubleshooting, but forwarded to log ingestion systems 
(Elasticsearch, Google Cloud Logging, etc.) for several observability use cases 
ranging from logging to metrics.
+This necessitates the applications to _structure_ their logs in a 
machine-readable way ready to be delivered to an external system.
+This act of encoding logs following a certain structure is called *structured 
logging*.
+====

Reply via email to