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*. +====
