You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by vy...@apache.org on 2024/06/25 08:35:41 UTC
(logging-log4j2) 01/02: Rewrite architecture page and several other affected pages
This is an automated email from the ASF dual-hosted git repository.
vy pushed a commit to branch doc/2.x/extending
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
commit 34eb9f036e853c7d4b05bfd9e36e2e170a12087e
Author: Volkan Yazıcı <vo...@yazi.ci>
AuthorDate: Tue Jun 25 10:25:03 2024 +0200
Rewrite architecture page and several other affected pages
---
.../manual/customloglevels/custom/log4j2.json | 34 +
.../customloglevels/custom/log4j2.properties | 30 +
.../manual/customloglevels/custom/log4j2.xml | 28 +
.../manual/customloglevels/custom/log4j2.yaml | 37 +
.../manual/customloglevels/filtering/log4j2.json | 24 +
.../customloglevels/filtering/log4j2.properties | 24 +
.../manual/customloglevels/filtering/log4j2.xml | 21 +
.../manual/customloglevels/filtering/log4j2.yaml | 31 +
.../manual/customloglevels/filtering/logback.xml | 34 +
.../antora/modules/ROOT/images/Log4jClasses.jpg | Bin 31443 -> 0 bytes
.../modules/ROOT/pages/manual/architecture.adoc | 1162 +++++++++++++-------
.../modules/ROOT/pages/manual/configuration.adoc | 2 +-
.../modules/ROOT/pages/manual/customloglevels.adoc | 170 +--
.../modules/ROOT/pages/manual/extending.adoc | 4 +-
.../antora/modules/ROOT/pages/manual/markers.adoc | 6 +-
15 files changed, 1117 insertions(+), 490 deletions(-)
diff --git a/src/site/antora/modules/ROOT/examples/manual/customloglevels/custom/log4j2.json b/src/site/antora/modules/ROOT/examples/manual/customloglevels/custom/log4j2.json
new file mode 100644
index 0000000000..06be7e3bcd
--- /dev/null
+++ b/src/site/antora/modules/ROOT/examples/manual/customloglevels/custom/log4j2.json
@@ -0,0 +1,34 @@
+{
+ "Configuration": {
+ "Appenders": {
+ "Console": {
+ "name": "CONSOLE",
+ "PatternLayout": {}
+ },
+ "File": {
+ "name": "FILE",
+ "JsonTemplateLayout": {}
+ }
+ },
+ "CustomLevels": [
+ { //<1>
+ "name": "VERBOSE",
+ "intLevel": 550
+ }
+ ],
+ "Loggers": {
+ "Root": {
+ "level": "ALL",
+ "AppenderRef": [
+ {
+ "ref": "CONSOLE",
+ "level": "VERBOSE" //<2>
+ },
+ {
+ "ref": "FILE"
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/src/site/antora/modules/ROOT/examples/manual/customloglevels/custom/log4j2.properties b/src/site/antora/modules/ROOT/examples/manual/customloglevels/custom/log4j2.properties
new file mode 100644
index 0000000000..6033c0851d
--- /dev/null
+++ b/src/site/antora/modules/ROOT/examples/manual/customloglevels/custom/log4j2.properties
@@ -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.
+#
+appender.0.type = Console
+appender.0.name = CONSOLE
+appender.0.layout.type = JsonTemplateLayout
+appender.1.type = File
+appender.1.name = FILE
+appender.1.layout.type = PatternLayout
+
+customLevel.0.name = VERBOSE #<1>
+customLevel.0.intLevel = 550
+
+rootLogger.level = ALL
+rootLogger.appenderRef.0.ref = CONSOLE
+rootLogger.appenderRef.0.level = VERBOSE #<2>
+rootLogger.appenderRef.1.ref = FILE
diff --git a/src/site/antora/modules/ROOT/examples/manual/customloglevels/custom/log4j2.xml b/src/site/antora/modules/ROOT/examples/manual/customloglevels/custom/log4j2.xml
new file mode 100644
index 0000000000..357d197932
--- /dev/null
+++ b/src/site/antora/modules/ROOT/examples/manual/customloglevels/custom/log4j2.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="https://logging.apache.org/xml/ns"
+ xsi:schemaLocation="
+ https://logging.apache.org/xml/ns
+ https://logging.apache.org/xml/ns/log4j-config-2.xsd">
+
+ <Appenders>
+ <Console name="CONSOLE">
+ <PatternLayout/>
+ </Console>
+ <File name="FILE" fileName="logs/app.log">
+ <JsonTemplateLayout/>
+ </File>
+ </Appenders>
+
+ <CustomLevels>
+ <CustomLevel name="VERBOSE" intLevel="550"/> <!--1-->
+ </CustomLevels>
+
+ <Loggers>
+ <Root level="ALL">
+ <AppenderRef ref="CONSOLE" level="VERBOSE"/> <!--2-->
+ <AppenderRef ref="FILE"/>
+ </Root>
+ </Loggers>
+
+</Configuration>
diff --git a/src/site/antora/modules/ROOT/examples/manual/customloglevels/custom/log4j2.yaml b/src/site/antora/modules/ROOT/examples/manual/customloglevels/custom/log4j2.yaml
new file mode 100644
index 0000000000..d702f4490d
--- /dev/null
+++ b/src/site/antora/modules/ROOT/examples/manual/customloglevels/custom/log4j2.yaml
@@ -0,0 +1,37 @@
+#
+# 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.
+#
+Configuration:
+
+ Appenders:
+ Console:
+ name: "CONSOLE"
+ PatternLayout: {}
+ File:
+ name: "FILE"
+ JsonTemplateLayout: {}
+
+ CustomLevels: #<1>
+ - name: "VERBOSE"
+ intLevel: 550
+
+ Loggers:
+ Root:
+ level: "ALL"
+ AppenderRef:
+ - ref: "CONSOLE"
+ level: "VERBOSE" #<2>
+ - ref: "FILE"
diff --git a/src/site/antora/modules/ROOT/examples/manual/customloglevels/filtering/log4j2.json b/src/site/antora/modules/ROOT/examples/manual/customloglevels/filtering/log4j2.json
new file mode 100644
index 0000000000..14f24253fc
--- /dev/null
+++ b/src/site/antora/modules/ROOT/examples/manual/customloglevels/filtering/log4j2.json
@@ -0,0 +1,24 @@
+{
+ "Configuration": {
+ "Appenders": {
+ "Console": {
+ "name": "CONSOLE",
+ "JsonTemplateLayout": {}
+ }
+ },
+ "Loggers": {
+ "Logger": [
+ {
+ "name": "com.mycompany",
+ "level": "INFO" //<1>
+ }
+ ],
+ "Root": {
+ "level": "ERROR", //<2>
+ "AppenderRef": {
+ "ref": "CONSOLE"
+ }
+ }
+ }
+ }
+}
diff --git a/src/site/antora/modules/ROOT/examples/manual/customloglevels/filtering/log4j2.properties b/src/site/antora/modules/ROOT/examples/manual/customloglevels/filtering/log4j2.properties
new file mode 100644
index 0000000000..a2d008872e
--- /dev/null
+++ b/src/site/antora/modules/ROOT/examples/manual/customloglevels/filtering/log4j2.properties
@@ -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.
+#
+appender.0.type = Console
+appender.0.name = CONSOLE
+appender.0.layout.type = JsonTemplateLayout
+
+logger.0.name = com.mycompany
+logger.0.level = INFO #<1>
+rootLogger.level = ERROR #<2>
+rootLogger.appenderRef.0.ref = CONSOLE
diff --git a/src/site/antora/modules/ROOT/examples/manual/customloglevels/filtering/log4j2.xml b/src/site/antora/modules/ROOT/examples/manual/customloglevels/filtering/log4j2.xml
new file mode 100644
index 0000000000..bc5d5bb726
--- /dev/null
+++ b/src/site/antora/modules/ROOT/examples/manual/customloglevels/filtering/log4j2.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="https://logging.apache.org/xml/ns"
+ xsi:schemaLocation="
+ https://logging.apache.org/xml/ns
+ https://logging.apache.org/xml/ns/log4j-config-2.xsd">
+
+ <Appenders>
+ <Console name="CONSOLE">
+ <JsonTemplateLayout/>
+ </Console>
+ </Appenders>
+
+ <Loggers>
+ <Logger name="com.mycompany" level="INFO"/> <!--1-->
+ <Root level="ERROR"> <!--2-->
+ <AppenderRef ref="CONSOLE"/>
+ </Root>
+ </Loggers>
+
+</Configuration>
diff --git a/src/site/antora/modules/ROOT/examples/manual/customloglevels/filtering/log4j2.yaml b/src/site/antora/modules/ROOT/examples/manual/customloglevels/filtering/log4j2.yaml
new file mode 100644
index 0000000000..8b7d3ce2c0
--- /dev/null
+++ b/src/site/antora/modules/ROOT/examples/manual/customloglevels/filtering/log4j2.yaml
@@ -0,0 +1,31 @@
+#
+# 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.
+#
+Configuration:
+
+ Appenders:
+ Console:
+ name: "CONSOLE"
+ JsonTemplateLayout: {}
+
+ Loggers:
+ Logger:
+ - name: "com.mycompany"
+ level: "INFO" #<1>
+ Root:
+ level: "ERROR" #<2>
+ AppenderRef:
+ ref: "CONSOLE"
diff --git a/src/site/antora/modules/ROOT/examples/manual/customloglevels/filtering/logback.xml b/src/site/antora/modules/ROOT/examples/manual/customloglevels/filtering/logback.xml
new file mode 100644
index 0000000000..09491b9571
--- /dev/null
+++ b/src/site/antora/modules/ROOT/examples/manual/customloglevels/filtering/logback.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+<!DOCTYPE configuration>
+<configuration>
+
+ <import class="ch.qos.logback.core.ConsoleAppender"/>
+
+ <appender name="CONSOLE" class="ConsoleAppender">
+ <encoder class="PatternLayoutEncoder">
+ <pattern><![CDATA[%d %5p [%t] %c{1} -- %m%n]]></pattern>
+ </encoder>
+ </appender>
+
+ <logger name="com.mycompany" level="INFO"/>
+ <root level="ERROR">
+ <appender-ref ref="CONSOLE"/>
+ </root>
+
+</configuration>
diff --git a/src/site/antora/modules/ROOT/images/Log4jClasses.jpg b/src/site/antora/modules/ROOT/images/Log4jClasses.jpg
deleted file mode 100755
index ea16084bd6..0000000000
Binary files a/src/site/antora/modules/ROOT/images/Log4jClasses.jpg and /dev/null differ
diff --git a/src/site/antora/modules/ROOT/pages/manual/architecture.adoc b/src/site/antora/modules/ROOT/pages/manual/architecture.adoc
index f151b79081..91213fec00 100644
--- a/src/site/antora/modules/ROOT/pages/manual/architecture.adoc
+++ b/src/site/antora/modules/ROOT/pages/manual/architecture.adoc
@@ -16,469 +16,789 @@
////
= Architecture
-== Main Components
-
-Log4j uses the classes shown in the diagram below.
-
-image:Log4jClasses.jpg[Log4j 2 Class Relationships,title="Log4j 2 Class Relationships"]
-
-Applications using the Log4j 2 API will request a Logger with a specific
-name from the LogManager. The LogManager will locate the appropriate
-LoggerContext and then obtain the Logger from it. If the Logger must be
-created it will be associated with the LoggerConfig that contains either
-a) the same name as the Logger, b) the name of a parent package, or c)
-the root LoggerConfig. LoggerConfig objects are created from Logger
-declarations in the configuration. The LoggerConfig is associated with
-the Appenders that deliver the LogEvents.
-
-[id=logger-hierarchy]
-=== Logger Hierarchy
-
-The first and foremost advantage of any logging API over plain
-`System.out.println()` resides in its ability to disable certain log
-statements while allowing others to print unhindered. This capability
-assumes that the logging space, that is, the space of all possible
-logging statements, is categorized according to some developer-chosen
-criteria.
-
-In Log4j 1.x the Logger Hierarchy was maintained through a relationship
-between Loggers. In Log4j 2 this relationship no longer exists. Instead,
-the hierarchy is maintained in the relationship between LoggerConfig
-objects.
-
-Loggers and LoggerConfigs are named entities. Logger names are
-case-sensitive and they follow the hierarchical naming rule:
-
-Named Hierarchy::
-A LoggerConfig is said to be an _ancestor_ of another LoggerConfig if
-its name followed by a dot is a prefix of the _descendant_ logger
-name. A LoggerConfig is said to be a _parent_ of a _child_
-LoggerConfig if there are no ancestors between itself and the
-descendant LoggerConfig.
-
-For example, the LoggerConfig named `"com.foo"` is a parent of the
-LoggerConfig named `"com.foo.Bar"`. Similarly, `"java"` is a parent of
-`"java.util"` and an ancestor of `"java.util.Vector"`. This naming
-scheme should be familiar to most developers.
-
-The root LoggerConfig resides at the top of the LoggerConfig hierarchy.
-It is exceptional in that it always exists and it is part of every
-hierarchy. A Logger that is directly linked to the root LoggerConfig can
-be obtained as follows:
-
-[source,java]
-----
-Logger logger = LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);
-----
-
-Alternatively, and more simply:
-
-[source,java]
-----
-Logger logger = LogManager.getRootLogger();
-----
-
-All other Loggers can be retrieved using the
-link:../javadoc/log4j-api/org/apache/logging/log4j/LogManager.html#getLogger(java.lang.String)[`LogManager.getLogger`]
-static method by passing the name of the desired Logger. Further
-information on the Logging API can be found in the
-xref:manual/api.adoc[Log4j API].
-
-[#logger-context]
-=== LoggerContext
+Log4j Core is the reference implementation of xref:manual/api.adoc[] and composed of several components.
+In this section we will try to explain major pillars its architecture stands on.
+An overview these major classes can be depicted as follows:
+
+[#architecture-diagram]
+.An overview of major classes and their relation
+[plantuml]
+....
+@startuml
+
+class LoggerContext {
+ Configuration config
+ Logger[] loggers
+ Logger getLogger(String name)
+}
+
+note left of LoggerContext {
+ Anchor for the logging system
+}
+
+LoggerContext --> Configuration
+
+LoggerContext --> "0..*" Logger
+
+class Configuration {
+ Appender[] appenders
+ Filter[] filters
+ LoggerConfig[] loggerConfigs
+ LoggerConfig getLoggerConfig(String name)
+ StrSubstitutor substitutor
+}
+
+note left of Configuration
+ Encapsulates components compiled
+ from a user-provided configuration
+ file (e.g., `log4j2.xml`)
+end note
+
+Configuration --> "0..*" Filter
+
+Configuration --> "0..*" Appender
+
+Configuration --> "0..*" LoggerConfig
+
+Configuration --> StrSubstitutor
+
+class Appender {
+ Layout layout
+ void append(LogEvent)
+}
+
+Appender -[#green,thickness=6]-> Layout
+
+class Layout {
+ byte[] encode(LogEvent)
+}
+
+class Filter {
+ Result filter(LogEvent)
+}
+
+note right of Filter
+ Note that a `Filter` can
+ be provided at 4 levels:
+ 1. `Configuration`
+ 2. `LoggerConfig`
+ 3. `AppenderRef`
+ 4. `AppenderControl`
+end note
+
+class LoggerConfig {
+ AppenderRef[] appenderRefs
+ AppenderControl[] appenderControls
+ Level level
+ Filter filter
+ void log(LogEvent)
+}
+
+LoggerConfig --> "0..*" AppenderRef
+
+LoggerConfig -[#green,thickness=6]-> "0..*" AppenderControl
+
+LoggerConfig --> Filter
+
+class AppenderRef {
+ String appenderName
+ Level level
+ Filter filter
+}
+
+note right of AppenderRef
+ Denotes a user-provided
+ appender configuration
+ for a `Logger`,
+ e.g., `<AppenderRef`
+ element in a `log4j2.xml`.
+
+ It is used to populate
+ `AppenderControl`s.
+end note
+
+AppenderRef --> Filter
+
+class AppenderControl {
+ Appender appender
+ Filter filter
+ void append(LogEvent)
+}
+
+note right of AppenderControl
+ Decorates an `Appender`
+ with a `Filter`
+end note
+
+AppenderControl -[#green,thickness=6]-> Appender
+
+AppenderControl --> Filter
+
+class StrSubstitutor {
+ Interpolator interpolator
+ String replace(String input)
+}
+
+note right of StrSubstitutor
+ Responsible for
+ property substitution
+ (e.g., `${env:USER}`)
+end note
+
+StrSubstitutor --> Interpolator
+
+class Interpolator {
+ StrLookup[] lookups
+ String lookup(String input)
+}
+
+Interpolator --> "0..*" StrLookup
+
+class StrLookup {
+ String lookup(String input)
+}
+
+class Logger {
+ void log(Level level, Message message)
+}
+
+note right of Logger
+ The main API entry point
+ users interact with
+end note
+
+Logger -[#green,thickness=6]-> LoggerConfig : delegates `log()`
+
+@enduml
+....
+
+At a really high level,
+
+* A <<LoggerContext>>, the composition anchor, gets created in combination with a <<Configuration>>.
+Both can be created either directly (i.e., programmatically) or indirectly at first interaction with Log4j.
+* `LoggerContext` creates <<Logger>>s that users interact with for logging purposes.
+* <<Appender>> delivers a link:../javadoc/log4j-core/org/apache/logging/log4j/core/LogEvent.html[`LogEvent`] to a target (file, socket, database, etc.) and typically uses a <<Layout>> to encode log events.
+* <<LoggerConfig>> encapsulates configuration for a `Logger`, as `AppenderControl` and `AppenderRef` for ``Appender``s.
+* <<Configuration>> is equipped with <<StrSubstitutor>> to allow property substitution in `String`-typed values.
+* A typical `log()` call triggers a chain of invocations through classes `Logger`, `LoggerConfig`, `AppenderControl`, `Appender`, and `Layout` in order – this is depicted using green arrows in xref:architecture-diagram[xrefstyle=short].
+
+Following sections examine this interplay in detail.
+
+[#LoggerContext]
+== `LoggerContext`
The link:../javadoc/log4j-api/org/apache/logging/log4j/spi/LoggerContext.html[`LoggerContext`] acts as the anchor point for the logging system.
-It is primarily responsible for instantiating <<logger>>s.
+It is associated with an active <<Configuration>> and is primarily responsible for instantiating <<Logger>>s.
+
+[#LoggerContext-diagram]
+.`LoggerContext` and other directly related classes
+[plantuml]
+....
+@startuml
+
+class LoggerContext #line.bold {
+ Configuration config
+ Logger[] loggers
+ Logger getLogger(String name)
+}
+
+LoggerContext --> Configuration
+
+LoggerContext --> "0..*" Logger
+
+class Configuration {
+ Appender[] appenders
+ Filter[] filters
+ LoggerConfig[] loggerConfigs
+ LoggerConfig getLoggerConfig(String name)
+ StrSubstitutor substitutor
+}
+
+class Logger {
+ void log(Level level, Message message)
+}
+
+@enduml
+....
In most cases, applications have a single global `LoggerContext`.
Though in certain cases (e.g., Java EE applications), Log4j can be configured to accommodate multiple ``LoggerContext``s.
Refer to xref:manual/logsep.adoc[] for details.
-=== Configuration
-
-Every LoggerContext has an active
-link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/Configuration.html[`Configuration`].
-The Configuration contains all the Appenders, context-wide Filters,
-LoggerConfigs and contains the reference to the StrSubstitutor.
-During reconfiguration, two Configuration objects will exist. Once all Loggers
-have been redirected to the new Configuration, the old Configuration
-will be stopped and discarded.
-
-[#logger]
-=== Logger
-
-As stated previously, Loggers are created by calling
-link:../javadoc/log4j-api/org/apache/logging/log4j/LogManager.html#getLogger(java.lang.String)[`LogManager.getLogger`].
-The Logger itself performs no direct actions. It simply has a name and
-is associated with a LoggerConfig. It extends
-link:../javadoc/log4j-api/org/apache/logging/log4j/spi/AbstractLogger.html[`AbstractLogger`]
-and implements the required methods. As the configuration is modified
-Loggers may become associated with a different LoggerConfig, thus
-causing their behavior to be modified.
-
-Retrieving Loggers
-
-Calling the `LogManager.getLogger` method with the same name will always
-return a reference to the same Logger object.
-
-For example, in
-
-[source,java]
-----
-Logger x = LogManager.getLogger("wombat");
-Logger y = LogManager.getLogger("wombat");
-----
-
-`x` and `y` refer to _exactly_ the same Logger object.
-
-Configuration of the log4j environment is typically done at application
-initialization. The preferred way is by reading a configuration file.
-This is discussed in xref:manual/configuration.adoc[Configuration].
-
-Log4j makes it easy to name Loggers by _software component_. This can be
-accomplished by instantiating a Logger in each class, with the logger
-name equal to the fully qualified name of the class. This is a useful
-and straightforward method of defining loggers. As the log output bears
-the name of the generating Logger, this naming strategy makes it easy to
-identify the origin of a log message. However, this is only one
-possible, albeit common, strategy for naming loggers. Log4j does not
-restrict the possible set of loggers. The developer is free to name the
-loggers as desired.
-
-Since naming Loggers after their owning class is such a common idiom,
-the convenience method `LogManager.getLogger()` is provided to
-automatically use the calling class's fully qualified class name as the
-Logger name.
-
-Nevertheless, naming loggers after the class where they are located
-seems to be the best strategy known so far.
-
-[#loggerconfig]
-=== LoggerConfig
-
-link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/LoggerConfig.html[`LoggerConfig`]
-objects are created when Loggers are declared in the logging
-configuration. The LoggerConfig contains a set of Filters that must
-allow the LogEvent to pass before it will be passed to any Appenders. It
-contains references to the set of Appenders that should be used to
-process the event.
-
-==== Log Levels
-
-LoggerConfigs will be assigned a Log
-link:../javadoc/log4j-api/org/apache/logging/log4j/Level.html[`Level`].
-The set of built-in levels includes ALL, TRACE, DEBUG, INFO, WARN, ERROR,
-FATAL, and OFF. Log4j 2 also supports xref:manual/customloglevels.adoc[custom log
-levels]. Another mechanism for getting more granularity is to use
-xref:manual/markers.adoc[markers] instead. The OFF and ALL
-levels are not intended to be used on calls to the logging API.
-Specifying OFF in the configuration implies no logging events should
-match while specifying ALL would mean all events match, including custom
-events. However, OFF can be used on logging API calls in special cases
-where the event should always be logged regardless of the configuration.
-However, it is generally recommended that a Marker with a corresponding
-global Marker Filter be used instead.
-
-{logging-services-url}/log4j/1.x/manual.html[Log4j 1] and
-{logback-url}/manual/architecture.html#effectiveLevel[Logback]
-both have the concept of "Level Inheritance". In Log4j 2, Loggers and
-LoggerConfigs are two different objects so this concept is implemented
-differently. Each Logger references the appropriate LoggerConfig which
-in turn can reference its parent, thus achieving the same effect.
-
-Below are five tables with various assigned level values and the
-resulting levels that will be associated with each Logger. Note that in
-all these cases if the root LoggerConfig is not configured a default
-Level will be assigned to it.
-
-.Example 1
-[cols=",,,",options="header",]
-|====================================================================
-|Logger Name |Assigned LoggerConfig |LoggerConfig Level |Logger Level
+[#Configuration]
+== `Configuration`
+
+Every <<LoggerContext>> is associated with an active link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/Configuration.html[`Configuration`].
+It models the configuration of all appenders, layouts, filters, loggers, and contains the reference to <<StrSubstitutor>>.
+
+[#Configuration-diagram]
+.`Configuration` and other directly related classes
+[plantuml]
+....
+@startuml
+
+class LoggerContext {
+ Configuration config
+ Logger[] loggers
+ Logger getLogger(String name)
+}
+
+LoggerContext --> Configuration
+
+class Configuration #line.bold {
+ Appender[] appenders
+ Filter[] filters
+ LoggerConfig[] loggerConfigs
+ LoggerConfig getLoggerConfig(String name)
+ StrSubstitutor substitutor
+}
+
+Configuration --> "0..*" Filter
+
+Configuration --> "0..*" Appender
+
+Configuration --> "0..*" LoggerConfig
+
+Configuration --> StrSubstitutor
+
+class Appender {
+ Layout layout
+ void append(LogEvent)
+}
+
+class Filter {
+ Result filter(LogEvent)
+}
+
+class LoggerConfig {
+ AppenderRef[] appenderRefs
+ AppenderControl[] appenderControls
+ Level level
+ Filter filter
+ void log(LogEvent)
+}
+
+class StrSubstitutor {
+ Interpolator interpolator
+ String replace(String input)
+}
+@enduml
+....
+
+During reconfiguration, two `Configuration` instances will be present.
+Once all ``Logger``s have been redirected to the new `Configuration`, the old one will be stopped and discarded.
+
+Configuration of Log4j Core is typically done at application initialization.
+The preferred way is by reading a xref:manual/configuration.adoc[configuration file], but it can also be done xref:manual/customconfig.adoc[programmatically].
+This is further discussed in xref:manual/config-intro.adoc[].
+
+[#Logger]
+== `Logger`
+
+link:../javadoc/log4j-api/org/apache/logging/log4j/Logger.html[`Logger`]s are the primary user entry point for logging.
+They are created by calling one of the `getLogger()` methods of link:../javadoc/log4j-api/org/apache/logging/log4j/LogManager.html[`LogManager`] – this is further documented in xref:manual/api.adoc[].
+The `Logger` itself performs no direct actions.
+It simply has a name and is associated with a <<LoggerConfig>>.
+
+[#Logger-diagram]
+.`Logger` and other directly related classes
+[plantuml]
+....
+@startuml
+
+class LoggerContext {
+ Configuration config
+ Logger[] loggers
+ Logger getLogger(String name)
+}
+
+LoggerContext --> "0..*" Logger
+
+class LoggerConfig {
+ AppenderRef[] appenderRefs
+ AppenderControl[] appenderControls
+ Level level
+ Filter filter
+ void log(LogEvent)
+}
+
+class Logger #line.bold {
+ void log(Level level, Message message)
+}
+
+Logger -[#green,thickness=6]-> LoggerConfig : delegates `log()`
+
+@enduml
+....
+
+The hierarchy between <<LoggerConfig>>s, implies the very same hierarchy between ``Logger``s too.
+You can use `LogManager.getRootLogger()` to get the root logger.
+Note that Log4j API has no assumptions on a `Logger` hierarchy – this is a feature implemented by Log4j Core.
+
+When the <<Configuration>> is modified, ``Logger``s may become associated with a different `LoggerConfig`, thus causing their behavior to be modified.
+Refer to xref:manual/configuration.adoc#configuring-loggers[configuring ``Logger``s] for further information.
+
+[#LoggerConfig]
+== `LoggerConfig`
+
+link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/LoggerConfig.html[`LoggerConfig`] binds <<Logger>> definitions to their associated components (appenders, filters, etc.) as declared in the active <<Configuration>>.
+The details of mapping a `Configuration` to ``LoggerConfig``s is explained xref:manual/configuration.adoc#configuring-loggers[here].
+``Logger``s effectively interact with appenders, filters, etc. through corresponding ``LoggerConfig``s.
+A `LoggerConfig` essentially contains
+
+* A reference to its parent (except if it is the root logger)
+* A xref:manual/customloglevels.adoc[level] denoting the severity of messages that are accepted (defaults to `ERROR`)
+* <<Filter>>s that must allow the `LogEvent` to pass before it will be passed to any <<Appender>>s
+* References to <<Appender>>s that should be used to process the event
+
+[#LoggerConfig-diagram]
+.`LoggerConfig` and other directly related classes
+[plantuml]
+....
+@startuml
+
+class Configuration {
+ Appender[] appenders
+ Filter[] filters
+ LoggerConfig[] loggerConfigs
+ LoggerConfig getLoggerConfig(String name)
+ StrSubstitutor substitutor
+}
+
+Configuration --> "0..*" LoggerConfig
+
+class Filter {
+ Result filter(LogEvent)
+}
+
+class LoggerConfig #line.bold {
+ AppenderRef[] appenderRefs
+ AppenderControl[] appenderControls
+ Level level
+ Filter filter
+ void log(LogEvent)
+}
+
+LoggerConfig --> "0..*" AppenderRef
+
+LoggerConfig -[#green,thickness=6]-> "0..*" AppenderControl
+
+LoggerConfig --> Filter
+
+class AppenderRef {
+ String appenderName
+ Level level
+ Filter filter
+}
+
+class AppenderControl {
+ Appender appender
+ Filter filter
+ void append(LogEvent)
+}
+
+class Logger {
+ void log(Level level, Message message)
+}
+
+Logger -[#green,thickness=6]-> LoggerConfig : delegates `log()`
+
+@enduml
+....
+
+[#logger-hiearchy]
+=== Logger hierarchy
+
+Log4j Core has a *hierarchical* model of ``LoggerConfig``s, and hence ``Logger``s.
+A `LoggerConfig` called `child` is said to be parented by `parent`, if `parent` has the _longest prefix match_ on name.
+This match is case-sensitive and performed after tokenizing the name by splitting it from `.` (dot) characters.
+For a positive name match, tokens must match exhaustively.
+See xref:#logger-hiearchy-diagram[xrefstyle=short] for an example.
+
+[#logger-hiearchy-diagram]
+.Example hierarchy of loggers named `X`, `X.Y`, `X.Y.Z`, and `X.YZ`
+[plantuml]
+....
+@startmindmap
+* root
+** X
+*** X.Y
+**** X.Y.Z
+*** X.YZ
+@endmindmap
+....
+
+If a `LoggerConfig` is not provided an explicit level, it will be inherited from its parent.
+Similarly, if a user programmatically requests a `Logger` with a name that doesn't have a directly corresponding `LoggerConfig` configuration entry with its name, the `LoggerConfig` of the parent will be used.
+
+.Click for examples on `LoggerConfig` hierarchy
+[%collapsible]
+====
+Below we demonstrate the `LoggerConfig` hierarchy by means of _level inheritance_.
+That is, we will examine the effective level of a `Logger` in various `LoggerConfig` settings.
+
+.Only the root logger is configured with a level, and it is `DEBUG`
+[%header,cols="1m,1m,1m,1m"]
+|===
+|Logger name |Assigned `LoggerConfig` name |Configured level |Effective level
|root |root |DEBUG |DEBUG
-|X |root |DEBUG |DEBUG
-|X.Y |root |DEBUG |DEBUG
-|X.Y.Z |root |DEBUG |DEBUG
-|====================================================================
-
-In example 1 above, only the root logger is configured and has a Log
-Level. All the other Loggers reference the root LoggerConfig and use its
-Level.
-
-.Example 2
-[cols=",,,",options="header",]
-|=============================================================
-|Logger Name |Assigned LoggerConfig |LoggerConfig Level |Level
+|X |root | |DEBUG
+|X.Y |root | |DEBUG
+|X.Y.Z |root | |DEBUG
+|===
+
+.All loggers are configured with a level
+[%header,cols="1m,1m,1m,1m"]
+|===
+|Logger name |Assigned `LoggerConfig` |Configured level |Effective level
|root |root |DEBUG |DEBUG
|X |X |ERROR |ERROR
|X.Y |X.Y |INFO |INFO
|X.Y.Z |X.Y.Z |WARN |WARN
-|=============================================================
-
-In example 2, all loggers have a configured LoggerConfig and obtain
-their Level from it.
+|===
-.Example 3
-[cols=",,,",options="header",]
-|=============================================================
-|Logger Name |Assigned LoggerConfig |LoggerConfig Level |Level
+.All loggers are configured with a level, except the logger `X.Y`
+[%header,cols="1m,1m,1m,1m"]
+|===
+|Logger name |Assigned `LoggerConfig` |Configured level |Effective level
|root |root |DEBUG |DEBUG
|X |X |ERROR |ERROR
-|X.Y |X |ERROR |ERROR
+|X.Y |X | |ERROR
|X.Y.Z |X.Y.Z |WARN |WARN
-|=============================================================
-
-In example 3, the loggers`root`, `X` and `X.Y.Z` each have a configured
-LoggerConfig with the same name. The Logger `X.Y` does not have a
-configured LoggerConfig with a matching name so uses the configuration
-of LoggerConfig `X` since that is the LoggerConfig whose name has the
-the longest match to the start of the Logger's name.
-
-.Example 4
-[cols=",,,",options="header",]
-|=============================================================
-|Logger Name |Assigned LoggerConfig |LoggerConfig Level |level
-|root |root |DEBUG |DEBUG
-|X |X |ERROR |ERROR
-|X.Y |X |ERROR |ERROR
-|X.Y.Z |X |ERROR |ERROR
-|=============================================================
-
-In example 4, the loggers `root` and `X` each have a Configured
-LoggerConfig with the same name. The loggers `X.Y` and `X.Y.Z` do not
-have configured LoggerConfigs and so get their Level from the
-LoggerConfig assigned to them, `X`, since it is the LoggerConfig whose
-name has the longest match to the start of the Logger's name.
-
-.Example 5
-[cols=",,,",options="header",]
-|=============================================================
-|Logger Name |Assigned LoggerConfig |LoggerConfig Level |level
+|===
+
+.All loggers are configured with a level, except loggers `X.Y` and `X.Y.Z`
+[%header,cols="1m,1m,1m,1m"]
+|===
+|Logger name |Assigned `LoggerConfig` |Configured level |Effective level
|root |root |DEBUG |DEBUG
|X |X |ERROR |ERROR
-|X.Y |X.Y |INFO |INFO
-|X.YZ |X |ERROR |ERROR
-|=============================================================
-
-In example 5, the loggers `root`.`X`, and `X.Y` each has a configured
-LoggerConfig with the same name. The logger `X.YZ` does not have
-configured LoggerConfig and so gets its Level from the LoggerConfig
-assigned to it, `X`, since it is the LoggerConfig whose name has the
-longest match to the start of the Logger's name. It is not associated
-with LoggerConfig `X.Y` since tokens after periods must match exactly.
-
-.Example 6
-[cols=4*,options="header"]
+|X.Y |X | |ERROR
+|X.Y.Z |X | |ERROR
+|===
+
+.All loggers are configured with a level, except the logger `X.YZ`
+[%header,cols="1m,1m,1m,1m"]
|===
-|Logger Name |Assigned LoggerConfig |LoggerConfig Level |Level
+|Logger name |Assigned `LoggerConfig` |Configured level |Effective level
|root |root |DEBUG |DEBUG
|X |X |ERROR |ERROR
-|X.Y |X.Y | |ERROR
-|X.Y.Z |X.Y | |ERROR
+|X.Y |X.Y |INFO |INFO
+|X.YZ |X | |ERROR
|===
+====
-In example 6, LoggerConfig X.Y has no configured level so it inherits
-its level from LoggerConfig X. Logger X.Y.Z uses LoggerConfig X.Y since
-it doesn't have a LoggerConfig with a name that exactly matches. It too
-inherits its logging level from LoggerConfig X.
+For further information on log levels and using them for filtering purposes in a configuration, see xref:manual/customloglevels.adoc[].
-The table below illustrates how Level filtering works. In the table,
-the vertical header shows the Level of the LogEvent, while the horizontal
-header shows the Level associated with the appropriate LoggerConfig. The
-intersection identifies whether the LogEvent would be allowed to pass
-for further processing (Yes) or discarded (No).
+[#Filter]
+== `Filter`
-[cols=8*,options="header"]
-|===
-|Event Level
-7+|LoggerConfig Level
+In addition to <<LoggerConfig,the level-based filtering facilitated by `LoggerConfig`>>, Log4j provides link:../javadoc/log4j-core/org/apache/logging/log4j/core/Filter.html[`Filter`]s to evaluate the parameters of a logging call (i.e., context-wide filter) or a log event, and decide if it should be processed further in the pipeline.
-| |`TRACE` |`DEBUG` |`INFO` |`WARN` |`ERROR` |`FATAL` |`OFF`
+[#Filter-diagram]
+.`Filter` and other directly related classes
+[plantuml]
+....
+@startuml
-|`ALL` |❌ |❌ |❌ |❌ |❌ |❌ |❌
+class Configuration {
+ Appender[] appenders
+ Filter[] filters
+ LoggerConfig[] loggerConfigs
+ LoggerConfig getLoggerConfig(String name)
+ StrSubstitutor substitutor
+}
-|`TRACE` |✅ |❌ |❌ |❌ |❌ |❌ |❌
+Configuration --> "0..*" Filter
-|`DEBUG` |✅ |✅ |❌ |❌ |❌ |❌ |❌
+Configuration --> "0..*" LoggerConfig
-|`INFO` |✅ |✅ |✅ |❌ |❌ |❌ |❌
+class Filter #line.bold {
+ Result filter(LogEvent)
+}
-|`WARN` |✅ |✅ |✅ |✅ |❌ |❌ |❌
+class LoggerConfig {
+ AppenderRef[] appenderRefs
+ AppenderControl[] appenderControls
+ Level level
+ Filter filter
+ void log(LogEvent)
+}
-|`ERROR` |✅ |✅ |✅ |✅ |✅ |❌ |❌
+LoggerConfig --> "0..*" AppenderRef
-|`FATAL` |✅ |✅ |✅ |✅ |✅ |✅ |❌
+LoggerConfig -[#green,thickness=6]-> "0..*" AppenderControl
-|`OFF` |✅ |✅ |✅ |✅ |✅ |✅ |✅
-|===
+LoggerConfig --> Filter
+
+class AppenderRef {
+ String appenderName
+ Level level
+ Filter filter
+}
+
+AppenderRef --> Filter
+
+AppenderControl --> Filter
+
+@enduml
+....
+
+Refer to xref:manual/filters.adoc[] for further information.
+
+[#Appender]
+== `Appender`
+
+link:../javadoc/log4j-core/org/apache/logging/log4j/core/Appender.html[`Appender`]s are responsible for delivering a link:../javadoc/log4j-core/org/apache/logging/log4j/core/LogEvent.html[`LogEvent`] to a certain target; console, file, database, etc.
+While doing so, they typically use <<Layout>>s to encode the log event.
+See xref:manual/appenders.adoc[] for the complete guide.
+
+[#Appender-diagram]
+.`Appender` and other directly related classes
+[plantuml]
+....
+@startuml
+
+class Configuration {
+ Appender[] appenders
+ Filter[] filters
+ LoggerConfig[] loggerConfigs
+ LoggerConfig getLoggerConfig(String name)
+ StrSubstitutor substitutor
+}
-=== Filter
-
-In addition to the automatic log Level filtering that takes place as
-described in the previous section, Log4j provides
-link:../javadoc/log4j-core/org/apache/logging/log4j/core/Filter.html[`Filter`]s
-that can be applied before control is passed to any LoggerConfig, after
-control is passed to a LoggerConfig but before calling any Appenders,
-after control is passed to a LoggerConfig but before calling a specific
-Appender, and on each Appender. In a manner very similar to firewall
-filters, each Filter can return one of three results, `Accept`, `Deny`
-or `Neutral`. A response of `Accept` means that no other Filters should
-be called and the event should progress. A response of `Deny` means the
-event should be immediately ignored and control should be returned to
-the caller. A response of `Neutral` indicates the event should be passed
-to other Filters. If there are no other Filters the event will be
-processed.
-
-Although an event may be accepted by a Filter the event still might not
-be logged. This can happen when the event is accepted by the
-pre-LoggerConfig Filter but is then denied by a LoggerConfig filter or
-is denied by all Appenders.
-
-=== Appender
-
-The ability to selectively enable or disable logging requests based on
-their logger is only part of the picture. Log4j allows logging requests
-to print to multiple destinations. In log4j speak, an output destination
-is called an
-link:../javadoc/log4j-core/org/apache/logging/log4j/core/Appender.html[`Appender`].
-Currently, appenders exist for the console, files, remote socket
-servers, Apache Flume, remote UNIX Syslog daemons, and various
-database APIs. See the section on xref:manual/appenders.adoc[Appenders] for
-more details on the various types available. More than one Appender can
-be attached to a Logger.
-
-An Appender can be added to a Logger by calling the
-link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/Configuration.html#addLoggerAppender(org.apache.logging.log4j.core.Logger,%20org.apache.logging.log4j.core.Appender)[`addLoggerAppender`]
-method of the current Configuration. If a LoggerConfig matching the name
-of the Logger does not exist, one will be created, and the Appender will be
-attached to it and then all Loggers will be notified to update their
-LoggerConfig references.
-
-*Each enabled logging request for a given logger will be forwarded to
-all the appenders in that Logger's LoggerConfig as well as the Appenders
-of the LoggerConfig's parents.* In other words, Appenders are inherited
-additively from the LoggerConfig hierarchy. For example, if a console
-appender is added to the root logger, then all enabled logging requests
-will at least print on the console. If in addition a file appender is
-added to a LoggerConfig, say _C_, then enabled logging requests for _C_
-and _C_'s children will print in a file _and_ on the console. It is
-possible to override this default behavior so that Appender accumulation
-is no longer additive by setting `additivity="false"` on the Logger
-declaration in the configuration file.
-
-The rules governing appender additivity are summarized below.
-
-Appender Additivity::
-The output of a log statement of Logger _L_ will go to all the
-Appenders in the LoggerConfig associated with _L_ and the ancestors of
-that LoggerConfig. This is the meaning of the term "appender
-additivity".
-+
-However, if an ancestor of the LoggerConfig associated with Logger
-_L_, say _P_, has the additivity flag set to `false`, then _L_'s
-output will be directed to all the appenders in _L_'s LoggerConfig and
-it's ancestors up to and including _P_ but not the Appenders in any of
-the ancestors of _P_.
-+
-Loggers have their additivity flag set to `true` by default.
-
-The table below shows an example:
+Configuration --> "0..*" Filter
+Configuration --> "0..*" Appender
+
+Configuration --> "0..*" LoggerConfig
+
+class Appender #line.bold {
+ Layout layout
+ void append(LogEvent)
+}
+
+Appender -[#green,thickness=6]-> Layout
+
+class Layout {
+ byte[] encode(LogEvent)
+}
+
+class Filter {
+ Result filter(LogEvent)
+}
+
+class LoggerConfig {
+ AppenderRef[] appenderRefs
+ AppenderControl[] appenderControls
+ Level level
+ Filter filter
+ void log(LogEvent)
+}
+
+LoggerConfig --> "0..*" AppenderRef
+
+LoggerConfig -[#green,thickness=6]-> "0..*" AppenderControl
+
+LoggerConfig --> Filter
+
+class AppenderRef {
+ String appenderName
+ Level level
+ Filter filter
+}
+
+AppenderRef --> Filter
+
+class AppenderControl {
+ Appender appender
+ Filter filter
+ void append(LogEvent)
+}
+
+AppenderControl -[#green,thickness=6]-> Appender
+
+AppenderControl --> Filter
+
+@enduml
+....
+
+An `Appender` can be added to a <<Logger>> by calling the link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/Configuration.html#addLoggerAppender(org.apache.logging.log4j.core.Logger,%20org.apache.logging.log4j.core.Appender)[`addLoggerAppender()`] method of the current <<Configuration>>.
+If a <<LoggerConfig>> matching the name of the `Logger` does not exist, one will be created, and the `Appender` will be attached to it, and then all ``Logger``s will be notified to update their `LoggerConfig` references.
+
+[#appender-additivity]
+=== Appender additivity
+
+Each enabled logging request for a given logger will be forwarded to all the appenders in the corresponding ``Logger``'s `LoggerConfig`, as well as to the ``Appender``s of the ``LoggerConfig``'s parents.
+In other words, ``Appender``s are inherited *additively* from the `LoggerConfig` hierarchy.
+For example, if a console appender is added to the root logger, then all enabled logging requests will at least print on the console.
+If in addition a file appender is added to a `LoggerConfig`, say `LC`, then enabled logging requests for `LC` and ``LC``'s children will print in a file _and_ on the console.
+It is possible to override this default behavior so that appender accumulation is no longer additive by setting `additivity` attribute to `false` on xref:manual/configuration.adoc#configuring-loggers[the `Logger` declaration in the configuration file].
+
+The output of a log statement of `Logger` `L` will go to all the appenders in the `LoggerConfig` associated with `L` and the ancestors of that `LoggerConfig`.
+However, if an ancestor of the `LoggerConfig` associated with `Logger`
+`L`, say `P`, has the additivity flag set to `false`, then ``L``'s output will be directed to all the appenders in ``L``'s `LoggerConfig` and it's ancestors up to and including `P` but not the appenders in any of the ancestors of `P`.
+
+.Click for an example on appender additivity
+[%collapsible]
+====
+[#appender-additivity-diagram]
+.Example hierarchy of logger configurations to demonstrate appender additivity
+[plantuml]
+....
+@startmindmap
+* root
+** A
+*** A.B1 (additivity=false)
+**** A.B1.C
+***** A.B1.C.D
+*** A.B2.C
+**** A.B2.C.D (additivity=false)
+@endmindmap
+....
+
+In xref:#appender-additivity-diagram[xrefstyle=short], the effective appenders for each logger configuration are as follows:
+
+.Effective appenders of logger configurations in xref:#appender-additivity-diagram[xrefstyle=short]
+[cols="1c,1c,1c,1c,1c,1c,1c"]
|===
-|Logger Name |Added Appenders |Additivity Flag |Output Targets |Comment
-
-|root
-|A1
-|not applicable
-|A1
-|The root logger has no parent so additivity does not apply to it.
-
-|x
-|A-x1, A-x2
-|true
-|A1, A-x1, A-x2
-|Appenders of "x" and root.
-
-|x.y
-|none
-|true
-|A1, A-x1, A-x2
-|Appenders of "x" and root. It would not be typical to configure a Logger with no Appenders.
-
-|x.y.z
-|A-xyz1
-|true
-|A1, A-x1, A-x2, A-xyz1
-|Appenders in "x.y.z", "x" and root.
-
-|security
-|A-sec
-|false
-|A-sec
-|No appender accumulation since the additivity flag is set to `false`.
-
-|security.access
-|none
-|true
-|A-sec
-|Only appenders of "security" because the additivity flag in "security" is set to `false`.
+.2+^.^h| Appender
+6+^.h|Logger configuration
+
+| `A`
+| `A.B1`
+| `A.B1.C`
+| `A.B1.C.D`
+| `A.B2.C`
+| `A.B2.C.D`
+
+| `root`
+| ✅
+| ✅
+| ✅
+| ✅
+| ✅
+| ❌
+
+| `A`
+| ✅
+| ❌
+| ❌
+| ❌
+| ✅
+| ❌
+
+| `A.B1`
+| -
+| ✅
+| ✅
+| ✅
+| -
+| -
+
+| `A.B1.C`
+| -
+| -
+| ✅
+| ✅
+| -
+| -
+
+| `A.B1.C.D`
+| -
+| -
+| -
+| ✅
+| -
+| -
+
+| `A.B2.C`
+| -
+| -
+| -
+| -
+| ✅
+| ❌
+
+| `A.B2.C.D`
+| -
+| -
+| -
+| -
+| -
+| ✅
|===
+====
+
+[#Layout]
+== `Layout`
-=== Layout
+An <<Appender>> uses a *layout* to encode a link:../javadoc/log4j-core/org/apache/logging/log4j/core/LogEvent.html[`LogEvent`] into a form that meets the needs of whatever will be consuming the log event.
-More often than not, users wish to customize not only the output
-destination but also the output format. This is accomplished by
-associating a
-link:../javadoc/log4j-core/org/apache/logging/log4j/core/Layout.html[`Layout`]
-with an Appender. The Layout is responsible for formatting the LogEvent
-according to the user's wishes, whereas an appender takes care of
-sending the formatted output to its destination. The
-link:../javadoc/log4j-core/org/apache/logging/log4j/core/layout/PatternLayout.html[`PatternLayout`],
-part of the standard log4j distribution, lets the user specify the
-output format according to conversion patterns similar to the C language
-`printf()` function.
+[#Layout-diagram]
+.`Layout` and other directly related classes
+[plantuml]
+....
+@startuml
-For example, the PatternLayout with the conversion pattern "%r [%t] %-5p
-%c - %m%n" will output something akin to:
+class Appender {
+ Layout layout
+ void append(LogEvent)
+}
+Appender -[#green,thickness=6]-> Layout
+
+class Layout #line.bold {
+ byte[] encode(LogEvent)
+}
+
+@enduml
....
-176 [main] INFO org.foo.Bar - Located nearest gas station.
+
+Refer to xref:manual/layouts.adoc[] for details.
+
+[#StrSubstitutor]
+== `StrSubstitutor` et al.
+
+link:../javadoc/log4j-core/org/apache/logging/log4j/core/lookup/StrSubstitutor.html[`StrSubstitutor`] is a `String` interpolation tool that can be used in both configurations and components (e.g., appenders, layouts).
+It accepts an link:../javadoc/log4j-core/org/apache/logging/log4j/core/lookup/Interpolator.html[`Interpolator`] to determine if a key maps to a certain value.
+`Interpolator` is essentially a facade delegating to multiple link:../javadoc/log4j-core/org/apache/logging/log4j/core/lookup/StrLookup.html[`StrLookup`] (aka. _lookup_) implementations.
+
+[#StrSubstitutor-diagram]
+.`StrSubstitutor` et al. and other directly related classes
+[plantuml]
+....
+@startuml
+
+class Configuration {
+ Appender[] appenders
+ Filter[] filters
+ LoggerConfig[] loggerConfigs
+ LoggerConfig getLoggerConfig(String name)
+ StrSubstitutor substitutor
+}
+
+Configuration --> StrSubstitutor
+
+class StrSubstitutor #line.bold {
+ Interpolator interpolator
+ String replace(String input)
+}
+
+StrSubstitutor --> Interpolator
+
+class Interpolator {
+ StrLookup[] lookups
+ String lookup(String input)
+}
+
+Interpolator --> "0..*" StrLookup
+
+class StrLookup {
+ String lookup(String input)
+}
+
+@enduml
....
-The first field is the number of milliseconds elapsed since the start of
-the program. The second field is the thread making the log request. The
-third field is the level of the log statement. The fourth field is the
-name of the logger associated with the log request. The text after the
-'-' is the message of the statement.
-
-Log4j comes with many different xref:manual/layouts.adoc[Layouts] for various
-use cases such as JSON, XML, HTML, and Syslog (including the new RFC
-5424 version). Other appenders such as the database connectors fill in
-specified fields instead of a particular textual layout.
-
-Just as importantly, log4j will render the content of the log message
-according to user-specified criteria. For example, if you frequently
-need to log `Oranges`, an object type used in your current project, then
-you can create an OrangeMessage that accepts an Orange instance and pass
-that to Log4j so that the Orange object can be formatted into an
-appropriate byte array when required.
-
-=== StrSubstitutor and StrLookup
-
-The
-link:../javadoc/log4j-core/org/apache/logging/log4j/core/lookup/StrSubstitutor.html[`StrSubstitutor`]
-class and
-link:../javadoc/log4j-core/org/apache/logging/log4j/core/lookup/StrLookup.html[`StrLookup`]
-interface was borrowed from
-https://commons.apache.org/proper/commons-lang/[Apache Commons Lang] and
-then modified to support evaluating LogEvents. In addition the
-link:../javadoc/log4j-core/org/apache/logging/log4j/core/lookup/Interpolator.html[`Interpolator`]
-class was borrowed from Apache Commons Configuration to allow the
-StrSubstitutor to evaluate variables from multiple StrLookups. It
-too was modified to support evaluating LogEvents. Together these provide
-a mechanism to allow the configuration to reference variables coming
-from System Properties, the configuration file, the ThreadContext Map,
-StructuredData in the LogEvent. The variables can either be resolved
-when the configuration is processed or as each event is processed if
-the component is capable of handling it. See xref:manual/lookups.adoc[Lookups]
-for more information.
+See xref:manual/configuration.adoc#property-substitution[how property substitution works] and xref:manual/lookups.adoc[the predefined lookups] for further information.
diff --git a/src/site/antora/modules/ROOT/pages/manual/configuration.adoc b/src/site/antora/modules/ROOT/pages/manual/configuration.adoc
index 5d9b94627b..58d8e0dacc 100644
--- a/src/site/antora/modules/ROOT/pages/manual/configuration.adoc
+++ b/src/site/antora/modules/ROOT/pages/manual/configuration.adoc
@@ -438,7 +438,7 @@ Other logger configurations are optional.
Every
link:../javadoc/log4j-api/org/apache/logging/log4j/Logger.html[`Logger`]
in your application is assigned to one of these logger configurations (see
-xref:manual/architecture.adoc#loggerconfig[architecture]), which determines the events that will be logged and those that won't.
+xref:manual/architecture.adoc#LoggerConfig[architecture]), which determines the events that will be logged and those that won't.
Let's start with an example of logger configuration:
diff --git a/src/site/antora/modules/ROOT/pages/manual/customloglevels.adoc b/src/site/antora/modules/ROOT/pages/manual/customloglevels.adoc
index 2c98e3b478..42423e751a 100644
--- a/src/site/antora/modules/ROOT/pages/manual/customloglevels.adoc
+++ b/src/site/antora/modules/ROOT/pages/manual/customloglevels.adoc
@@ -14,6 +14,7 @@
See the License for the specific language governing permissions and
limitations under the License.
////
+
= Levels
Log levels are used to categorize log events by severity and control the verbosity of the logs.
@@ -44,6 +45,14 @@ Priority can be used in several contexts to express a filtering capability, for
The entry point to log levels are through link:../javadoc/log4j-api/org/apache/logging/log4j/Level.html[`Level`].
Predefined levels are available for Log4j API integrators through link:../javadoc/log4j-api/org/apache/logging/log4j/spi/StandardLevel.html[`StandardLevel`].
+[NOTE]
+====
+The `OFF` and `ALL` levels are not intended to be used on calls to the logging API.
+Specifying `OFF` in the configuration implies no logging events should match, while specifying `ALL` means all events match, including custom events.
+`OFF` can be used on logging API calls in special cases where the event should always be logged regardless of the configuration.
+However, it is generally recommended that a xref:manual/markers.adoc[marker] with a corresponding global xref:manual/filters.adoc#MarkerFilter[marker filter] be used instead.
+====
+
[#usage]
== [[StandardLoggerInterface]] Usage
@@ -57,39 +66,8 @@ LOGGER.log(Level.INFO, "Hello, {}!", userName); // <2>
<1> Using `Logger#info()` to log a message at `INFO` level
<2> Using `Logger#log()` to log a message and specifying the `INFO` level explicitly
-There are several ways levels can be employed in the Log4j configuration file for filtering purposes.
-Filtering on levels for loggers is a pretty common example:
-[source,xml]
-----
-<?xml version="1.0" encoding="UTF-8"?>
-<Configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns="https://logging.apache.org/xml/ns"
- xsi:schemaLocation="
- https://logging.apache.org/xml/ns
- https://logging.apache.org/xml/ns/log4j-config-2.xsd">
-
- <appenders>
- <Console name="CONSOLE">
- <JsonTemplateLayout/>
- </Console>
- </appenders>
-
- <loggers>
- <logger name="com.mycompany" level="INFO"/><!--1-->
- <root level="ERROR"><!--2-->
- <AppenderRef ref="CONSOLE"/>
- </root>
- </loggers>
-
-</Configuration>
-----
-<1> Logs of level `INFO` or higher severity (i.e., `WARN`, `ERROR`, `FATAL`) are allowed for `com.mycompany` package
-<2> Logs of level `ERROR` or higher severity (i.e., `FATAL`) are allowed for the rest
-
-[[top]]
-
[#DefiningLevelsInCode]
-== Defining custom log levels programmatically
+=== Custom log levels
Users can programmatically define custom levels using link:../javadoc/log4j-api/org/apache/logging/log4j/Level.html#forName(java.lang.String,int)[the `Level.forName()` method]:
@@ -122,45 +100,113 @@ public class PurchaseOrder {
----
<1> Logging with the created custom level
+[#config]
+== Configuration
+
+Levels can be used in various ways in a configuration file.
+We will explain some important ones from multiple logging implementations.
+
+[#config-core]
+=== Log4j Core
+
+Log4j Core, the reference implementation of Log4j API, has extensive support for levels.
+It allows both <<config-core-filter,basic level-based filtering>> and <<DefiningLevelsInConfiguration,custom log levels>>.
+
+[#config-core-filter]
+==== Basic filtering
+
+Filtering on levels for loggers is a pretty common example:
+
+[tabs]
+====
+XML::
++
+.Snippet from an example {antora-examples-url}/manual/customloglevels/filtering/log4j2.xml[`log4j2.xml`] configuring level-filtered loggers
+[source,xml]
+----
+include::example$manual/customloglevels/filtering/log4j2.xml[lines=14..19,indent=0]
+----
+
+JSON::
++
+.Snippet from an example {antora-examples-url}/manual/customloglevels/filtering/log4j2.json[`log4j2.json`] configuring level-filtered loggers
+[source,xml]
+----
+include::example$manual/customloglevels/filtering/log4j2.json[lines=9..22,indent=0]
+----
+
+YAML::
++
+.Snippet from an example {antora-examples-url}/manual/customloglevels/filtering/log4j2.yaml[`log4j2.yaml`] configuring level-filtered loggers
+[source,xml]
+----
+include::example$manual/customloglevels/filtering/log4j2.yaml[lines=24..31,indent=0]
+----
+
+Properties::
++
+.Snippet from an example {antora-examples-url}/manual/customloglevels/filtering/log4j2.properties[`log4j2.properties`] configuring level-filtered loggers
+[source,xml]
+----
+include::example$manual/customloglevels/filtering/log4j2.properties[lines=21..24]
+----
+====
+<1> Logs of level `INFO` or higher severity (i.e., `WARN`, `ERROR`, `FATAL`) are allowed for `com.mycompany` package
+<2> Logs of level `ERROR` or higher severity (i.e., `FATAL`) are allowed for the rest
+
[#DefiningLevelsInConfiguration]
-== Defining custom log levels in configuration
+==== Custom log levels
-Similar to defining log levels programmatically, a custom level must be defined first, before it can be used in a configuration file.
+Log4j Core, the reference implementation of Log4j API, requires a custom level to be defined first, before it can be used in a configuration file.
To facilitate this, the `CustomLevel` configuration element is used to define a custom level.
Internally it calls the same `Level.forName()` method discussed in <<DefiningLevelsInCode>>.
The following example shows a configuration that defines the `VERBOSE` custom log level and uses it to filter log events sent to the console.
+[tabs]
+====
+XML::
++
+.Snippet from an example {antora-examples-url}/manual/customloglevels/custom/log4j2.xml[`log4j2.xml`] configuring custom log levels
+[source,xml]
+----
+include::example$manual/customloglevels/custom/log4j2.xml[lines=17..26,indent=0]
+----
+
+JSON::
++
+.Snippet from an example {antora-examples-url}/manual/customloglevels/custom/log4j2.json[`log4j2.json`] configuring custom log levels
[source,xml]
----
-<?xml version="1.0" encoding="UTF-8"?>
-<Configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns="https://logging.apache.org/xml/ns"
- xsi:schemaLocation="
- https://logging.apache.org/xml/ns
- https://logging.apache.org/xml/ns/log4j-config-2.xsd">
-
- <CustomLevels><!--1-->
- <CustomLevel name="VERBOSE" intLevel="550"/>
- </CustomLevels>
-
- <appenders>
- <Console name="CONSOLE">
- <PatternLayout/>
- </Console>
- <File name="FILE" fileName="logs/app.log">
- <PatternLayout/>
- </File>
- </appenders>
-
- <loggers>
- <root level="TRACE">
- <AppenderRef ref="CONSOLE" level="VERBOSE" /><!--2-->
- <AppenderRef ref="FILE"/>
- </root>
- </loggers>
-
-</Configuration>
+include::example$manual/customloglevels/custom/log4j2.json[lines=13..32,indent=0]
----
+
+YAML::
++
+.Snippet from an example {antora-examples-url}/manual/customloglevels/custom/log4j2.yaml[`log4j2.yaml`] configuring custom log levels
+[source,xml]
+----
+include::example$manual/customloglevels/custom/log4j2.yaml[lines=27..37,indent=0]
+----
+
+Properties::
++
+.Snippet from an example {antora-examples-url}/manual/customloglevels/custom/log4j2.properties[`log4j2.properties`] configuring custom log levels
+[source,xml]
+----
+include::example$manual/customloglevels/custom/log4j2.properties[lines=24..30]
+----
+====
<1> Defining the `VERBOSE` custom log level
<2> Only events of `VERBOSE` level or higher severity are sent to the console
+
+[#config-logback]
+=== Logback
+
+{logback-url}[Logback] can be configured as follows to define level-filtered loggers:
+
+.Snippet from an example {antora-examples-url}/manual/customloglevels/filtering/logback.xml[`logback.xml`] configuring level-filtered loggers
+[source,xml]
+----
+include::example$manual/customloglevels/filtering/logback.xml[lines=29..32,indent=0]
+----
diff --git a/src/site/antora/modules/ROOT/pages/manual/extending.adoc b/src/site/antora/modules/ROOT/pages/manual/extending.adoc
index 679aabb23b..463269e16f 100644
--- a/src/site/antora/modules/ROOT/pages/manual/extending.adoc
+++ b/src/site/antora/modules/ROOT/pages/manual/extending.adoc
@@ -91,7 +91,7 @@ Yet when this happens, you can use xref:manual/systemproperties.adoc#log4j2.prov
[#LoggerContextFactory]
=== `LoggerContextFactory`
-link:../javadoc/log4j-api/org/apache/logging/log4j/spi/LoggerContextFactory.html[`LoggerContextFactory`] is the factory class used by Log4j API implementations to create xref:manual/architecture.adoc#logger-context[`LoggerContext`]s.
+link:../javadoc/log4j-api/org/apache/logging/log4j/spi/LoggerContextFactory.html[`LoggerContextFactory`] is the factory class used by Log4j API implementations to create xref:manual/architecture.adoc#LoggerContext[`LoggerContext`]s.
If you are using Log4j Core, you can provide a custom implementation using xref:manual/systemproperties.adoc#log4j2.loggerContextFactory[the `log4j2.loggerContextFactory` property].
Another way to provide a custom `LoggerContextFactory` is to <<Provider,provide a custom `Provider`>>.
But this is generally discouraged, since it requires a more complicated setup and is intended mostly to be used by Log4j API implementations.
@@ -105,7 +105,7 @@ It can be configured using xref:manual/systemproperties.adoc#log4j2.contextSelec
[#ConfigurationFactory]
=== `ConfigurationFactory`
-link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/ConfigurationFactory.html[`ConfigurationFactory`] is the factory class used by Log4j Core to create link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/Configuration.html[`Configuration`] instances given a xref:manual/architecture.adoc#logger-context[`LoggerContext`] and a link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/ConfigurationSource.html[`ConfigurationSource`].
+link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/ConfigurationFactory.html[`ConfigurationFactory`] is the factory class used by Log4j Core to create link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/Configuration.html[`Configuration`] instances given a xref:manual/architecture.adoc#LoggerContext[`LoggerContext`] and a link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/ConfigurationSource.html[`ConfigurationSource`].
You can provide a custom `ConfigurationFactory` in the form of a <<Custom_Plugins,plugin>>.
For example, see {project-github-url}/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfigurationFactory.java[`XmlConfigurationFactory.java`] and {project-github-url}/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfiguration.java[`XmlConfiguration.java`] of Log4j Core.
diff --git a/src/site/antora/modules/ROOT/pages/manual/markers.adoc b/src/site/antora/modules/ROOT/pages/manual/markers.adoc
index 0cc8f583f1..a52e36decb 100644
--- a/src/site/antora/modules/ROOT/pages/manual/markers.adoc
+++ b/src/site/antora/modules/ROOT/pages/manual/markers.adoc
@@ -100,9 +100,7 @@ complex hierarchies of markers where possible.
== Configuring filtering
Developers can use markers to filter the log statements delivered to log files.
-Marker processing is supported at least by
-https://logback.qos.ch/manual/filters.html[Logback]
-and the Log4j Core logging backends.
+Marker processing is supported at least by {logback-url}/manual/filters.html[Logback] and the Log4j Core logging implementations.
We will provide a sample configuration for both these backends.
[#log4j-core]
@@ -154,7 +152,7 @@ include::example$manual/markers/log4j2.properties[lines=17..-1]
Logback differentiates two kinds of filters: ``TurboFilter``s, which are applied before a log event is created, and
``Filter``s, which are applied only when a log event reaches an appender.
-See https://logback.qos.ch/manual/filters.html[Logback filters] for more information.
+See {logback-url}/manual/filters.html[Logback filters] for more information.
You can use a combination of `MarkerFilter`, `EvaluatorFilter` and `OnMarkerEvaluator` to redirect all messages marked with `SQL` to a specific appender, regardless of their level.
In order to do that, you can use a configuration as below: