ALERT Dec 16th 2021:
How to Fix Log4J Vulnerability.
ALERT Dec 18th 2021:
Log4J 2.16.0 is vulnerable to DoS attack. Switch to 2.17.0.
For more details:
Log4J 2.16.0 is Vulnerable to DoS. Switch to 2.17.0.
ALERT Dec 29th 2021: Log4J 2.17.0 is vulnerable to RCE attack. Switch to 2.17.1. For more details: Log4J 2.17.0 is Vulnerable to RCE. Upgrade to 2.17.1.
This article is an old post introducing SLF4J. You can
still refer it to learn more about SLF4J. For Log4J
vulnerability related posts, check these links:
After seeing so many students in last four years, I have decided to write
this article about the new loggers which are widely being used by the
industry. Almost all the university students I have seen are familiar with
Log4j 1.x (at least heard about it) but most of them even did not hear about
SLF4J and
Logback. The purpose of
this article is introducing SLF4J and Logback and convincing you towards
them. Before getting into the topic, be informed that Log4j 1.x is not being
maintained after August 5, 2015 and Ceki Gülcü the developer of Log4j
came up with the new tools SLF4J and Logback. Technically, Logback is an
enhanced successor of Log4j and performs better than Log4j.
He did a good job, but we have to move forward.
SLF4J – Simple Logging Facade for Java, as the name suggests it provides a
common interface for various Java loggers. The actual logger which you are
using to log the events can be Logback, Apache Commons Logging, JDK 1.4
Logging or Log4j (I am sure, I miss some more loggers). Since it quickly
becomes a standard, industry moves towards SLF4J. Especially most of the
libraries and frameworks are migrating to SLF4J because they do not need to
pack the logger within their own library but let the developers choose their
desired logger implementation. For example, if you have
slf4j-api.jar (API), slf4j-log4j12.jar (Connector) and log4j-1.x.jar (Implementation),
your logs will be logged using Log4j. If you replace the
slf4j-log4j12.jar and log4j-1.x.jar by slf4j-jdk14.jar,
your logs will be logged using java.util.logging.
Remember that SLF4J is not an alternative for Log4j; it is only a facade. If
you are developing a library or middleware, use SLF4J and the developers who
use your library will provide any implementations according to their
requirements. Using SLF4J as a facade to access other logger implementations
provide two major advantages.
1: Loose coupling between your project and the logger
If you directly use a logger in your code, your code directly has access to
the logger-specific classes. For example, if you use Log4j, an instance of
logger should be retrieved in all the classes using the following statement.
import org.apache.log4j.Logger;
...
static final Logger LOGGER = Logger.getLogger(MyClass.class);
Suppose if your uncle suggests replacing Log4j by JDK logger for some
strange reasons, you have to open all those 9,836 Java classes and replace
the above statement by something for JDK logger.
If you used Log4j with SLF4J, the only thing you need is replacing Log4j and
log4j-connector JAR files (or maven dependencies) by JDK logger connector
library. You do not want to touch any source files in order to replace your
logger.
2: Performance
SLF4J supports an advanced feature called parameterized logging which can
significantly improve logging performance for disabled logging statement.
For example, if you have a Log4j statement as shown below, your application
will perform String concatenation regardless of whether the message will be
logged or not.
int val = /* Definced the the runtime */;
logger.debug("Current value is " + val);
SLF4J provides parameterized logging methods which will construct the final
String only if the log has to be logged.
int val = 10;
logger.debug("Current value is {}", val);
There is a disadvantage too: using a logging facade in a standalone
application may slightly reduce the performance compared to native
implementation. This is where Logback comes into the stage. Logback is a
native implementation of SLF4J, so it performs better than other logger
implementations. Studies have shown that using SLF4J + Logback performs
better than SLF4J + Log4j (Reference). In my case, I always go with Logback for all of my standalone
applications. In the company I am working for, we distribute the libraries
only with SLF4J so that the clients have the choice on selecting the actual
logger implementation and we do not need to distribute a logger along with
our library.
Adding Logback to your project
Step 1:
Add the following dependencies. If you need the JAR files, download them
from this
link.
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j-version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${logback-version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback-version}</version>
</dependency>
Step 2:
Retrieve the logger instance using LoggerFactory.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
...
static final Logger LOGGER = LoggerFactory.getLogger(MyClass.class);
Step 3:
If you do not have a custom configuration, Logback will continue with its
default configuration. If you prefer to have a custom configuration, add
logback.xml to the classpath with a similar configuration.
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator" />
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>output.log</file>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE" />
</root>
</configuration>
For more details: Logback ConfigurationMigrating from Log4j to Logback
Step 1:
Remove the Log4j dependencies and add the Logback dependencies.
Step 2:
Retrieve the logger instance using
LoggerFactory.
Step 3:
If you have any fatal logs, change them to error because SLF4J does not
support fatal. If you still want to use something similar to fatal, use
markers.
Step 4:
Replace the log4j.xml by logback.xml. Use this online
tool, convert your existing Log4j configuration to Logback.
1 comments:
Write commentsGood article, well compared both the frameworks and covered the migration from one framework to another framework too.
ReplyI have also tried comparing the frameworks in my post here
EmoticonEmoticon