The new log4j 2.0

By Christian Grobmeier

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.


Follow me on Twitter :-)

  • Emmanuel Lécharny

    Cool ! Going to test it on Apache Directory, we already use it in MINA.

    Anything to say about http://www.infoq.com/news/2012/12/bitz4j-netflix ?

  • http://www.grobmeier.de Christian Grobmeier

    Great to hear! If you have some feedback for us, we are happy about learning on your experiences. Blitz4j does address many issues in log4j 1.x. It does somehow wrap 1.x series. Would have love to see them joining Apache Logging. If you read in their description, they would not use blitz4j when they would start again – it is a workaround because they invested a lot of time in logj4 1.x. With log4j 2.x you should have all the issues fixed which have led to blitz4j.

  • Gustavo Fischer

    Hi, your English is not very understandable, is it translated automatically?

    That said, thanks for writing this post, made me interested in the new features of log4j.

  • http://www.grobmeier.de Christian Grobmeier

    I am afraid it is not automatically translated… anyway thanks for your interest in log4j 2.0

  • kanzenryu

    I guess you never heard of the logback project http://logback.qos.ch/

  • http://www.grobmeier.de Christian Grobmeier

    Sure, I have heard of logback. The log4j 2 team has closely looked at it and tried to make things we don’t like better. Personally I believe that a project developed within the Apache Software Foundation does bring many benefits. That said, Ceki (main developer of logback) is still a Apache Logging PMC member. Personally I expect further collaboration between projects. As a user will finally end up with choosing whatever is best for you. If you have a facade like slf4j in place you have that freedom.

  • James Carman

    Nice work!

  • John Burwell

    Why didn’t log4j 2 choose to use the Java5 printf semantic?

  • http://twitter.com/brindy brindy

    Is it OSGi friendly?

    Even better, can it be used as an OSGi LogService implementation?

  • http://www.grobmeier.de Christian Grobmeier

    @John: it is there, it is just a little hidden. We have an issue open to make printf like message formatting possible, which should be resolved pretty soon. Check this out: https://issues.apache.org/jira/browse/LOG4J2-133

  • http://www.grobmeier.de Christian Grobmeier

    @Brindy: There is some OSGi stuff configured: http://svn.apache.org/repos/asf/logging/log4j/log4j2/trunk/pom.xml So yes, it is OSGi “friendly”. I am afraid to say that I am not so good with OSGi so I can’t tell further. Your best bet is to ask that on the mailing list: http://logging.apache.org/log4j/2.x/mail-lists.html

  • Sam Wilson

    Hi,

    You do realize that, in your first example, the use of the message formatting (placeholders, etc.) does not eliminate the need for the code guard?

    The calls to u.getA() and u.getB() will still be evaluated, regardless of whether or not debug logging is enabled.

    So, you would need to write this:
    if(logger.isDebugEnabled()) {
    logger.debug(“Hi, {} {}”, u.getA(), u.getB());
    }

    It’s still an improvement over the original because it gets rid of all the message formatting (possibly letting you keep your log messages in i18n-friendly resource files).

    You still need the code guard, however.

  • http://www.grobmeier.de Christian Grobmeier

    @Sam: assuming that you would only return a reference from the getters and assuming there is not costly logic behind it, I believe it is OK in many cases to leave out the guard. But I agree, if you need all performance possible then returning references might become an issue. I have once made a little performance test if the performance would change if we would return references by default. It does. Here are the results http://s.apache.org/fluentlog4j That said, it is not longer so important as it was before to have these guards (I think).

  • FredTrellis

    logger.debug(“Hi, {} {}”, u.getA(), u.getB());

    NIH. How stupid.

    logger.debug(String.format(“”Hi, %s %s”, u.getA(), u.getB()));

    When re-usability is trumpeted so loudly, why the chuff does no-one actually do it?

  • Jose Fernandez

    @FredTrellis

    You’re right, NIH. SLF4J does it. It’s a variation on Java’s MessageFormat syntax.

  • http://www.grobmeier.de Christian Grobmeier

    One can write this:

    log.debug(new StringFormattedMessage("I have %,d %s widgets", num, size));

    This is not very readable, but at the moment we are working on improving things to make it look like:

    log.debug("I have %,d %s widgets", num, size);

    You can follow the progress here:
    https://issues.apache.org/jira/browse/LOG4J2-133

  • NickSharman

    @4a660fd4147131e9081e7e86c2271b09:disqus : It’s not purely NIH: the point of supplying the message as a template plus parameters is that the (expensive) string formatting isn’t done if debug tracing is not enabled. If you call String.format explicitly, the formatting is performed regardless. But there is some NIH in not simply reusing String.format’s notation in the template (and handing it off to String.format internally)

  • Calvin

    how about logback? wil you stop the development ?

  • grobmeier

    I am not involved in logback development. That said, logback remains active and will be developed further. Please note, there is a different team behind logback than behind log4j

  • imesh

    Can I use two different appenders and control two different log levels?

    Say, appender 1 log only fatal level logs

    appender 2 log all from debug level ?

    appender 1 is a log file.

    appender 2 is a server socket appender.

    Can anyone help me please?

  • grobmeier

    Please subscribe to the log4j user mailinglists were a lot of people are able to help you: http://logging.apache.org/log4j/2.x/mail-lists.html

  • Gustavo Ehrhardt

    Hi Christian!
    I do appreciate the Log4j2! The API is very simple and powerful

    Do you plan a date to a QA/Promoted release of the 2.x version?

    Thanks.

  • grobmeier

    Hi Gustavo! Currently we are voting on the ninth release of log4j2. Its labelled beta, but we are looking at quality. We don’t have a fixed date of a official “stable” release, but my guess is end of this summer. So far, it is already used by a few projects without bigger issues. Regards, Christian

  • Gustavo Ehrhardt

    Great!
    I’ll wait the official release to use the JDBCAppender.

    Thanks.

  • grobmeier

    Thats great to hear! I will surely write about the first stable on this blog, but you also can follow our blog: blogs.apache.org/logging and we are having a basic G+ site too. https://plus.google.com/b/104876804201453912446/104876804201453912446/posts