What's new in Log4j 2.6
It’s been almost six months since we released Log4j 2.5, and we have a bunch of neat things added since then. The biggest change is that now you can operate Log4j in a garbage-free mode during steady state logging. Sounds a bit jargony? The basic idea here is that once your application is initialized and doing its thing (the steady state), logging no longer contributes towards memory pressure, thus you have more control over memory allocation and gargabe collection. Various Java performance gurus point out that logging tends to add a lot of overhead to applications, and one major reason is due to garbage generated by the logging framework. The less garbage objects generated by the framework, the less time your application needs to spend collecting said garbage.
In prior versions of Log4j (and every other major logging framework), various
temporary objects are created with each call to Logger.log()
. For instance,
the method Logger.info(String message, Object... args)
would allocate a
temporary array to hold the arguments passed to the method. In Log4j 2.6, we’ve
added unrolled versions of these methods up to 10 arguments. In contrast,
SLF4J 1.7.21 only provides up to two unrolled arguments.
Another source of garbage is the boxing of primitive values into their object
forms. For certain primitives and small values, these boxed values are already
cached by the JVM and don’t really add any overhead, but in general, you might
not want your application to allocate new Long
instances just to log user IDs.
A helper class has been added called Unbox
which can be used to convert a
primitive directly into a StringBuilder
that can be used (and re-used) by the
Logger
methods. For example:
That particular change is only the tip of the iceberg, but it is something
that was added to log4j-api. Do note that if you implement the Logger
or
ExtendedLogger
interfaces manually instead of inheriting from AbstractLogger
,
you will need to update your code. There were a large number of method additions
to these interfaces to accomodate garbage-free logging, so I encourage the use
of the abstract base classes. In order to take advantage of the new unrolled
methods, you’ll have to recompile your code, but I’m sure you do that all the
time anyways. Existing compiled code will still work (we take semantic
versioning of log4j-api seriously), but it will still use the varargs versions
of methods as expected.
One other important API addition to support garbage-free logging is the addition
of Logger.log(CharSequence)
style methods. For example, suppose you have code
that builds a StringBuilder
to format your own log message. Previously, this
would be converted to a String
which is an unnecessary allocation before it was
further used by another StringBuilder
later when formatting the log message to
a Layout
. Now you can log the StringBuilder
(or any CharSequence
) directly
and no intermediary String
is created to hold it.
When it comes to log4j-core, most of the commonly used appenders, layouts,
filters, lookups, etc., have been also made garbage-free. The primary technique
used to make this garbage-free is to re-use objects as much as possible as well
as caching these objects in ThreadLocal
s usually. However, this has major
implications to traditional web applications due to the use of thread pools and
the subsequent memory leaks caused by naively using ThreadLocal
in a web app.
Because of this, the use of ThreadLocal
s is disabled by default when deployed
in a servlet container. This can be overridden via the system propery
log4j2.is.webapp
with the value false
. Note that if you enable this in a web
app, you cannot undeploy or redeploy your web app without introducing memory
leaks. Instead, you’ll have to take down your whole servlet container and bring
it back up. When using projects like Spring Boot, this is a perfectly good
scenario to override the safe defaults. Another alternative is to deploy Log4j
directly to your server’s global libraries so that it isn’t part of any WAR
deployments (similar to how you should be using JDBC drivers).
Another API addition is the LogManager.shutdown()
method to manually
terminate Log4j. To support this in a custom Log4j provider, your LoggerContext
implementation must also implement Terminable
(only needed if your
LoggerContext
needs to have a terminate()
method).
One last thing of note is that we’ve improved the properties file syntax and support quite a bit in this release. This includes simplifications to the syntax as well as some bugfixes that only affected the properties format. There has been some experimental work done towards supporting log4j 1.x style properties files, but that particular feature hasn’t made it to a release yet. Despite the XML, JSON, and YAML formats being objectively better configuration file formats than the properties format, we’ll continue to improve properties support over time.
One last thing about configuration files: you can now merge multiple config files together to form a composite configuration!