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

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

commit 48aa669d04c2a3fff7bcf1bc4a9d154f7ce9fcc8
Author: Volkan Yazıcı <[email protected]>
AuthorDate: Wed May 22 12:10:06 2024 +0200

    Improve `api.adoc` et al.
---
 src/site/antora/modules/ROOT/nav.adoc              |  20 +-
 src/site/antora/modules/ROOT/pages/5min.adoc       | 140 +-------
 .../modules/ROOT/pages/manual/api-separation.adoc  | 233 -------------
 src/site/antora/modules/ROOT/pages/manual/api.adoc | 370 ++++++++++++++-------
 .../modules/ROOT/pages/manual/customloglevels.adoc |   2 +-
 .../modules/ROOT/pages/manual/logbuilder.adoc      |   2 +-
 .../antora/modules/ROOT/pages/manual/usage.adoc    | 227 -------------
 .../api-best-practice-dont-use-string-concat.adoc  |  36 ++
 .../api-best-practice-dont-use-toString.adoc       |  30 ++
 ...i-best-practice-exception-as-last-argument.adoc |  30 ++
 .../manual/api-best-practice-use-supplier.adoc     |  47 +++
 .../modules/ROOT/partials/manual/api-intro.adoc    |  72 ++++
 src/site/resources/.htaccess                       |   2 +
 13 files changed, 492 insertions(+), 719 deletions(-)

diff --git a/src/site/antora/modules/ROOT/nav.adoc 
b/src/site/antora/modules/ROOT/nav.adoc
index 15e7856c7d..6fde30e7cd 100644
--- a/src/site/antora/modules/ROOT/nav.adoc
+++ b/src/site/antora/modules/ROOT/nav.adoc
@@ -31,17 +31,18 @@
 * xref:manual/installation.adoc[]
 * xref:manual/architecture.adoc[]
 * xref:manual/migration.adoc[]
-* xref:manual/api.adoc[]
+* xref:manual/api.adoc[API]
 ** xref:manual/logbuilder.adoc[]
-** xref:manual/flowtracing.adoc[]
 ** xref:manual/markers.adoc[]
-** xref:manual/eventlogging.adoc[]
-** xref:manual/messages.adoc[]
-** xref:manual/thread-context.adoc[]
 ** xref:manual/scoped-context.adoc[]
+** xref:manual/thread-context.adoc[]
+** xref:manual/messages.adoc[]
+** xref:manual/flowtracing.adoc[]
+** xref:manual/eventlogging.adoc[]
 ** xref:manual/resource-logger.adoc[]
 * Configuration
 ** xref:manual/configuration.adoc[Configuration file]
+** xref:manual/systemproperties.adoc[]
 ** xref:manual/appenders.adoc[]
 ** xref:manual/layouts.adoc[]
 *** xref:manual/json-template-layout.adoc[]
@@ -49,21 +50,12 @@
 ** xref:manual/customloglevels.adoc[]
 ** xref:manual/filters.adoc[]
 ** xref:manual/scripts.adoc[]
-** xref:manual/systemproperties.adoc[]
-* xref:manual/usage.adoc[]
 * xref:manual/cloud.adoc[]
-* xref:manual/lookups.adoc[]
-* xref:manual/appenders.adoc[]
-* xref:manual/layouts.adoc[]
-** xref:manual/json-template-layout.adoc[]
-* xref:manual/filters.adoc[]
 * xref:manual/extending.adoc[]
 ** xref:manual/customconfig.adoc[]
 * xref:manual/plugins.adoc[]
 * xref:manual/customconfig.adoc[]
-* xref:manual/customloglevels.adoc[]
 * xref:manual/jmx.adoc[]
-* xref:manual/logsep.adoc[]
 * xref:manual/performance.adoc[]
 ** xref:manual/async.adoc[]
 ** xref:manual/garbagefree.adoc[]
diff --git a/src/site/antora/modules/ROOT/pages/5min.adoc 
b/src/site/antora/modules/ROOT/pages/5min.adoc
index cc5246fb65..ec24c35776 100644
--- a/src/site/antora/modules/ROOT/pages/5min.adoc
+++ b/src/site/antora/modules/ROOT/pages/5min.adoc
@@ -129,144 +129,32 @@ dependencies {
 [#logging]
 == How do I write logs using Log4j?
 
-To write logs, you need a `Logger` instance which you will retrieve from the 
`LogManager`. 
-The `Logger` instance is thread-safe and reusable.
+include::partial$manual/api-intro.adoc[]
 
-Second, you can use the `Logger` instance to write logs by using methods like 
`info()`, `warn()`, `error()`, etc.
-These methods are named after the log levels they represent, a way to 
categorize log events by severity.
-The log message can also contain placeholders written as `{}` that will be 
replaced by the arguments passed to the method.
+[#best-practice]
+=== Best practices
 
-[source,java]
-----
-import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.LogManager;
-
-public class DbTableService {
-
-    private static final Logger LOGGER = LogManager.getLogger(); // <1>
-
-    public void truncateTable(String tableName) throws IOException {
-        LOGGER.warn("truncating table `{}`", tableName); // <2>
-        db.truncate(tableName);
-    }
-
-}
-----
-<1> This is a thread-safe, reusable `Logger` instance.
-<2> The placeholder `{}` in the message will be replaced with the value of 
`tableName`
-
-The generated **log event** will be enriched with the **log level** (i.e., 
`WARN`),
-but also timestamp, class & method name, line number, and several other 
information.
-
-As already mentioned Log levels are used to categorize log events by severity 
and control the verbosity of the logs.  
-Log4j knows various levels, but the most common are `DEBUG`, `INFO`, `WARN`, 
and `ERROR`.
-With them, you can filter out less important logs and focus on the most 
critical ones.
-Previously we used `LOGGER.warn()` to log a warning message, which could mean 
that something is not right, but the application can continue.
-Log levels have a priority, and `WARN` is less severe than `ERROR`.
-
-Exceptions are often also errors. 
-In this case, we might use the `ERROR` log level.
-Make sure to log exceptions that have diagnostics value - we can simply pass 
the exception as the last argument to the log method.
-
-[source,java]
-----
-LOGGER.warn("truncating table `{}`", tableName);
-try {
-    db.truncate(tableName);
-} catch (IOException exception) {
-    LOGGER.error("failed truncating table `{}`", tableName, exception); // <1>
-    throw new IOException("failed truncating table: " + tableName, exception);
-}
-----
-<1> By using `error()` instead of `warn()`, we signal that the operation 
failed.
-
-While there is only one placeholder in the message, we pass two arguments: 
`tableName` and `exception`.
-Log4j will attach the last extra argument of type `Throwable` in a separate 
field to the generated log event.
-
-[#pitfalls]
-=== Common pitfalls
-
-There are several widespread bad practices.
-Let's try to walk through the most common ones.
+There are several widespread bad practices while using Log4j API.
+Below we will walk through the most common ones and see how to fix them.
+For a complete list, refer to xref:manual/api.adoc#best-practice[the Log4j API 
best practices page].
 
-[#pitfal-toString]
+[#best-practice-toString]
 ==== Don't use `toString()`
 
-* [ ] Don't use `Object#toString()` in arguments, it is redundant!
-+
-[source,java]
-----
-/* BAD! */ LOGGER.info("userId: {}", userId.toString());
-----
-
-* [x] Underlying message type and layout will deal with arguments:
-+
-[source,java]
-----
-/* GOOD */ LOGGER.info("userId: {}", userId);
-----
+include::partial$manual/api-best-practice-dont-use-toString.adoc[]
 
-[#pitfall-exception]
+[#best-practice-exception]
 ==== Pass exception as the last extra argument
 
-* [ ] Don't call `Throwable#printStackTrace()`!
-This not only circumvents the logging but can also leak sensitive information!
-+
-[source,java]
-----
-/* BAD! */ exception.printStackTrace();
-----
-
-* [ ] Don't use `Throwable#getMessage()`!
-This prevents the log event from getting enriched with the exception.
-+
-[source,java]
-----
-/* BAD! */ LOGGER.info("failed", exception.getMessage());
-/* BAD! */ LOGGER.info("failed for user ID `{}`: {}", userId, 
exception.getMessage());
-----
-
-* [ ] Don't provide both `Throwable#getMessage()` and `Throwable` itself!
-This bloats the log message with a duplicate exception message.
-+
-[source,java]
-----
-/* BAD! */ LOGGER.info("failed for user ID `{}`: {}", userId, 
exception.getMessage(), exception);
-----
-
-* [x] Pass exception as the last extra argument:
-+
-[source,java]
-----
-/* GOOD */ LOGGER.error("failed", exception);
-/* GOOD */ LOGGER.error("failed for user ID `{}`", userId, exception);
-----
+include::partial$manual/api-best-practice-exception-as-last-argument.adoc[]
 
-[#pitfal-concat]
+[#best-practice-concat]
 ==== Don't use string concatenation
 
-If you are using `String` concatenation while logging, you are doing something 
very wrong and dangerous!
-
-* [ ] Don't use `String` concatenation to format arguments!
-This circumvents the handling of arguments by message type and layout.
-More importantly, **this approach is prone to attacks!**
-Imagine `userId` being provided by the user with the following content:
-`placeholders for non-existing args to trigger failure: {} {} 
\{dangerousLookup}`
-+
-[source,java]
-----
-/* BAD! */ LOGGER.info("failed for user ID: " + userId);
-----
-
-* [x] Use message parameters
-+
-[source,java]
-----
-/* GOOD */ LOGGER.info("failed for user ID `{}`", userId);
-----
+include::partial$manual/api-best-practice-dont-use-string-concat.adoc[]
 
-[#basic-log4j-architecture]
-== Basic Log4j Architecture
+[#architecture]
+== Architecture
 
 In a nutshell, Log4j operates with two main parts: the API and the Core.
 With this structure, Log4j allows you to log events using the API and route 
them through the Core.
diff --git a/src/site/antora/modules/ROOT/pages/manual/api-separation.adoc 
b/src/site/antora/modules/ROOT/pages/manual/api-separation.adoc
deleted file mode 100644
index 51233ef907..0000000000
--- a/src/site/antora/modules/ROOT/pages/manual/api-separation.adoc
+++ /dev/null
@@ -1,233 +0,0 @@
-////
-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.
-////
-= API Separation
-
-When selecting a logging library, some care must be taken in order to ensure 
that multiple different logging libraries are properly accounted for.
-For example, library code that you depend on may use slf4j, while other 
libraries may simply use java.util.logging.
-All of these can be routed to the log4j core in order to be logged.
-
-If however you want to use a different logging implementation (such as 
logback), it is possible to route messages from the Log4j API to logback, 
ensuring that your application is not tied to a specific logging framework.
-
-A typical class using the Log4j2 API looks like the following:
-
-[,java]
-----
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-
-public class Log4j2Test {
-    private static final Logger logger = LogManager.getLogger();
-
-    public Log4j2Test(){
-        logger.info( "Hello World!" );
-    }
-}
-----
-
-In order to use the API portion of Log4j2, we only need to provide a single 
dependency, log4j-api.
-Using Maven, you would add the following to your dependencies:
-
-[,xml]
-----
-<dependency>
-    <groupId>org.apache.logging.log4j</groupId>
-    <artifactId>log4j-api</artifactId>
-    <version>2.17.0</version>
-</dependency>
-----
-
-== Using Log4j2 API and Core
-
-Using the Log4j2 API and the implementation (Core) together means that log 
messages will be routed through the Log4j2 Core.
-The Log4j2 core implementation is responsible for the following (note: this is 
not an exhaustive list):
-
-* Configuration of the system (via an XML file for example)
-* Routing messages to Appenders
-* Opening files and other resources for logging (e.g.
-network sockets)
-
-The xref:manual/configuration.adoc[configuration] page in the manual describes 
the configuration format supported by the Log4j2 core implementation.
-
-To use both the API and the core implementation, you would add the following 
to your dependencies (assuming that you are using Maven):
-
-[,xml]
-----
-<dependency>
-    <groupId>org.apache.logging.log4j</groupId>
-    <artifactId>log4j-api</artifactId>
-    <version>2.17.0</version>
-</dependency>
-<dependency>
-    <groupId>org.apache.logging.log4j</groupId>
-    <artifactId>log4j-core</artifactId>
-    <version>2.17.0</version>
-</dependency>
-----
-
-Note that having two different versions of log4j-api and log4j-core on your 
classpath is not guaranteed to work correctly (e.g., log4j-api version 2.15 and 
  log4j-core version 2.17 are not guaranteed to work correctly together).
-
-== Using Log4j2 API with Logback
-
-Since the Log4j2 API is generic, we can use it to send messages via SLF4J and 
then have Logback do the actual logging of the messages.
-This means that you can write your code tied to the Log4j2 API, but users of 
your code do not need to use the Log4j2 core if they are already using Logback.
-
-To switch to using Logback as your logging backend, you will need to add the 
following to your dependencies (assuming that you are using Maven):
-
-[,xml]
-----
-<dependency>
-    <groupId>org.apache.logging.log4j</groupId>
-    <artifactId>log4j-api</artifactId>
-    <version>2.17.0</version>
-</dependency>
-<dependency>
-    <groupId>org.apache.logging.log4j</groupId>
-    <artifactId>log4j-to-slf4j</artifactId>
-    <version>2.17.0</version>
-</dependency>
-<dependency>
-      <groupId>ch.qos.logback</groupId>
-      <artifactId>logback-classic</artifactId>
-      <version>1.2.10</version>
-</dependency>
-----
-
-== Using Log4j2 as an SLF4J Implementation
-
-If you don't want to depend on the Log4j2 API and instead want to use SLF4J, 
that is possible as well.
-Assuming that our code looks like the following:
-
-[,java]
-----
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class Log4j2Test {
-
-    private static final Logger logger = 
LoggerFactory.getLogger(Log4j2Test.class);
-
-    public Log4j2Test(){
-        logger.info( "Hello World!" );
-    }
-}
-----
-
-We can then route the messages to Log4j2 using the log4j-slf4j-impl like the 
following:
-
-[,xml]
-----
-<dependency>
-    <groupId>org.slf4j</groupId>
-    <artifactId>slf4j-api</artifactId>
-    <version>1.7.32</version>
-</dependency>
-<dependency>
-      <groupId>org.apache.logging.log4j</groupId>
-      <artifactId>log4j-slf4j-impl</artifactId>
-      <version>2.17.0</version>
-</dependency>
-<dependency>
-    <groupId>org.apache.logging.log4j</groupId>
-    <artifactId>log4j-core</artifactId>
-    <version>2.17.0</version>
-</dependency>
-----
-
-Note that if we were using SLF4J 1.8 instead of 1.7, that requires us to use 
log4j-slf4j18-impl instead of log4j-slf4j-impl.
-
-== Using Log4j2 with JUL
-
-It is also possible to route messages that are logged using java.util.logging 
to Log4j2.
-Assuming that the code looks like the following:
-
-[,java]
-----
-import java.util.logging.Logger;
-
-public class Log4j2Test {
-
-    private static final Logger logger = 
Logger.getLogger(Log4j2Test.class.getName());
-
-    public Log4j2Test() {
-        logger.info("Hello World!");
-    }
-}
-----
-
-We can then also route these messages to the Log4j2 core by adding in the JUL 
bridge, and setting 
`-Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager` on the 
JVM (see the documentation on xref:../log4j-jul.adoc[the JUL adapter] for more 
information as to how this works).
-
-In order to route these messages to Log4j2, your dependencies would look like 
the following:
-
-[,xml]
-----
-<dependency>
-    <groupId>org.apache.logging.log4j</groupId>
-    <artifactId>log4j-jul</artifactId>
-    <version>2.17.0</version>
-</dependency>
-<dependency>
-    <groupId>org.apache.logging.log4j</groupId>
-    <artifactId>log4j-core</artifactId>
-    <version>2.17.0</version>
-</dependency>
-----
-
-== Using Log4j2 as a backend for Log4j1
-
-Some software may still depend on Log4j1, and in some cases it may be 
infeasible to modify this software to migrate it to Log4j2.
-
-However, it may be possible to start using Log4j2 without modifying the 
application.
-
-Assuming that our code looks like the following:
-
-[,java]
-----
-import org.apache.log4j.Logger;
-
-public class Log4j2Test {
-
-    private static final Logger logger = Logger.getLogger(Log4j2Test.class);
-
-    public Log4j2Test(){
-        logger.info( "Hello World!" );
-    }
-}
-----
-
-we can then quickly and easily configure these messages to use Log4j2 as the 
logging implementation by depending on the `log4j-1.2-api` bridge, like so:
-
-[,xml]
-----
-<dependency>
-    <groupId>org.apache.logging.log4j</groupId>
-    <artifactId>log4j-1.2-api</artifactId>
-    <version>2.17.0</version>
-</dependency>
-<dependency>
-    <groupId>org.apache.logging.log4j</groupId>
-    <artifactId>log4j-core</artifactId>
-    <version>2.17.0</version>
-</dependency>
-----
-
-There are some limitations to this, but it is expected to work for the 
majority of common cases.
-See the xref:manual/migration.adoc[manual page on migration] for more 
information on this feature.
-
-== Conclusion
-
-With the API separation that Log4j2 provides, it is possible to use multiple 
logging APIs and implementations in the same project.
-This allows for greater flexibility, ensuring that you are not tied to a 
single API or implementation.
diff --git a/src/site/antora/modules/ROOT/pages/manual/api.adoc 
b/src/site/antora/modules/ROOT/pages/manual/api.adoc
index 7c5b8d0154..ce3360844f 100644
--- a/src/site/antora/modules/ROOT/pages/manual/api.adoc
+++ b/src/site/antora/modules/ROOT/pages/manual/api.adoc
@@ -14,187 +14,323 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 ////
+
+:jboss-logging-link: https://github.com/jboss-logging/jboss-logging[JBoss 
Logging]
+:jcl-link: https://commons.apache.org/proper/commons-logging/[JCL (Apache 
Commons Logging)]
+:jpl-link: https://openjdk.org/jeps/264[JPL (Java Platform Logging)]
+:jul-link: 
https://docs.oracle.com/en/java/javase/{java-target-version}/core/java-logging-overview.html[JUL
 (Java Logging)]
+:logback-link: https://logback.qos.ch/[Logback]
+:slf4j-link: https://www.slf4j.org/[SLF4J]
+
 = Log4j API
 
-== Overview
+Log4j is essentially composed of a logging API called *Log4j API*, and its 
reference implementation called *Log4j Core*.
 
-The Log4j 2 API provides the interface that applications should code to
-and provides the adapter components required for implementers to create
-a logging implementation. Although Log4j 2 is broken up between an API
-and an implementation, the primary purpose of doing so was not to allow
-multiple implementations, although that is certainly possible, but to
-clearly define what classes and methods are safe to use in "normal"
-application code.
+.What is a logging API and a logging implementation?
+[%collapsible]
+====
+Logging APIs::
+A logging API is an interface your code or your dependencies directly logs 
against.
+It is implementation agnostic.
+Log4j API, {slf4j-link}, {jul-link}, {jcl-link}, {jpl-link} and 
{jboss-logging-link} are major logging APIs.
 
-=== Hello World!
+Logging implementation::
+A logging implementation is only required at runtime and can be changed 
without the need to recompile your software.
+Log4j Core, {jul-link}, {logback-link} are the most well-known logging 
implementations.
+====
 
-No introduction would be complete without the customary Hello, World
-example. Here is ours. First, a Logger with the name "HelloWorld" is
-obtained from the
-link:../javadoc/log4j-api/org/apache/logging/log4j/LogManager.html[`LogManager`].
-Next, the logger is used to write the "Hello, World!" message, however
-the message will be written only if the Logger is configured to allow
-informational messages.
+[TIP]
+====
+Are you looking for a crash course on how to use Log4j in your application or 
library?
+See xref:5min.adoc[].
+You can also check out xref:manual/installation.adoc[] for the complete 
installation instructions.
+====
 
-[source,java]
-----
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
+Log4j API provides
 
-public class HelloWorld {
-    private static final Logger logger = LogManager.getLogger("HelloWorld");
-    public static void main(String[] args) {
-        logger.info("Hello, World!");
-    }
-}
-----
+* A logging API that libraries and applications can code to
+* Adapter components to create a logging implementation
 
-The output from the call to `logger.info()` will vary significantly
-depending on the configuration used. See the
-xref:manual/configuration.adoc[Configuration] section for more details.
+This page tries to cover the most prominent Log4j API features that libraries 
and applications can code to.
 
-=== Substituting Parameters
+== Introduction
 
-Frequently the purpose of logging is to provide information about what
-is happening in the system, which requires including information about
-the objects being manipulated. In Log4j 1.x this could be accomplished
-by doing:
+include::partial$manual/api-intro.adoc[leveloffset=+1]
 
-[source,java]
-----
-if (logger.isDebugEnabled()) {
-    logger.debug("Logging in user " + user.getName() + " with birthday " + 
user.getBirthdayCalendar());
-}
-----
+[#best-practice]
+== Best practices
+
+There are several widespread bad practices while using Log4j API.
+Let's try to walk through the most common ones and see how to fix them.
+
+[#best-practice-toString]
+=== Don't use `toString()`
+
+include::partial$manual/api-best-practice-dont-use-toString.adoc[]
+
+[#best-practice-exception]
+=== Pass exception as the last extra argument
+
+include::partial$manual/api-best-practice-exception-as-last-argument.adoc[]
+
+[#best-practice-concat]
+=== Don't use string concatenation
+
+include::partial$manual/api-best-practice-dont-use-string-concat.adoc[]
+
+[#best-practice-supplier]
+=== Use ``Supplier``s to pass computationally expensive arguments
+
+include::partial$manual/api-best-practice-use-supplier.adoc[]
+
+[#loggers]
+== Loggers
 
-Doing this repeatedly has the effect of making the code feel like it is
-more about logging than the actual task at hand. In addition, it results
-in the logging level being checked twice; once on the call to
-isDebugEnabled and once on the debug method. A better alternative would
-be:
+link:../javadoc/log4j-api/org/apache/logging/log4j/Logger.html[`Logger`]s 
obtained using 
link:../javadoc/log4j-api/org/apache/logging/log4j/LogManager.html[`LogManager`]
 is the primary entry point for logging.
+In this section we will introduce you to further details about ``Logger``s.
+
+[#logger-names]
+=== Logger names
+
+Most logging implementations use a hierarchical scheme for matching logger 
names with logging configuration.
+In this scheme, the logger name hierarchy is represented by `.` (dot) 
characters in the logger name, in a fashion very similar to the hierarchy used 
for Java package names.
+For example, `org.apache.logging.appender` and `org.apache.logging.filter` 
both have `org.apache.logging` as their parent.
+
+In most cases, applications name their loggers by passing the current class's 
name to `LogManager.getLogger(...)`.
+Because this usage is so common, Log4j provides that as the default when the 
logger name parameter is either omitted or is null.
+For example, all `Logger`-typed variables below will have a name of 
`com.mycompany.LoggerNameTest`:
 
 [source,java]
 ----
-logger.debug("Logging in user {} with birthday {}", user.getName(), 
user.getBirthdayCalendar());
+package com.mycompany;
+
+public class LoggerNameTest {
+
+    Logger logger1 = LogManager.getLogger(LoggerNameTest.class);
+
+    Logger logger2 = LogManager.getLogger(LoggerNameTest.class.getName());
+
+    Logger logger3 = LogManager.getLogger();
+
+}
 ----
 
-With the code above the logging level will only be checked once and the
-String construction will only occur when debug logging is enabled.
+**We suggest you to use `LogManager.getLogger()` without any arguments** since 
it delivers the same functionality with less characters and is not prone to 
copy-paste errors.
 
-=== Formatting Parameters
+[#formatter-logger]
+=== Formatter logger
 
-Formatter Loggers leave formatting up to you if `toString()` is not what
-you want. To facilitate formatting, you can use the same format strings
-as Java's
-http://docs.oracle.com/javase/6/docs/api/java/util/Formatter.html#syntax[`Formatter`].
-For example:
+The `Logger` instance returned by default replaces the occurrences of `{}` 
placeholders with the `toString()` output of the associated parameter.
+If you need more control over how the parameters are formatted, you can also 
use the 
http://docs.oracle.com/javase/6/docs/api/java/util/Formatter.html#syntax[`java.util.Formatter`]
 format strings by obtaining your `Logger` using 
link:../javadoc/log4j-api/org/apache/logging/log4j/LogManager.html#getFormatterLogger(java.lang.Class)[`LogManager#getFormatterLogger()`]:
 
 [source,java]
 ----
-public static Logger logger = LogManager.getFormatterLogger("Foo");
-
+Logger logger = LogManager.getFormatterLogger();
 logger.debug("Logging in user %s with birthday %s", user.getName(), 
user.getBirthdayCalendar());
 logger.debug("Logging in user %1$s with birthday %2$tm %2$te,%2$tY", 
user.getName(), user.getBirthdayCalendar());
 logger.debug("Integer.MAX_VALUE = %,d", Integer.MAX_VALUE);
 logger.debug("Long.MAX_VALUE = %,d", Long.MAX_VALUE);
 ----
 
-To use a formatter Logger, you must call one of the `LogManager`
-link:../javadoc/log4j-api/org/apache/logging/log4j/LogManager.html#getFormatterLogger(java.lang.Class)[`getFormatterLogger`]
-methods. The output for this example shows that `Calendar::toString` is
-verbose compared to custom formatting:
+Loggers returned by `getFormatterLogger()` are referred as *formatter loggers*.
+
+[#printf]
+==== `printf()` method
+
+Formatter loggers give fine-grained control over the output format, but have 
the drawback that the correct type must be specified.
+For example, passing anything other than a decimal integer for a `%d` format 
parameter gives an exception.
+If your main usage is to use `{}`-style parameters, but occasionally you need 
fine-grained control over the output format, you can use the `Logger#printf()` 
method:
 
 [source,java]
 ----
-2012-12-12 11:56:19,633 [main] DEBUG: User John Smith with birthday 
java.util.GregorianCalendar[time=?,areFieldsSet=false,areAllFieldsSet=false,lenient=true,zone=sun.util.calendar.ZoneInfo[id="America/New_York",offset=-18000000,dstSavings=3600000,useDaylight=true,transitions=235,lastRule=java.util.SimpleTimeZone[id=America/New_York,offset=-18000000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMod
 [...]
-2012-12-12 11:56:19,643 [main] DEBUG: User John Smith with birthday 05 23, 1995
-2012-12-12 11:56:19,643 [main] DEBUG: Integer.MAX_VALUE = 2,147,483,647
-2012-12-12 11:56:19,643 [main] DEBUG: Long.MAX_VALUE = 
9,223,372,036,854,775,807
+Logger logger = LogManager.getLogger("Foo");
+logger.debug("Opening connection to {}...", someDataSource);
+logger.printf(Level.INFO, "Hello, %s!", userName);
 ----
 
-=== Mixing Loggers with Formatter Loggers
+[#formatter-perf]
+==== Formatter performance
+
+Keep in mind that, contrary to the formatter logger, the default Log4j logger 
(i.e., `{}`-style parameters) is heavily optimized for several use cases and 
can operate xref:manual/garbagefree.adoc[garbage-free] when configured 
correctly.
+You might reconsider your formatter logger usages for latency sensitive 
applications.
+
+[#resource-logger]
+=== Resource logger
+
+Resource loggers, introduced in Log4j API `2.24.0`, is a special kind of 
`Logger` that:
+
+* is a regular class member variable that will be garbage collected along with 
the class instance
+* enriches generated log events with data associated with the resource (i.e., 
the class instance)
+
+xref:manual/resource-logger.adoc[Read more on resource loggers...]
+
+[#event-logger]
+=== Event logger
+
+link:../javadoc/log4j-api/org/apache/logging/log4j/LogManager.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)].
 
-Formatter loggers give fine-grained control over the output format, but
-have the drawback that the correct type must be specified (for example,
-passing anything other than a decimal integer for a %d format parameter
-gives an exception).
+xref:manual/eventlogging.adoc[Read more on event loggers...]
 
-If your main usage is to use \{}-style parameters, but occasionally you
-need fine-grained control over the output format, you can use the
-`printf` method:
+[#feature-fluent-api]
+== Fluent API
+
+The fluent API allows you to log using a fluent interface:
 
 [source,java]
 ----
-public static Logger logger = LogManager.getLogger("Foo");
-
-logger.debug("Opening connection to {}...", someDataSource);
-logger.printf(Level.INFO, "Logging in user %1$s with birthday %2$tm 
%2$te,%2$tY", user.getName(), user.getBirthdayCalendar());
+logger.atInfo()
+      .withMarker(marker)
+      .withLocation()
+      .withThrowable(exception)
+      .log("Login for user `{}` failed", userId);
 ----
 
-[#LambdaSupport]
-=== Java 8 lambda support for lazy logging
+xref:manual/logbuilder.adoc[Read more on the Fluent API...]
+
+[#fish-tagging]
+== Fish tagging
+
+Just as a fish can be tagged and have its movement tracked (aka. _fish 
tagging_), stamping log events with a common tag or set of data
+elements allows the complete flow of a transaction or a request to be tracked.
+You can use them for several purposes, such as:
+
+* Provide extra information while serializing the log event
+* Allow filtering of information so that it does not overwhelm the system or 
the individuals who need to make use of it
+
+Log4j provides fish tagging in several flavors:
+
+[#levels]
+=== Levels
+
+Log levels are used to categorize log events by severity.
+Log4j contains predefined levels, of which the most common are `DEBUG`, 
`INFO`, `WARN`, and `ERROR`.
+Log4j also allows you to introduce your own custom levels too.
+
+xref:manual/customloglevels.adoc[Read more on custom levels...]
 
-In release 2.4, the `Logger` interface added support for lambda
-expressions. This allows client code to lazily log messages without
-explicitly checking if the requested log level is enabled. For example,
-previously you would write:
+[#markers]
+=== Markers
+
+Markers are programmatic labels developers can associate to log statements:
 
 [source,java]
 ----
-// pre-Java 8 style optimization: explicitly check the log level
-// to make sure the expensiveOperation() method is only called if necessary
-if (logger.isTraceEnabled()) {
-    logger.trace("Some long-running operation returned {}", 
expensiveOperation());
+public class MyApp {
+
+    private static final Logger LOGGER = LogManager.getLogger();
+
+    private static final Marker ACCOUNT_MARKER = 
MarkerManager.getMarker("ACCOUNT");
+
+    public void removeUser(String userId) {
+        logger.debug(ACCOUNT_MARKER, "Removing user with ID `{}`", userId);
+        // ...
+    }
+
 }
 ----
 
-With Java 8 you can achieve the same effect with a lambda expression.
-You no longer need to explicitly check the log level:
+xref:manual/markers.adoc[Read more on markers...]
+
+[#scoped-context]
+=== Scoped Context
+
+Just like a 
https://docs.oracle.com/en/java/javase/22/docs/api/java.base/java/lang/ScopedValue.html[Java's
 `ScopedValue`], the visibility of tags are associated with the block they were 
introduced:
 
 [source,java]
 ----
-// Java-8 style optimization: no need to explicitly check the log level:
-// the lambda expression is not evaluated if the TRACE level is not enabled
-logger.trace("Some long-running operation returned {}", () -> 
expensiveOperation());
+
+private class Worker implements Runnable {
+
+    private static final Logger LOGGER = LogManager.getLogger();
+
+    public void authUser(Request request, Session session) {
+         // ... // <3>
+        ScopedContext
+                .where("ipAddress", request.getRemoteAddr()) // <1>
+                .where("hostName", request.getServerName()) // <1>
+                .where("loginId", session.getAttribute("loginId")) // <1>
+                .run(() -> { // <2>
+                    LOGGER.debug("Authenticating user");
+                    // ...
+                });
+         // ... // <3>
+    }
+
+}
 ----
+<1> Associating properties such that they will only be visible to Log4j 
**within the scope of the `run()` method**.
+These properties can later on be used to, for instance, filter the log event, 
provide extra information in the layout, etc.
+<2> The block determining the visibility scope of the provided properties.
+<3> Outside the scope of the `run()` method provided properties will not be 
visible.
+
+xref:manual/scoped-context.adoc[Read more on Scoped Context...]
 
-=== Logger Names
+[#thread-context]
+=== Thread Context
 
-Most logging implementations use a hierarchical scheme for matching
-logger names with logging configuration. In this scheme, the logger name
-hierarchy is represented by `'.'` characters in the logger name, in a
-fashion very similar to the hierarchy used for Java package names. For
-example, `org.apache.logging.appender` and `org.apache.logging.filter`
-both have `org.apache.logging` as their parent. In most cases,
-applications name their loggers by passing the current class's name to
-`LogManager.getLogger(...)`. Because this usage is so common, Log4j 2
-provides that as the default when the logger name parameter is either
-omitted or is null. For example, in all examples below the Logger will
-have a name of `"org.apache.test.MyTest"`.
+Just like 
https://docs.oracle.com/javase/8/docs/api/java/lang/ThreadLocal.html[Java's 
`ThreadLocal`], the visibility of tags are associated with the thread they were 
introduced:
 
 [source,java]
 ----
-package org.apache.test;
+ThreadContext.put("ipAddress", request.getRemoteAddr()); // <1>
+ThreadContext.put("hostName", request.getServerName()); // <1>
+ThreadContext.put("loginId", session.getAttribute("loginId")); // <1>
 
-public class MyTest {
-    private static final Logger logger = LogManager.getLogger(MyTest.class);
-}
+LOGGER.debug("Performing work");
 ----
+<1> Associating properties **with the thread**.
+These properties can later on be used to, for instance, filter the log event, 
provide extra information in the layout, etc.
+
+[CAUTION]
+====
+**Thread Context is mostly superseded by Scoped Context**, which, unlike 
Thread Context,
+
+* is safe to use in servlet applications
+* can store any `Object`-typed value
+====
+
+xref:manual/thread-context.adoc[Read more on Thread Context]...
+
+[#messages]
+== Messages
+
+Whereas almost every other logging API and implementation accepts only 
`String`-typed input as message, Log4j generalizes this concept with a 
`Message` contract.
+Customizability of the message type enables users to **have complete control 
over how a message is encoded** by Log4j.
+This liberal approach allows applications to choose the message type best 
fitting to their logging needs; they can log plain ``String``s, or custom 
`PurchaseOrder` objects.
+
+Log4j provides several predefined message types to cater for common use cases:
 
+* Simple `String`-typed messages:
++
 [source,java]
 ----
-package org.apache.test;
-
-public class MyTest {
-    private static final Logger logger = 
LogManager.getLogger(MyTest.class.getName());
-}
+LOGGER.info("foo");
+LOGGER.info(new SimpleMessage("foo"));
 ----
 
+* `String`-typed parameterized messages:
++
 [source,java]
 ----
-package org.apache.test;
+LOGGER.info("foo {} {}", "bar", "baz");
+LOGGER.info(new ParameterizedMessage("foo {} {}", new Object[]{"bar", "baz"}));
+----
 
-public class MyTest {
-    private static final Logger logger = LogManager.getLogger();
-}
+* `Map`-typed messages:
++
+[source,java]
 ----
+LOGGER.info(new StringMapMessage()
+    .with("key1", "val1")
+    .with("key2", "val2"));
+----
+
+xref:manual/messages.adoc[Read more on messages...]
+
+[#flow-tracing]
+== Flow tracing
+
+The `Logger` class provides `traceEntry()`, `traceExit()`, `catching()`, 
`throwing()` methods that are quite useful for following the execution path of 
applications.
+These methods generate log events that can be filtered separately from other 
debug logging.
+
+xref:manual/flowtracing.adoc[Read more on flow tracing...]
diff --git a/src/site/antora/modules/ROOT/pages/manual/customloglevels.adoc 
b/src/site/antora/modules/ROOT/pages/manual/customloglevels.adoc
index 3110c71705..8f15912e37 100644
--- a/src/site/antora/modules/ROOT/pages/manual/customloglevels.adoc
+++ b/src/site/antora/modules/ROOT/pages/manual/customloglevels.adoc
@@ -14,7 +14,7 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 ////
-= Custom Log Levels
+= Levels
 
 [[top]]
 
diff --git a/src/site/antora/modules/ROOT/pages/manual/logbuilder.adoc 
b/src/site/antora/modules/ROOT/pages/manual/logbuilder.adoc
index f6b93f158a..3cc8c40591 100644
--- a/src/site/antora/modules/ROOT/pages/manual/logbuilder.adoc
+++ b/src/site/antora/modules/ROOT/pages/manual/logbuilder.adoc
@@ -15,7 +15,7 @@
     limitations under the License.
 ////
 
-= Log Builder
+= Fluent API
 
 Log4j has traditionally been used with logging statements like
 [source,java]
diff --git a/src/site/antora/modules/ROOT/pages/manual/usage.adoc 
b/src/site/antora/modules/ROOT/pages/manual/usage.adoc
deleted file mode 100644
index 3c158bf704..0000000000
--- a/src/site/antora/modules/ROOT/pages/manual/usage.adoc
+++ /dev/null
@@ -1,227 +0,0 @@
-////
-    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.
-////
-= Usage
-
-[#static-vs-non-static]
-== Static vs Non-Static Loggers
-As with any variable in Java, Loggers may be declared as static variables or 
class member variables. However,
-there are a few factors to consider when choosing to declare a logger as 
static vs non-static. Generally, it
-is better to declare Loggers as static.
-
-1. Instantiation of a new Logger is a fairly expensive operation when using 
the default ContextSelector,
-link:../javadoc/log4j-core/org/apache/logging/log4j/core/selector/ClassLoaderContextSelector.html[ClassLoaderContextSelector].
-When the Logger is created the `ClassLoaderContextSelector` will locate the 
ClassLoader for the Class the Logger
-is associated with and add the Logger to the LoggerContext associated with 
that ClassLoader.
-2. Once a Logger is created it will not be deleted until the `LoggerContext` 
it is associated with
-is deleted. Typically, this will only happen when the application is shut down 
or un-deployed. Each call
-to getLogger with the same logger name will return the same Logger instance. 
Thus, there is very little
-difference between a static or non-static Logger.
-3. There is no behavioral difference between a static and non-static Logger. 
Both will have the Logger name
-assigned when they are created, which usually will be the name of the class 
they are associated with. See
-the discussion below on logger names vs class names and the example for more 
information.
-
-[#logger-name-vs-class-name]
-== Logging the Logger name vs the Class name
-The logger name of a Logger is specified when the Logger is created. When a 
log method is called the
-class name value in the log event will reflect the name of the class the log 
method was called from, which is
-not necessarily the same as the class that created the Logger. The following 
example illustrations this.
-
-The base class creates a static Logger and a logger variable that is 
initialized as that same Logger.
-          It has two methods that perform logging, once that uses the static 
logger and one that uses a Logger that
-          can be overridden.
-
-
-[source]
-----
-  package org.apache.logging;
-
-  import org.apache.logging.log4j.LogManager;
-  import org.apache.logging.log4j.Logger;
-  import org.apache.logging.log4j.Marker;
-
-  /**
-  *
-  */
-  public abstract class Parent {
-
-      // The name of this Logger will be "org.apache.logging.Parent"
-      protected static final Logger parentLogger = LogManager.getLogger();
-
-      private Logger logger = parentLogger;
-
-      protected Logger getLogger() {
-          return logger;
-      }
-
-      protected void setLogger(Logger logger) {
-          this.logger = logger;
-      }
-
-
-      public void log(Marker marker) {
-          logger.debug(marker,"Parent log message");
-      }
-  }
-----
-
-This class extends the base class. It provides its own logger and has three 
methods, one that uses the
-logger in this class,one that uses the static logger from the base class, and 
one that where the logger
-may be set to either the parent or the child.
-
-[source]
-----
-  package org.apache.logging;
-
-  import org.apache.logging.log4j.LogManager;
-  import org.apache.logging.log4j.Logger;
-  import org.apache.logging.log4j.Marker;
-
-  /**
-  *
-  */
-  public class Child extends Parent {
-
-      // The name of this Logge will be "org.apache.logging.Child"
-      public Logger childLogger = LogManager.getLogger();
-
-      public void childLog(Marker marker) {
-          childLogger.debug(marker,"Child logger message");
-      }
-
-      public void logFromChild(Marker marker) {
-          getLogger().debug(marker,"Log message from Child");
-      }
-
-      public void parentLog(Marker marker) {
-          parentLogger.debug(marker,"Parent logger, message from Child");
-      }
-  }
-----
-
-The application exercises all the logging methods four times. The first two 
times the Logger in the base
-class is set to the static Logger. The second two times the Logger in the base 
class is set to use the
-Logger in the subclass. In the first and third invocation of each method a 
null Marker is passed. In the
-second and fourth a Marker named "CLASS" is passed.
-
-[source]
-----
-  package org.apache.logging;
-
-  import org.apache.logging.log4j.Marker;
-  import org.apache.logging.log4j.MarkerManager;
-
-  public class App {
-
-      public static void main( String[] args ) {
-          Marker marker = MarkerManager.getMarker("CLASS");
-          Child child = new Child();
-
-          System.out.println("------- Parent Logger ----------");
-          child.log(null);
-          child.log(marker);
-          child.logFromChild(null);
-          child.logFromChild(marker);
-          child.parentLog(null);
-          child.parentLog(marker);
-
-          child.setLogger(child.childLogger);
-
-          System.out.println("------- Parent Logger set to Child Logger 
----------");
-          child.log(null);
-          child.log(marker);
-          child.logFromChild(null);
-          child.logFromChild(marker);
-      }
-  }
-----
-
-The configuration takes advantage of Log4j's ability to select a pattern based 
upon attributes of the log event.
-In this case %C, the class name pattern, is used when the CLASS Marker is 
present, and %c, the logger name
-is used when the CLASS marker is not present.
-
-[source,xml]
-----
-<?xml version="1.0" encoding="UTF-8"?>
-<Configuration status="error">
-  <Appenders>
-    <Console name="Console" target="SYSTEM_OUT">
-      <PatternLayout>
-        <MarkerPatternSelector defaultPattern="%sn. %msg: Logger=%logger%n">
-          <PatternMatch key="CLASS" pattern="%sn. %msg: Class=%class%n"/>
-        </MarkerPatternSelector>
-      </PatternLayout>
-    </Console>
-  </Appenders>
-  <Loggers>
-    <Root level="TRACE">
-      <AppenderRef ref="Console" />
-    </Root>
-  </Loggers>
-</Configuration>
-----
-
-The output below illustrates the difference between using the Logger name and 
the Class name in the pattern. All
-the odd numbered items print the name of the logger (%c) while all the even 
numbered items print the
-name of the class that called the logging method (%C). The numbers in the 
description of the outcomes in the
-following list match the corresponding numbers shown in the output.
-
-1. Logging is performed in the parent class using the static logger with the 
Logger name pattern. The
-logger name matches the name of the parent class.
-2. Logging is performed in the parent class using the static logger with the 
Class name pattern. Although
-the method was called against the Child instance it is implemented in Parent 
so that is what appears.
-3. Logging is performed in Child using the logger in the parent, so the name 
of the parent is printed as the logger
-name.
-4. Logging is performed in Child using the logger in the parent. Since the 
method calling the logging
-method is in Child that is the class name that appears.
-5. Logging is performed in Child using the static logger in the parent, so the 
name of the parent is printed as the
-logger name.
-6. Logging is performed in Child using the static logger in the parent. Since 
the method calling the logging
-method is in Child that is the class name that appears.
-7. Logging is performed in the parent class using the logger of Child. The 
logger name matches the name of the child
-and so it is printed.
-8. Logging is performed in the parent class using the logger of the Child. 
Although the method was called against
-the Child instance it is implemented in Parent so that is what appears as the 
class name.
-9. Logging is performed in Child using the logger in the parent which is set 
to the child logger, so the name of the
-child is printed as the logger name.
-10. Logging is performed in Child using the logger in the parent, which is set 
to the child logger. Since
-the method calling the logging method is in Child that is the class name that 
appears.
-
-[source]
-----
-  ------- Parent Logger ----------
-  1. Parent log message: Logger=org.apache.logging.Parent
-  2. Parent log message: Class=org.apache.logging.Parent
-  3. Log message from Child: Logger=org.apache.logging.Parent
-  4. Log message from Child: Class=org.apache.logging.Child
-  5. Parent logger, message from Child: Logger=org.apache.logging.Parent
-  6. Parent logger, message from Child: Class=org.apache.logging.Child
-  ------- Parent Logger set to Child Logger ----------
-  7. Parent log message: Logger=org.apache.logging.Child
-  8. Parent log message: Class=org.apache.logging.Parent
-  9. Log message from Child: Logger=org.apache.logging.Child
-  10. Log message from Child: Class=org.apache.logging.Child
-----
-
-In the example above there are two Loggers declared. One is static and one is 
non-static. When looking at
-the results it is clear that the outcomes would be exactly the same regardless 
of whether how the loggers
-are declared. The name of the logger will always originate from the class in 
which it is created and the
-Class name in each log event will always reflect the Class from which the 
logging method was called.
-
-It should be noted that there is a substantial performance penalty for 
printing the location information
-(class name, method name, and line number). If the method name and line number 
are not important it is
-usually better to make sure that each class has its own Logger so the logger 
name accurately reflects the
-class performing the logging.
diff --git 
a/src/site/antora/modules/ROOT/partials/manual/api-best-practice-dont-use-string-concat.adoc
 
b/src/site/antora/modules/ROOT/partials/manual/api-best-practice-dont-use-string-concat.adoc
new file mode 100644
index 0000000000..5759d12dc9
--- /dev/null
+++ 
b/src/site/antora/modules/ROOT/partials/manual/api-best-practice-dont-use-string-concat.adoc
@@ -0,0 +1,36 @@
+////
+    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.
+////
+
+If you are using `String` concatenation while logging, you are doing something 
very wrong and dangerous!
+
+* [ ] Don't use `String` concatenation to format arguments!
+This circumvents the handling of arguments by message type and layout.
+More importantly, **this approach is prone to attacks!**
+Imagine `userId` being provided by the user with the following content:
+`placeholders for non-existing args to trigger failure: {} {} 
\{dangerousLookup}`
++
+[source,java]
+----
+/* BAD! */ LOGGER.info("failed for user ID: " + userId);
+----
+
+* [x] Use message parameters
++
+[source,java]
+----
+/* GOOD */ LOGGER.info("failed for user ID `{}`", userId);
+----
diff --git 
a/src/site/antora/modules/ROOT/partials/manual/api-best-practice-dont-use-toString.adoc
 
b/src/site/antora/modules/ROOT/partials/manual/api-best-practice-dont-use-toString.adoc
new file mode 100644
index 0000000000..eada95008c
--- /dev/null
+++ 
b/src/site/antora/modules/ROOT/partials/manual/api-best-practice-dont-use-toString.adoc
@@ -0,0 +1,30 @@
+////
+    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.
+////
+
+* [ ] Don't use `Object#toString()` in arguments, it is redundant!
++
+[source,java]
+----
+/* BAD! */ LOGGER.info("userId: {}", userId.toString());
+----
+
+* [x] Underlying message type and layout will deal with arguments:
++
+[source,java]
+----
+/* GOOD */ LOGGER.info("userId: {}", userId);
+----
diff --git 
a/src/site/antora/modules/ROOT/partials/manual/api-best-practice-exception-as-last-argument.adoc
 
b/src/site/antora/modules/ROOT/partials/manual/api-best-practice-exception-as-last-argument.adoc
new file mode 100644
index 0000000000..eada95008c
--- /dev/null
+++ 
b/src/site/antora/modules/ROOT/partials/manual/api-best-practice-exception-as-last-argument.adoc
@@ -0,0 +1,30 @@
+////
+    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.
+////
+
+* [ ] Don't use `Object#toString()` in arguments, it is redundant!
++
+[source,java]
+----
+/* BAD! */ LOGGER.info("userId: {}", userId.toString());
+----
+
+* [x] Underlying message type and layout will deal with arguments:
++
+[source,java]
+----
+/* GOOD */ LOGGER.info("userId: {}", userId);
+----
diff --git 
a/src/site/antora/modules/ROOT/partials/manual/api-best-practice-use-supplier.adoc
 
b/src/site/antora/modules/ROOT/partials/manual/api-best-practice-use-supplier.adoc
new file mode 100644
index 0000000000..5156e24854
--- /dev/null
+++ 
b/src/site/antora/modules/ROOT/partials/manual/api-best-practice-use-supplier.adoc
@@ -0,0 +1,47 @@
+////
+    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.
+////
+
+If one or more arguments of the log statement are computationally expensive, 
it is not wise to evaluate them knowing that their results can be discarded.
+Consider the following example:
+
+[source,java]
+----
+/* BAD! */ LOGGER.info("failed for user ID `{}` and role `{}`", userId, 
db.findUserRoleById(userId));
+----
+
+The database query (i.e., `db.findUserNameById(userId)`) can be a significant 
bottleneck if the created the log event will be discarded anyway – maybe the 
`INFO` level is not accepted for this logger, or due to some other filtering.
+
+* [ ] The old-school way of solving this problem is to level-guard the log 
statement:
++
+[source,java]
+----
+/* OKAY */ if (LOGGER.isInfoEnabled()) { LOGGER.info(...); }
+----
++
+While this would work for cases where the message can be dropped due to 
insufficient level, this approach is still prone to other filtering cases; 
e.g., maybe the associated xref:manual/markers.adoc[marker] is not accepted.
+* [x] Use ``Supplier``s to pass arguments containing computationally expensive 
items:
++
+[source,java]
+----
+/* GOOD */ LOGGER.info("failed for user ID `{}` and role `{}`", () -> userId, 
() -> db.findUserRoleById(userId));
+----
+* [x] Use a `Supplier` to pass the message and its arguments containing 
computationally expensive items:
++
+[source,java]
+----
+/* GOOD */ LOGGER.info(() -> new ParameterizedMessage("failed for user ID `{}` 
and role `{}`", userId, db.findUserRoleById(userId)));
+----
diff --git a/src/site/antora/modules/ROOT/partials/manual/api-intro.adoc 
b/src/site/antora/modules/ROOT/partials/manual/api-intro.adoc
new file mode 100644
index 0000000000..ba0921f305
--- /dev/null
+++ b/src/site/antora/modules/ROOT/partials/manual/api-intro.adoc
@@ -0,0 +1,72 @@
+////
+    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.
+////
+
+To write logs, you need a `Logger` instance which you will retrieve from the 
`LogManager`.
+You can use the `Logger` instance to write logs by using methods like 
`info()`, `warn()`, `error()`, etc.
+These methods are named after the _log levels_ they represent, a way to 
categorize log events by severity.
+The log message can also contain placeholders written as `{}` that will be 
replaced by the arguments passed to the method.
+
+[source,java]
+----
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.LogManager;
+
+public class DbTableService {
+
+    private static final Logger LOGGER = LogManager.getLogger(); // <1>
+
+    public void truncateTable(String tableName) throws IOException {
+        LOGGER.warn("truncating table `{}`", tableName); // <2>
+        db.truncate(tableName);
+    }
+
+}
+----
+<1> The returned `Logger` instance is thread-safe and reusable.
+Unless explicitly provided as an argument, `getLogger()` associates the 
returned `Logger` with the enclosing class, that is, `DbTableService` in this 
example.
+<2> The placeholder `{}` in the message will be replaced with the value of 
`tableName`
+
+The generated **log event** will be enriched with the log level (i.e., 
`WARN`), but also timestamp, class & method name, line number, and several 
other information.
+
+**What happens to the generated log event will vary significantly depending on 
the configuration used.**
+It can be pretty-printed to the console, written to a file, or get totally 
ignored due to insufficient severity or some other filtering.
+
+Log levels are used to categorize log events by severity and control the 
verbosity of the logs.
+Log4j knows various levels, but the most common are `DEBUG`, `INFO`, `WARN`, 
and `ERROR`.
+With them, you can filter out less important logs and focus on the most 
critical ones.
+Previously we used `Logger#warn()` to log a warning message, which could mean 
that something is not right, but the application can continue.
+Log levels have a priority, and `WARN` is less severe than `ERROR`.
+
+Exceptions are often also errors.
+In this case, we might use the `ERROR` log level.
+Make sure to log exceptions that have diagnostics value.
+This is simply done by passing the exception as the last argument to the log 
method:
+
+[source,java]
+----
+LOGGER.warn("truncating table `{}`", tableName);
+try {
+    db.truncate(tableName);
+} catch (IOException exception) {
+    LOGGER.error("failed truncating table `{}`", tableName, exception); // <1>
+    throw new IOException("failed truncating table: " + tableName, exception);
+}
+----
+<1> By using `error()` instead of `warn()`, we signal that the operation 
failed.
+
+While there is only one placeholder in the message, we pass two arguments: 
`tableName` and `exception`.
+Log4j will attach the last extra argument of type `Throwable` in a separate 
field to the generated log event.
diff --git a/src/site/resources/.htaccess b/src/site/resources/.htaccess
index 62f3e81140..ee5a68abe5 100644
--- a/src/site/resources/.htaccess
+++ b/src/site/resources/.htaccess
@@ -18,5 +18,7 @@
 #
 RewriteEngine On
 RewriteRule "^(/log4j/[23].x)/log4j-(core|api)/apidocs(.*)" "$1/javadoc/$2$3" 
[R=permanent]
+RewriteRule "^(/log4j/[23].x)/manual/api-separation.html" "$1/manual/api.html" 
[R=permanent]
 RewriteRule "^(/log4j/[23].x)/manual/scala-api.html" "/log4j/scala" 
[R=permanent]
+RewriteRule "^(/log4j/[23].x)/manual/usage.html" "$1/manual/api.html" 
[R=permanent]
 RewriteRule "^(/log4j/[23].x)/release-notes/index.html" 
"$1/release-notes.html" [R=permanent]

Reply via email to