Application and library use of Java System.Logger
logging facade.
<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-applog</artifactId>
<version>1.0</version>
</dependency>
If using module-path add a requires clause into module-info:
requires io.avaje.applog;
Use AppLog.getLogger()
rather than System.getLogger()
to obtain System.Logger
.
System.Logger logger = AppLog.getLogger("org.foo");
logger.log(Level.INFO, "Hello {0}", "world");
Using AppLog.getLogger()
rather than using System.getLogger()
gives applications an extra
option for controlling the System.Logger
implementation returned by AppLog. Typically, this
is useful in the case where application does not have a dedicated JVM where service loading
System.LoggerFinder
is not sufficient. One such environment currently is AWS Lambda Java runtime.
Defaults to using JDK System.getLogger()
but allows applications to provide an alternative
System.Logger implementation returned by AppLog.getLogger() by service loading a AppLog.Provider
.
Applications wanting control over the System.Logger implementation can firstly provide
a System.LoggerFinder
and have that loaded via ServiceLoader. This might not be possible
for applications that for example don't have a dedicated JVM.
Applications that can't use System.LoggerFinder
can instead use AppLog.Provider
to
control the System.Logger implementations returned by AppLog. The reason to use AppLog is
that it provides this 1 extra level of indirection that applications can use to control
the System.Logger implementation returned by AppLog.
We can add avaje-applog-slf4j
as a dependency such that System.Logger implementations
provided by AppLog.getLogger()
are slf4j-api Logger.
<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-applog-slf4j</artifactId>
<version>1.0</version>
</dependency>
System.Logger uses {@link java.text.MessageFormat} with placeholders like {0}, {1}, {2} ...
rather than slf4j which uses {}
. This means parameters can be referenced multiple times
and the parameters can use formats like {0,number,#.##} {0,time} {0,date}
etc.
See {@link java.text.MessageFormat} for more details.
By default, numbers are formatted based on locale so {@code 8080 } can be formatted as {@code 8,080}.
We often prefer to format integers like {0,number,#}
rather than {0}
.
// use {1,number,integer} to format the int port so we get 8080 rather than 8,080
logger.log(Level.INFO, "started with host {0} port {1,number,integer} ", host, port);
When logging a message with vararg parameters, slf4j will automatically try to detect if the last parameter is a Throwable and if so extract it and trim the parameters. System.Logger does not do this, instead we need to be explicit when logging Throwable and formatting the message if needed.
System.Logger logger = AppLog.getLogger("org.foo");
// using varargs parameters all ok with no Throwable
logger.log(Level.INFO, "My {0} Hello {1} message", "silly", "world");
try {
someMethodThatThrows();
} catch (Throwable e) {
// need to format message here and explicitly pass throwable
logger.log(Level.ERROR, MessageFormat.format("Error using {0} and {1}", "MyParam0", "OtherParam1"), e);
}