jvz commented on code in PR #2716:
URL: https://github.com/apache/logging-log4j2/pull/2716#discussion_r1668960552
##########
src/site/antora/modules/ROOT/pages/manual/architecture.adoc:
##########
@@ -16,467 +16,848 @@
////
= 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
-{log4j2-url}/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].
-
-=== LoggerContext
-
-The
-link:../javadoc/log4j-core/org/apache/logging/log4j/core/LoggerContext.html[`LoggerContext`]
-acts as the anchor point for the Logging system. However, it is possible
-to have multiple active LoggerContexts in an application depending on
-the circumstances. More details on the LoggerContext are in the
-xref:manual/logsep.adoc[Log Separation] section.
-
-=== 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
-
-As stated previously, Loggers are created by calling
-{log4j2-url}/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
-{log4j2-url}/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
-{log4j2-url}/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
{log4j2-url}/manual/customloglevels.adoc[custom log
-levels]. Another mechanism for getting more granularity is to use
-{log4j2-url}/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
+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 --> "0..*" Logger
+
+package "Configuration" as c {
+
+ 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 --> Filter
+
+ Configuration --> "0..*" Appender
Review Comment:
The PlantUML [docs](https://plantuml.com/class-diagram) have some other
relation types you can use here like `o--` for aggregation and `*--` for
composition, though I've used the aggregation relation before to denote when
one class has an array or collection of another class. What you've done here,
though, is probably easier to understand for people who don't write UML
diagrams :)
##########
src/site/antora/modules/ROOT/pages/manual/architecture.adoc:
##########
@@ -16,467 +16,848 @@
////
= 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
-{log4j2-url}/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].
-
-=== LoggerContext
-
-The
-link:../javadoc/log4j-core/org/apache/logging/log4j/core/LoggerContext.html[`LoggerContext`]
-acts as the anchor point for the Logging system. However, it is possible
-to have multiple active LoggerContexts in an application depending on
-the circumstances. More details on the LoggerContext are in the
-xref:manual/logsep.adoc[Log Separation] section.
-
-=== 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
-
-As stated previously, Loggers are created by calling
-{log4j2-url}/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
-{log4j2-url}/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
-{log4j2-url}/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
{log4j2-url}/manual/customloglevels.adoc[custom log
-levels]. Another mechanism for getting more granularity is to use
-{log4j2-url}/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
+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 --> "0..*" Logger
+
+package "Configuration" as c {
+
+ 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 --> Filter
+
+ Configuration --> "0..*" Appender
+
+ Configuration --> "0..*" LoggerConfig
+
+ Configuration --> StrSubstitutor
+
+ class Appender {
+ AbstractManager manager
+ Layout layout
+ Filter filter
+ void append(LogEvent)
+ }
+
+ Appender --> Layout
+
+ Appender --> Filter
+
+ class Layout {
+ byte[] encode(LogEvent)
Review Comment:
Possibly worth noting the parent interface, `Encoder<LogEvent>`, which adds
a `void encode(LogEvent, ByteBufferDestination)` method, but that also requires
adding `ByteBufferDestination` to the diagram, and that might be getting too
deep into technical minutiae. What do you think?
##########
src/site/antora/modules/ROOT/pages/manual/layouts.adoc:
##########
@@ -557,6 +557,11 @@ include::partial$manual/plugin-preliminaries.adoc[]
Layouts are xref:manual/plugins.adoc[plugins] implementing
link:../javadoc/log4j-core/org/apache/logging/log4j/core/Layout.html[the
`Layout` interface].
If your layout is a `String`-based one, we recommend you to extend your plugin
class from
link:../javadoc/log4j-core/org/apache/logging/log4j/core/layout/AbstractStringLayout.html[`AbstractStringLayout`],
which contains convenience for some of the boilerplate code shared by
`String`-based layouts.
+While annotating your layout with `@Plugin`, you need to make sure that
+
+* It has a unique `name` attribute across all available `Layout` plugins
Review Comment:
Technically, it'd have to be a unique `name` attribute for all `Core`
category/namespace plugins as this name determines the XML element name it
aliases to. Had we used different categories for different plugin types, then
that would likely correspond to XML namespaces which would make the config file
more complicated to write.
##########
src/site/antora/modules/ROOT/pages/manual/plugins.adoc:
##########
@@ -14,244 +14,265 @@
See the License for the specific language governing permissions and
limitations under the License.
////
+
= Plugins
-Log4j 1.x allowed for extension by requiring class attributes on most of
-the configuration declarations. In the case of some elements, notably
-the PatternLayout, the only way to add new pattern converters was to
-extend the PatternLayout class and add them via code. One goal of Log4j
-2 is to make extending it extremely easy through the use of plugins.
-
-In Log4j 3.x, a plugin is declared by adding a `@Plugin` and `@Namespace`
annotation to the class declaration.
-During initialization the
-link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/Configuration.html[`Configuration`]
-will invoke the `PluginRegistry`
-to load the built-in Log4j plugins as well as any custom plugins. The
-`Injector` locates plugins by looking in the following places:
-
-1. Plugin collection classes on the classpath that are loaded by
java.util.ServiceLoader.
-These classes are generated automatically during the build (more details
below).
-2. (OSGi only) Serialized plugin listing files in each active OSGi
-bundle. A `BundleListener` is added on activation to continue checking
-new bundles after `log4j-plugins` has started. Bundles must register their
plugin collection
-class as an OSGi service.
-3. Serialized plugin listing files on the classpath. These files were
generated by
-the plugin annotation processor in Log4j 2 2.x. These are processed to allow
-compatibility.
-
-When multiple plugins use the same case-insensitive `name` within the same
plugin category, then which one is selected is determined first by the presence
of `@PluginOrder` annotations and then by the previously described plugin
loading order.
-For example, to override the `File` plugin which is provided by the built-in
`FileAppender` class, you would need to place your plugin in a JAR file in the
CLASSPATH ahead of`log4j-core.jar`.
-This is not recommended; plugin name collisions will cause a warning to be
emitted.
-Note that in an OSGi environment, the order that bundles are scanned for
plugins generally follows the same order that bundles were installed into the
framework.
-See
https://www.osgi.org/javadoc/r5/core/org/osgi/framework/BundleContext.html#getBundles()[`getBundles()`]
and
https://www.osgi.org/javadoc/r5/core/org/osgi/framework/SynchronousBundleListener.html[`SynchronousBundleListener`].
-In short, name collisions are even more unpredictable in an OSGi environment
without additional `@PluginOrder` usage.
-
-Plugin collection classes are generated by an annotation processor contained
-in the log4j-plugins artifact which will automatically scan your code for
-Log4j 2 plugins and generate a Java source file that references all the
-located plugins. It will also generate a
-META-INF/services/org.apache.logging.log4j.plugins.model.PluginService
-file in compliance with java.util.ServiceLoader.
-There is nothing extra that needs to be done to enable this;
-the Java compiler will automatically pick up the annotation processor on
-the class path unless you explicitly disable it.
-
-If annotation processing is disabled plugins may still be registered by either
-[loweralpha]
-.. manually providing a class that extends
`org.apache.logging.log4j.plugins.model.PluginService`
-and identifies all the plugins and also declaring a
-`META-INF/services/org.apache.logging.log4j.plugins.model.PluginService` file
-that provides the fully qualified name of the implemented class or
-.. adding another compiler pass to the build process that
-only handles annotation processing using the Log4j 2 annotation
-processor class,
-`org.apache.logging.log4j.plugin.processor.PluginProcessor`.
-To do this using Apache Maven, add the following execution to your
-_maven-compiler-plugin_ (version 2.2 or higher) build plugin:
-
-[source,xml]
+Log4j plugin system is the de facto extension mechanism embraced by various
Log4j Core components.
+Plugins make it possible for extensible components to _receive_ feature
implementations without any explicit links in between.
+It is analogous to a
https://en.wikipedia.org/wiki/Dependency_injection[dependency injection]
framework, but curated for Log4j-specific needs.
+
+[NOTE]
+====
+Log4j plugin system is implemented by Log4j Core, the logging implementation.
+It is deliberately not a part of the Log4j API to keep the logging API
footprint small.
+====
+
+[TIP]
+====
+Did you know about *xref:plugin-reference.adoc[], the documentation extracted
from the source code* of all predefined Log4j plugins?
+Like Javadoc, but specialized for plugins!
+====
+
+In this section we will give an overview of the Log4j plugin system by
answering certain questions:
+
+. <<#declare-plugin,How can you declare a plugin?>>
+. <<#core,How can you declare a plugin that needs to be represented in a Log4j
configuration file?>>
+. <<#plugin-registry,How can you register your plugin to Log4j?>>
+. <<#plugin-discovery,How does Log4j discover plugins?>>
+. <<#plugin-load,How can you load other plugins in a plugin?>>
+
+[#declare-plugin]
+== Declaring plugins
+
+A class can be declared as a plugin by adding a
link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/plugins/Plugin.html[`@Plugin`]
annotation, which is essentially composed of following attributes:
+
+`name`::
+Name of the plugin.
+It is recommended to be distinct among plugins sharing the same `category`.
Review Comment:
It's pretty important; you can disambiguate which plugin uses the name based
on plugin order I think, but they otherwise need to be unique in a category/
##########
src/site/antora/modules/ROOT/pages/manual/architecture.adoc:
##########
@@ -16,467 +16,848 @@
////
= 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
-{log4j2-url}/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].
-
-=== LoggerContext
-
-The
-link:../javadoc/log4j-core/org/apache/logging/log4j/core/LoggerContext.html[`LoggerContext`]
-acts as the anchor point for the Logging system. However, it is possible
-to have multiple active LoggerContexts in an application depending on
-the circumstances. More details on the LoggerContext are in the
-xref:manual/logsep.adoc[Log Separation] section.
-
-=== 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
-
-As stated previously, Loggers are created by calling
-{log4j2-url}/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
-{log4j2-url}/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
-{log4j2-url}/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
{log4j2-url}/manual/customloglevels.adoc[custom log
-levels]. Another mechanism for getting more granularity is to use
-{log4j2-url}/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
+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 --> "0..*" Logger
+
+package "Configuration" as c {
+
+ 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 --> Filter
+
+ Configuration --> "0..*" Appender
+
+ Configuration --> "0..*" LoggerConfig
+
+ Configuration --> StrSubstitutor
+
+ class Appender {
+ AbstractManager manager
+ Layout layout
+ Filter filter
+ void append(LogEvent)
+ }
+
+ Appender --> Layout
+
+ Appender --> Filter
+
+ 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. `AppenderControl`
+ 4. `Appender`
+ end note
+
+ class LoggerConfig {
+ AppenderControl[] appenderControls
+ Level level
+ Filter filter
+ void log(LogEvent)
+ }
+
+ LoggerConfig -[#green,thickness=6]-> "0..*" AppenderControl
+
+ LoggerConfig --> 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)
+ }
+}
+
+LoggerContext --> Configuration
+
+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()`
+
+class AbstractManager {
+}
+
+Appender -[#green,thickness=6]-> AbstractManager
+
+@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.
Review Comment:
Could be worth mentioning that `Logger` and `LoggerConfig` work via a bridge
pattern where `Logger` provides the API and `LoggerConfig` provides the
implementation. This is one key architectural constraint that allows for
reconfiguration without dropping any log events being processed at the time of
reconfiguration. It's also one of the reasons why many methods of manual
configuration of appenders and such is so hard to do properly and why we offer
various utility methods and configuration DSLs to sort of hide away the
lifecycle handling, concurrency, etc.
##########
src/site/antora/modules/ROOT/pages/manual/architecture.adoc:
##########
@@ -16,467 +16,848 @@
////
= 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
-{log4j2-url}/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].
-
-=== LoggerContext
-
-The
-link:../javadoc/log4j-core/org/apache/logging/log4j/core/LoggerContext.html[`LoggerContext`]
-acts as the anchor point for the Logging system. However, it is possible
-to have multiple active LoggerContexts in an application depending on
-the circumstances. More details on the LoggerContext are in the
-xref:manual/logsep.adoc[Log Separation] section.
-
-=== 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
-
-As stated previously, Loggers are created by calling
-{log4j2-url}/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
-{log4j2-url}/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
-{log4j2-url}/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
{log4j2-url}/manual/customloglevels.adoc[custom log
-levels]. Another mechanism for getting more granularity is to use
-{log4j2-url}/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
+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
Review Comment:
This UML diagram is pretty awesome!
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]