Levels
Log levels are used to categorize log events by severity and control the verbosity of the logs. They are one of many fish tagging capabilities provided by Log4j API. Using levels, you can filter out less important logs and focus on the most critical ones.
Log4j contains following predefined levels:
Name | Priority |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The Log4j API implementations, such as Log4j Core, can use |
A level is composed of a case-sensitive name and a priority (of type int
), which is used to define an order while comparing two.
Priority can be used in several contexts to express a filtering capability, for instance:
-
WARN
is less severe thanERROR
-
WARN
is less specific thanERROR
The entry point to log levels are through Level
.
Predefined levels are available for Log4j API integrators through StandardLevel
.
Usage
To assign a level to a log event you can use one of the variants of the
Logger.log(..)
and
Logger.atLevel(Level)
methods:
LOGGER.log(Level.INFO, "Hello {}!", username);
LOGGER.atLevel(Level.INFO).log("Hello {}!", username);
The Logger
interface also contains shorthand methods that always log at a specified log level:
Effective level | Shorthand methods |
---|---|
|
|
|
|
|
|
|
|
|
|
|
By using shorthand methods, you can rewrite the example above as:
LOGGER.info("Hello {}!", username);
LOGGER.atInfo().log("Hello {}!", username);
Which level to use?
While Log4j API defines a set of standard levels, it does not define the purpose of these levels. Many different conventions on which log levels to use coexist in the industry. When in doubt, you should ask your teammates about the convention used at your company. |
Most log level usage conventions divide log levels into two categories:
-
the most severe log levels (e.g.
FATAL
,ERROR
andWARN
) are used to inform the system administrator about a problem in the Java application that needs to be fixed. The more severe the problem, the more severe the log level.Log events with these levels should be used sparingly and should allow the system administrator to fix the problem.
-
the less severe log levels (e.g.
INFO
,DEBUG
,TRACE
) provide context that allow a system administrator or developer to diagnose the reason of an application failure. The most severe of them describe events that concern the whole application, while the less severe describe events that are interesting for a single sub-system.
Custom log levels
While most Java logging APIs adopt the same set of standard logging levels, some logging APIs, such as JUL and external logging systems, such as Syslog and OpenTelemetry support additional logging levels that can not be mapped to the standard ones.
To improve interoperability between logging systems, Log4j API supports custom log levels that can be defined using the
Level.forName()
method:
// OpenTelemetry additional INFO levels
private static final Level INFO2 = Level.forName("INFO2", 375);
private static final Level INFO3 = Level.forName("INFO3", 350);
private static final Level INFO4 = Level.forName("INFO4", 325);
Custom log levels can be used in your code with the usual Logger.log(..)
and Logger.atLevel(Level)
methods:
LOGGER.log(INFO2, "Hello {}!", username);
LOGGER.atLevel(INFO3).log("Hello {}!", username);
Implementation support
All logging implementations support filtering of log events, based on their log level, but the number of available log levels varies between implementations.
While most logging implementations support standard log levels, custom log levels are only supported by Log4j Core (and the EOL Log4j 1). To ensure independence from a specific logging implementation you should restrict your log statements to standard log levels. If you use custom log levels as a fish-tagging technique, you can use alternative fish-tagging features such as Markers, which are supported by multiple logging implementations. |
Log4j Core
The Log4j Core implementation fully supports both standard and custom levels.
Similarly to the Log4j API usage, custom levels must be defined in a configuration file before they can be used.
You can do it using
CustomLevel
configuration elements:
-
XML
-
JSON
-
YAML
-
Properties
log4j2.xml
<Appenders>
<Console name="CONSOLE">
<PatternLayout pattern="%d [%t] %p %c - %m%n"/>(1)
</Console>
</Appenders>
<CustomLevels>(4)
<CustomLevel name="INFO2" intLevel="375"/>
<CustomLevel name="INFO3" intLevel="350"/>
<CustomLevel name="INFO4" intLevel="325"/>
</CustomLevels>
<Loggers>
<Logger name="com.example" level="DEBUG"/>(2)
<Root level="INFO2">(5)
<AppenderRef ref="CONSOLE" level="WARN"/>(3)
</Root>
</Loggers>
log4j2.json
"Appenders": {
"Console": {
"name": "CONSOLE",
"PatternLayout": {
"pattern": "%d [%t] %p %c - %m%n" (1)
}
}
},
"CustomLevels": { (4)
"CustomLevel": [
{
"name": "INFO2",
"intLevel": 375
},
{
"name": "INFO3",
"intLevel": 350
},
{
"name": "INFO4",
"intLevel": 325
}
]
},
"Loggers": {
"Logger": {
"name": "com.example",
"level": "DEBUG" (2)
},
"Root": {
"level": "INFO2", (5)
"AppenderRef": {
"ref": "CONSOLE",
"level": "WARN" (3)
}
}
}
log4j2.yaml
Appenders:
Console:
name: "CONSOLE"
PatternLayout:
pattern: "%d [%t] %p %c - %m%n" (1)
CustomLevels: (4)
CustomLevel:
- name: "INFO2"
intLevel: 375
- name: "INFO3"
intlevel: 350
- name: "INFO4"
intLevel: 325
Loggers:
Logger:
name: "com.example"
level: "DEBUG" (2)
Root:
level: "INFO2" (5)
AppenderRef:
ref: "CONSOLE"
level: "WARN" (3)
log4j2.properties
appender.0.type = Console
appender.0.name = CONSOLE
appender.0.layout.type = PatternLayout
(1)
appender.0.layout.pattern = %d [%t] %p %c - %m%n
(4)
customLevel.INFO2 = 375
customLevel.INFO3 = 350
customLevel.INFO4 = 325
logger.0.name = com.example
(2)
logger.0.level = DEBUG
(5)
rootLogger.level = INFO2
rootLogger.appenderRef.0.ref = CONSOLE
(3)
rootLogger.appenderRef.0.level = WARN
1 | All the available Layouts support printing levels.
In the case of
Pattern Layout
you can use a %p or %level pattern. |
2 | Loggers support a level configuration attribute to filter log events. |
3 | A level attribute is also available in appender references. |
4 | Custom levels must be defined before they can be used. |
5 | Custom levels can be used anywhere a standard level can be used. |
SLF4J implementations (Logback)
Since SLF4J only supports five log levels (ERROR
, WARN
, INFO
, DEBUG
and TRACE
) and does not support custom log levels,
Log4j API levels are converted according to the following table:
Log4j level priority | Log4j standard levels | SLF4J Level |
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
JUL (java.util.logging
)
Similarly to Log4j API, java.util.logging
also supports custom log levels, but the current
Log4j-to-JUL bridge implementation does not take advantage of them.
The conversion of between Log4j log levels and JUL levels is performed accordingly to the following table:
Log4j level priority | Log4j standard levels | Java Level |
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|