| //// |
| 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. |
| //// |
| = Architecture |
| Ralph Goers <rgoers@apache.org> |
| |
| == 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 actually deliver the LogEvents. |
| |
| === 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]. |
| |
| === 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 |
| 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 exact 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 |
| |
| 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. |
| |
| http://logging.apache.org/log4j/1.2/manual.html[Log4j 1.x] and |
| http://logback.qos.ch/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 |
| |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 |
| |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 |
| |root |root |DEBUG |DEBUG |
| |X |X |ERROR |ERROR |
| |X.Y |X |ERROR |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 |
| 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 |
| |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 have 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"] |
| |=== |
| |Logger Name |Assigned LoggerConfig |LoggerConfig Level |Level |
| |root |root |DEBUG |DEBUG |
| |X |X |ERROR |ERROR |
| |X.Y |X.Y | |ERROR |
| |X.Y.Z |X.Y | |ERROR |
| |=== |
| |
| In example 6, LoggerConfig X.Y it 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. |
| |
| 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). |
| |
| [cols=8*,options="header"] |
| |=== |
| |Event Level |
| 7+|LoggerConfig Level |
| |
| | |`TRACE` |`DEBUG` |`INFO` |`WARN` |`ERROR` |`FATAL` |`OFF` |
| |
| |`ALL` |❌ |❌ |❌ |❌ |❌ |❌ |❌ |
| |
| |`TRACE` |✅ |❌ |❌ |❌ |❌ |❌ |❌ |
| |
| |`DEBUG` |✅ |✅ |❌ |❌ |❌ |❌ |❌ |
| |
| |`INFO` |✅ |✅ |✅ |❌ |❌ |❌ |❌ |
| |
| |`WARN` |✅ |✅ |✅ |✅ |❌ |❌ |❌ |
| |
| |`ERROR` |✅ |✅ |✅ |✅ |✅ |❌ |❌ |
| |
| |`FATAL` |✅ |✅ |✅ |✅ |✅ |✅ |❌ |
| |
| |`OFF` |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| |=== |
| |
| === 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, 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: |
| |
| |=== |
| |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`. |
| |=== |
| |
| === Layout |
| |
| 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. |
| |
| For example, the PatternLayout with the conversion pattern "%r [%t] %-5p |
| %c - %m%n" will output something akin to: |
| |
| .... |
| 176 [main] INFO org.foo.Bar - Located nearest gas station. |
| .... |
| |
| 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 were 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 that 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. |