Concepts
Pax Logging is not trivial bridge to different (3 actually) logging frameworks (Log4J1, Log4J2, Logback), it also provides SPI layer that allows users to extend any logging framework. The most clear usage is when user wants to provide custom appender that processes logging events.
Here’s a summary of logging concepts used by all/most popular logging frameworks and how these concepts map to what Pax Logging provides.
Logging events
Each time a method like log.info() is called in any code fragment, new logging event is created. This event is a representation of a fact that user wants to log some message/information. Each logging event has some information associated like timestamp, code location (if available), message, exception (if needed) and severity (importance) of the event.
Appenders
Appender is kind of processor that does something with the logging event - usually appending new information (typically a line) to a file.
Level and threshold
This is a bit confusing part. At first glance it looks trivial - when user wants to invoke logging method, he/she may use one of typical methods like info(), warn(), trace() or other.
Simply from this set of alternatives we can derive the concept of logging event level (or severity).
Let’s start with something we can treat as canonical - Syslog. Here are the level names and their numerical equivalents:
Table 1. Syslog levels
Numerical value | Severity/level name |
|---|---|
0 | Emergency |
1 | Alert |
2 | Critical |
3 | Error |
4 | Warning |
5 | Notice |
6 | Informational |
7 | Debug |
From the above, we can try to summarize:
Numerically higher level is less important.
A concept related to level is threshold. Without giving precise constraints, threshold is a limit for logging events. For the above, Syslog example, setting a threshold value to Warning means that we’re interested in events with Warning or (numerically) lower events.
Thus:
The higher (numerically) the threshold, the more logging events are processed. Less important events are processed.
Adding more confusion:
Logging frameworks (and APIs) used in pax-logging treat the level concept differently… Log4J1 has direct relation to Syslog levels, but it’s not a case with Log4J2 and java.util.logging. Here’s a table where Syslog and Log4J1 can be directly related. Placement of levels from other libraries is a bit arbitrary and related to logging level name equivalents.
Log4J1: constants in
org.apache.log4j.LevelclassLog4J2: values in
org.apache.logging.log4j.spi.StandardLevelenumLogback: constants in
ch.qos.logback.classic.Levelclassjava.util.logging: values injava.util.logging.LevelclassSlf4J: constants in
org.slf4j.spi.LocationAwareLoggerinterfaceOSGi: constants in
org.osgi.service.log.LogServiceinterface
Syslog | Log4J1 | Log4J2 | Logback | java.util.logging | SLF4J | OSGi |
|---|---|---|---|---|---|---|
0 - Emergency | Integer.MAX_VALUE - OFF | 0 - OFF | Integer.MAX_VALUE - OFF | Integer.MAX_VALUE - OFF |
|
|
0 - Emergency | 50000 - FATAL | 100 - FATAL |
| 1000 - SEVERE |
|
|
1 - Alert |
|
|
|
|
|
|
2 - Critical |
|
|
|
|
|
|
3 - Error | 40000 - ERROR | 200 - ERROR | 40000 - ERROR | 1000 - SEVERE | 40 - ERROR | 1 - ERROR |
4 - Warning | 30000 - WARN | 300 - WARN | 30000 - WARN | 900 - WARNING | 30 - WARN | 2 - WARNING |
5 - Notice |
|
|
|
|
|
|
6 - Informational | 20000 - INFO | 400 - INFO | 20000 - INFO | 800 - INFO, 700 - CONFIG | 20 - INFO | 3 - INFO |
7 - Debug | 10000 - DEBUG | 500 - DEBUG | 10000 - DEBUG | 500 - FINE | 10 - DEBUG | 4 - DEBUG |
7 - Debug | 5000 - TRACE | 600 - TRACE | 5000 - TRACE | 400 - FINER | 0 - TRACE |
|
|
|
|
| 300 - FINEST |
|
|
7 - Debug | Integer.MIN_VALUE - ALL | Integer.MAX_VALUE - ALL | Integer.MIN_VALUE - ALL | Integer.MIN_VALUE - ALL |
|
|
Notes and confusing parts:
Log4J1’s
OFFlevel matches numerical value of SyslogEmergencyleveljava.util.logging: there are too many less important levels (FINE, FINER, FINEST) and too little more critical ones (only SEVERE)
Syslog doesn’t define trace level, so its debug entry is duplicated to cover constants from logging frameworks
Syslog, Log4J2 and OSGi use increasing numerical level for decreasing event importance
Log4J1, java.util.logging and SLF4J use higher numerical levels for more important events
Mapping of java.util.logging levels to more popular level names is implemented in
org.ops4j.pax.logging.spi.support.BackendSupport.toJULLevel()OFFandALLspecial levels have to be treated carefully by pax-logging because the usage of numerical values is totally unintuitive.
Markers
Markers allow to pass/associate additional, dynamic information with logging operation itself. Just as logger name (category) and level are static aspects of the logger itself, marker is associated with single logging invocation (thus effectively with logging event). Single logger may be used to log message with or without marker and it’s up to specific implementation (Logback, Log4J2) to handle the marker accordingly.
For example, Log4J1 doesn’t support markers, so slf4j-log4j12 bridges to Log4J1 using org.slf4j.helpers.MarkerIgnoringBase abstract base class which simply ignores markers. Logback and Log4J2 implement full org.slf4j.spi.LocationAwareLogger with marker support.
Markers are used usually by implementation-specific filters and appenders:
filters may be configured to restrict logging statements to ones using (or not using) particular marker
some appenders may simply do not do anything if specific marker is (or is not) present (for example that’s the case with
ch.qos.logback.classic.boolex.OnMarkerEvaluatorthat may be attached toch.qos.logback.classic.net.SMTPAppender)
Finally, a marker may have parent (or child) marker(s) associated - making them something slightly more complex than single name.
In Pax Logging, org.ops4j.pax.logging.PaxLogger interface didn’t contain methods accepting markers. PAXLOGGING-160 passed marker as String attribute through thread-bound org.ops4j.pax.logging.PaxContext. PAXLOGGING-259 adds such methods to this interface.
Remember - in Pax Logging, it’s possible to use for example Log4J2 API to log information that’s effectively handled by Log4J1, so despite the API being aware of markers, they may not be used correctly by actual logging implementation. As consequence, isXXXEnabled(…, marker, …) methods may not be handled early in the process of logging.