The new log4j 2.0
Before a while a new major version of the well known log4j logging framework was released. Since the first alpha version appeared 4 more releases happened!
You see, there is much more activity than with the predecessor log4j 1. And seriously, despite log4j 2s young age it is ways better.
This blog will give an overview on a few of the great features of Apache log4j 2.0.
Modern API
In old days, people wrote things like this:
if(logger.isDebugEnabled()) { logger.debug('Hi, ' + u.getA() + “ “ + u.getB()); }
Many have complained about it: it is very unreadable. And if one would forget the surrounding if-clause a lot of unnecessary Strings would be the result. These days String creation is most likely optimized by modern the JVM, but should we rely on JVM optimizations?
The log4j 2.0 team thought about things like that and improved the API. Now you can write the same like that:
logger.debug('Hi, {} {}', u.getA(), u.getB());
The new and improved API supports placeholders with variable arguments, as other modern logging frameworks do.
There is more API sweetness, like Markers and flow tracing:
private Logger logger = LogManager.getLogger(MyApp.class.getName()); private static final Marker QUERY_MARKER = MarkerManager.getMarker('SQL'); ... public String doQuery(String table) { logger.entry(param); logger.debug(QUERY_MARKER, 'SELECT * FROM {}', table); return logger.exit(); }
Markers let you identify specific log entries quickly. Flow Traces are methods which you can call at the start and the end of a method. In your log file you’ll would see a lot of new logging entries in trace level: your program flow is logged. Example on flow traces:
19:08:07.056 TRACE com.test.TestService 19 retrieveMessage - entry 19:08:07.060 TRACE com.test.TestService 46 getKey - entry
Plugin Architecture
log4j 2.0 supports a plugin architecture. Extending log4j 2 to your own needs has become dead-easy. You can build your extensions the namespace of your choice and just need to tell the framework where to look.
<configuration … packages='de.grobmeier.examples.log4j2.plugins'>
With the above configuration log4j 2 would look for plugins in the de.grobmeier.examples.log4j2.plugins package. If you have several namespaces, no problem. It is a comma separated list.
An simple plugin looks like that:
@Plugin(name = 'Sandbox', type = 'Core', elementType = 'appender') public class SandboxAppender extends AppenderBase { private SandboxAppender(String name, Filter filter) { super(name, filter, null); } public void append(LogEvent event) { System.out.println(event.getMessage().getFormattedMessage()); } @PluginFactory public static SandboxAppender createAppender( @PluginAttr('name') String name, @PluginElement('filters') Filter filter) { return new SandboxAppender(name, filter); } }
The method with the annotation @PluginFactory seves as, well, factory. The two arguments of the factory are directly read from the configuration file. I achieved that behavior with using @PluginAttr and @PluginElement on my arguments.
The rest is pretty trivial too. As I wrote an appender, I have chosen to extend AppenderBase. It forces me to implement the append() method which does the actual job. Besides Appenders, you can even write your own Logger or Filter. Just take a look at the docs.
Powerful Configuration
The new log4j 2 configuration has become easier. Don’t worry, if you could understand the old way to configure log4j, it will take you only a short time to learn the differences to the new way. It looks like that:
<?xml version='1.0' encoding='UTF-8'?> <configuration status='OFF'> <appenders> <Console name='Console' target='SYSTEM_OUT'> <PatternLayout pattern='%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n'/> </Console> </appenders> <loggers> <logger name='com.foo.Bar' level='trace' additivity='false'> <appender-ref ref='Console'/> </logger> <root level='error'> <appender-ref ref='Console'/> </root> </loggers> </configuration>
Please look at the appenders section. You are able to use speaking tags, f.e. matching the name of the appender. No more class names. Well, this XML document cannot be validated of course. In case you urgently need XML validation that, you can still use a more strict xml format, which reminds on the old format:
<appenders> <appender type='type' name='name'> <filter type='type' ... /> </appender> ... </appenders>
But that’s not all. You could even reload your configuration automatically:
<?xml version='1.0' encoding='UTF-8'?> <configuration monitorInterval='30'> ... </configuration>
The monitoring interval is a value in seconds, minimum value is 5. It means, log4j 2 would reconfigure logging in case something has changed in your configuration. If set to zero or left out, no change detection will happen. The best: log4j 2.0 does not lose logging events at the time of reconfiguration, unlike many other frameworks.
But there is even more exciting stuff. If you prefer JSON to XML, you are free to go with a JSON configuration:
{ 'configuration': { 'appenders': { 'Console': { 'name': 'STDOUT', 'PatternLayout': { 'pattern': '%m%n' } } }, 'loggers': { 'logger': { 'name': 'EventLogger', 'level': 'info', 'additivity': 'false', 'appender-ref': { 'ref': 'Routing' } }, 'root': { 'level': 'error', 'appender-ref': { 'ref': 'STDOUT' } } } } }
The new configuration is really powerful and supports things like property substitution. Check them more in detail on the manual pages.
log4j 2.0 is a team player: slf4j and friends
Apache log4j 2.0 has many integrations. It works well if your application still runs with Commons Logging. Not only that, you can use it with slf4j. You can bridge your log4j 1.x app to use log4j 2 in the background. And another opportunity: log4j 2 supports Apache Flume. Flume is a distributed, reliable, and available service for efficiently collecting, aggregating, and moving large amounts of log data.
Java 5 Concurrency
From the docs: “log4j 2 takes advantage of Java 5 concurrency support and performs locking at the lowest level possible.”. Apache log4j 2.0 does address many deadlock issues which are still in log4j 1.x. If you suffer from log4j 1.x memory leaks, you should definitely look at log4j 2.0.
Built at the Apache Software Foundation
As log4j 1.x, log4j 2.x is an Apache Software Foundation project. It means it is licensed with the “Apache License 2.0? and thus will stay free. You can build your own product upon it, you are free to modify it to your own needs and you can redistribute it, even commercially.
You don’t need to care on intellectual property. The Apache Software Foundation does care about that. If you would like to know more on licensing and how you can use log4j 2.0 for your own project, I refer you to the Licensing FAQ.
Reference: The new log4j 2.0 from our JCG partner Christian Grobmeier at the PHP und Java Entwickler blog.
I thought log4j was stagnated and no more active development is happening as the creators of log4j are concentrating on slf4j/logback. But what more features log4j2.0 have over slf4j/logback? curious to know.
So, how does log4j 2.0 stands up on blitz4j
blitz4j made improvements to log4j 1.x series. But log4j 2.x series is totally different, so you can’t directly compare them. Personally I would go with log4j2. Although blitz4j made obviously a good job, it still work arounds all the problems of log4j1.
:: Full circle :)
Now Log4j-2x AsynchAppender is 10 times faster logback & log4j-1x
http://logging.apache.org/log4j/2.x/manual/async.html#Performance
I had started migrating my applications from log4j to log4j2, but i had stuck up in one place where in we were using a custom log level .
Any idea on how to get this done in log4j2 ???
Maybe this can help: http://logging.apache.org/log4j/2.x/manual/customloglevels.html