From 178d579b4c1f15a52d766f396ccab38a068a64ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Fri, 14 Jun 2024 16:56:59 +0200 Subject: [PATCH 1/4] Improve documentation on structured logging --- .../org/apache/logging/log4j/EventLogger.java | 5 +- .../.2.x.x/deprecate_EventLogger.xml | 7 + src/changelog/.2.x.x/deprecate_duration.xml | 4 +- .../deprecate_log4j2_default_status_level.xml | 2 +- .../.2.x.x/deprecate_log4j_mongodb4.xml | 4 +- .../antora/modules/ROOT/pages/manual/api.adoc | 9 +- .../ROOT/pages/manual/eventlogging.adoc | 241 ++---------------- .../modules/ROOT/pages/manual/layouts.adoc | 15 +- .../modules/ROOT/pages/manual/messages.adoc | 153 +++++++---- .../partials/manual/structured-logging.adoc | 24 ++ 10 files changed, 183 insertions(+), 281 deletions(-) create mode 100644 src/changelog/.2.x.x/deprecate_EventLogger.xml create mode 100644 src/site/antora/modules/ROOT/partials/manual/structured-logging.adoc 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 c2bc874404d..9b08fa2d850 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.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_EventLogger.xml b/src/changelog/.2.x.x/deprecate_EventLogger.xml new file mode 100644 index 00000000000..6731db59411 --- /dev/null +++ b/src/changelog/.2.x.x/deprecate_EventLogger.xml @@ -0,0 +1,7 @@ + + + Deprecate `org.apache.logging.log4j.EventLogger` for removal + diff --git a/src/changelog/.2.x.x/deprecate_duration.xml b/src/changelog/.2.x.x/deprecate_duration.xml index f5eae02e73d..345bd03cdd4 100644 --- a/src/changelog/.2.x.x/deprecate_duration.xml +++ b/src/changelog/.2.x.x/deprecate_duration.xml @@ -2,6 +2,6 @@ - Deprecate `org.apache.logging.log4j.core.appender.rolling.action.Duration` class for removal. + type="deprecated"> + Deprecate `org.apache.logging.log4j.core.appender.rolling.action.Duration` class for removal 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 fe8e5d3ffb8..d97b850520e 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"> - Deprecate `log4j2.defaultStatusLevel` property in Log4j Core in favor of `log4j2.statusLoggerLevel`. + Deprecate `log4j2.defaultStatusLevel` property in Log4j Core in favor of `log4j2.statusLoggerLevel` diff --git a/src/changelog/.2.x.x/deprecate_log4j_mongodb4.xml b/src/changelog/.2.x.x/deprecate_log4j_mongodb4.xml index e83cd2e7f14..cb5e081a492 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 @@ - Deprecate the log4j-mongodb4 module in favor of log4j-mongodb. + type="deprecated"> + Deprecate the `log4j-mongodb4` module in favor of `log4j-mongodb` diff --git a/src/site/antora/modules/ROOT/pages/manual/api.adoc b/src/site/antora/modules/ROOT/pages/manual/api.adoc index 92e7b528b52..50a0c5e0e47 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 31dbbc4efcb..3d8a41acabe 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] ----- - - - - - - - - - - - ----- -<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] ----- - - RequestFilter - com.example.RequestFilter - - ProductName - YourProductName - - - - RequestFilter - /* <1> - +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 17a06a8c4f4..d9aa0dcc75d 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 <> 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 <>` using the https://docs.oracle.com/javase/{java-target-version}/docs/api/java/nio/charset/Charset.html[`Charset`] configured. +All <> 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 023dda25a71..3dbd3f972fc 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] +=== 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 <>, it uses `formatTo(StringBuilder)` instead. -[#ParameterizedMessage] -=== `ParameterizedMessage` +`ObjectMessage` can be thought as a convenience for <> 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 <>. -When garbage-free logging is enabled, xref:manual/api.adoc#loggers[loggers] will use this instead of <>. +* 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 <>. -When garbage-free logging is enabled, xref:manual/api.adoc#loggers[loggers] will use this instead of <>. +[#ReusableObjectMessage] +[NOTE] +==== +link:../javadoc/log4j-api/org/apache/logging/log4j/message/ReusableObjectMessage.html[`ReusableObjectMessage`] provides functionally equivalent to <>, 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 <>. +==== -[#ReusableSimpleMessage] -=== `ReusableSimpleMessage` +[#ParameterizedMessage] +==== `ParameterizedMessage` -link:../javadoc/log4j-api/org/apache/logging/log4j/message/ReusableSimpleMessage.html[`ReusableSimpleMessage`] provides functionally equivalent to <>. -When garbage-free logging is enabled, xref:manual/api.adoc#loggers[loggers] will use this instead of <>. +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 <>, 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] -=== `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 <>, 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 <>. +==== + [#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 <>, 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 <> interface to either create your own message types or make your domain models take control of the message formatting. +If <> 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 00000000000..8710f4f6ad9 --- /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*. +==== From 9b576968103f5f25acfd530e09ac5218cb92a4c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Mon, 17 Jun 2024 11:24:04 +0200 Subject: [PATCH 2/4] Add history --- src/site/antora/modules/ROOT/pages/manual/eventlogging.adoc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/site/antora/modules/ROOT/pages/manual/eventlogging.adoc b/src/site/antora/modules/ROOT/pages/manual/eventlogging.adoc index 3d8a41acabe..3d8451b3bc7 100644 --- a/src/site/antora/modules/ROOT/pages/manual/eventlogging.adoc +++ b/src/site/antora/modules/ROOT/pages/manual/eventlogging.adoc @@ -18,6 +18,7 @@ = Event Logger 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]. +Historically, `EventLogger` was added to help users migrate from SLF4J `EventLogger`, which was removed in https://www.slf4j.org/news.html#1.7.26[SLF4J version `1.7.26`]. [WARNING] ==== From e6f2cd98126de18f4db9e6e8b75439dca222f27f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Mon, 17 Jun 2024 11:26:34 +0200 Subject: [PATCH 3/4] Apply review feedback --- src/site/antora/modules/ROOT/pages/manual/layouts.adoc | 6 +++--- src/site/antora/modules/ROOT/pages/manual/messages.adoc | 4 ++++ .../modules/ROOT/partials/manual/structured-logging.adoc | 5 +---- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/site/antora/modules/ROOT/pages/manual/layouts.adoc b/src/site/antora/modules/ROOT/pages/manual/layouts.adoc index d9aa0dcc75d..457c71c7d80 100644 --- a/src/site/antora/modules/ROOT/pages/manual/layouts.adoc +++ b/src/site/antora/modules/ROOT/pages/manual/layouts.adoc @@ -32,11 +32,11 @@ This section introduces you to some common concerns shared by almost all < Date: Mon, 17 Jun 2024 13:10:48 +0200 Subject: [PATCH 4/4] Document `MultiFormatStringBuilderFormattable` --- src/site/antora/modules/ROOT/pages/manual/messages.adoc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/site/antora/modules/ROOT/pages/manual/messages.adoc b/src/site/antora/modules/ROOT/pages/manual/messages.adoc index 0df16e7a6cb..1c7ba84aef0 100644 --- a/src/site/antora/modules/ROOT/pages/manual/messages.adoc +++ b/src/site/antora/modules/ROOT/pages/manual/messages.adoc @@ -292,7 +292,7 @@ The link:../javadoc/log4j-api/org/apache/logging/log4j/message/Message.html[`Mes Layouts leverage this mechanism to encode a message in a particular format. For instance, when xref:manual/json-template-layout.adoc[] figures out that `getFormat()` of a `Message` returns `JSON`, it injects the `Message#getFormattedMessage()` output as is without quoting it. This way a message implementation can communicate its support for a particular encoding. -If you want to support multiple formats, extend from <> instead. +If you want to support multiple formats, extend from <>, and optionally from <>, instead. [#marker-interfaces] === Marker interfaces @@ -311,12 +311,16 @@ This method will be called during event construction to pass the associated `Log link:../javadoc/log4j-api/org/apache/logging/log4j/message/MultiformatMessage.html[`MultiformatMessage`] extends from `Message` to support multiple <>. For example, see {project-github-url}/tree/2.x/log4j-api/src/main/java/org/apache/logging/log4j/message/MapMessage.java[`MapMessage.java`] extending from `MultiformatMessage` to support multiple formats; XML, JSON, etc. +[#MultiFormatStringBuilderFormattable] +==== `MultiFormatStringBuilderFormattable` + +link:../javadoc/log4j-api/org/apache/logging/log4j/util/MultiFormatStringBuilderFormattable.html[`MultiFormatStringBuilderFormattable`] extends <> to support multiple <>. + [#StringBuilderFormattable] ==== `StringBuilderFormattable` Many xref:manual/layouts.adoc[layouts] recycle ``StringBuilder``s to encode log events xref:manual/garbagefree.adoc[without generating garbage], and this effectively results in significant xref:manual/performance.adoc[performance] benefits. link:../javadoc/log4j-api/org/apache/logging/log4j/util/StringBuilderFormattable.html[`StringBuilderFormattable`] is the primary interface facilitating the formatting of objects to a `StringBuilder`. -*You are strongly advised to implement this interface in your custom `Message` types.* [#TimestampMessage] ==== `TimestampMessage`