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ı <[email protected]> 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:
