Migration from log4j
This chapter deals with the topic of migrating custom log4j components such as appenders or layouts to logback-classic.
Software which merely invokes log4j client API, that is the
Logger
or Category
classes in
org.apache.log4j
package, can be automatically
migrated to use SLF4J via the SLF4J migrator
tool.
From a broader perspective, log4j and logback-classic are
closely related. The core components, such as loggers, appenders
and layouts exist in both frameworks and serve identical
purposes. Similarly, the most important internal data-structure,
namely LoggingEvent
exists in both frameworks with
rather similar but non-identical implementations. Most of the
changes requried in migrating log4j components to logback-classic
are related to differences in implementation of the
LoggingEvent
class. Rest assured, these differences
are rather limited. If in spite of your best efforts you are
unable to migrate any given log4j component to logback-classic, do
post a question on the logback-dev
mailing list. A logback developper should be able to provide
guidance.
Migrating a log4j layout
Let us begin by migrating a hypothetcical and trivially simple log4j layout named TrivialLog4jLayout which returns the message contained in a logging events as the formatted message. Here is the code.
package chapter11; import org.apache.log4j.Layout; import org.apache.log4j.spi.LoggingEvent; public class TrivialLog4jLayout extends Layout { public void activateOptions() { // there are no options to activate } public String format(LoggingEvent loggingEvent) { return loggingEvent.getRenderedMessage(); } public boolean ignoresThrowable() { return true; } }
The logback-classic equivalent named TrivialLogbackLayout would be
package chapter11; import ch.qos.logback.classic.spi.LoggingEvent; import ch.qos.logback.core.LayoutBase; public class TrivialLogbackLayout extends LayoutBase<LoggingEvent> { public String doLayout(LoggingEvent loggingEvent) { return loggingEvent.getMessage(); } }
As you can see, in a logback-classic layout, the formatting
method is named doLayout
instead of
format
() in log4j. The ignoresThrowable
()
method is not needed and has no equivalent in logback-classic. Note
that a logback-classic layout must extend the
LayoutBase<LoggingEvent>
class.
The activateOptions
() method merits further
discussion. In log4j, a layout will have its
activateOptions
() method invoked by log4j
configurators, that is PropertyConfigurator
or
DOMConfigurator
just after all the options of the
layout have been set. Thus, the layout will have an oppurtunity to
check that its options are coherent and if so, proceed to fully
intialize itself.
In logback-classic, layouts must implement the LifeCycle
interface which includes a method called start
(). The
start
() method is the equivalent of log4j's
activateOptions
() method.
Migrating a log4j appender
Migrating an appender is quite similar to migrating layout. Here is a trivially simple appender called TrivialLog4jLayout which writes on the console the string returned by its layout.
package chapter11; import org.apache.log4j.AppenderSkeleton; import org.apache.log4j.spi.LoggingEvent; public class TrivialLog4jAppender extends AppenderSkeleton { protected void append(LoggingEvent loggingevent) { String s = this.layout.format(loggingevent); System.out.println(s); } public void close() { // nothing to do } public boolean requiresLayout() { return true; } }
The logback-classic equivalent named TrivialLogbackAppender would be written as
package chapter11; import ch.qos.logback.classic.spi.LoggingEvent; import ch.qos.logback.core.AppenderBase; public class TrivialLogbackAppender extends AppenderBase<LoggingEvent> { @Override public void start() { if (this.layout == null) { addError("No layout set for the appender named [" + name + "]."); return; } super.start(); } @Override protected void append(LoggingEvent loggingevent) { // note that AppenderBase.doAppend will invoke this method only if // this appender was successfully started. String s = this.layout.doLayout(loggingevent); System.out.println(s); } }
Comparing the two classes, you should notice that the contents
of the append
() method remains unchanged. The
requiresLayout
method is not used in logback and can
be removed. In logback, the stop
() method is the
equivalent of log4j's close
() method. However,
AppenderBase
in logback-classic, contains an nop
implementation for stop
which is sufficient for the
purposes of this trivial appender.