Home » Logging Facades for Java | hot online

Logging Facades for Java | hot online

by admin
Logging Facades for Java |  hot online

After I discussed best practices and pitfalls in the first post about Java logging, I would now like to go into the use of logging in a large project. In this area, there are often problems between different logging frameworks, and merging the entire application logging can sometimes be difficult.

Advertisement

Hendrik Ebbers (@hendrikEbbers) is Java Champion, JCP Expert Group Member and has been awarded several times as Rockstar Speaker at JavaOne. With his own company Open Elements, Hendrik is currently helping to design the Hedera Hashgraph and make its services available to the public. Hendrik is a co-founder of JUG Dortmund and Cyberland and gives lectures and workshops on Java all over the world. His book “Mastering JavaFX 8 Controls” was published by Oracle Press in 2014. Hendrik is actively involved in open source projects such as JakartaEE or Eclipse Adoptium. Hendrik is a member of the AdoptOpenJDK TSC and the Eclipse Adoptium WG.

In order to understand the problem better, I’ll start with a very simple example, like the Hello World in logging. The following code shows a minimal Java application that simply logs a message:

public class HelloLogging {

private static final Logger LOG = Logger.getLogger(“HelloLogging”);

public static void main(final String[] args) {
LOG.info(“Hello World“);
}
}

Even in this trivial application, logging can be configured using the features of the logging framework, in the example java.util.Logging (JUL), and output to a file or the console (shell). The following diagram shows the structure and configuration of the logging in a schematic structure.

Advertisement

While the given structure works well for a small project, sometimes it becomes problematic once the first dependencies are added. Let’s imagine that we need two dependencies for our application: a library to ensure access to a database and another dependency on a security library to make our application safe from attacks. Since the developers of these libraries also want to output information about their status, usage and runtime errors, they also use logging. However, these libraries do not use java.util.Logging, but other logging libraries. As you can see in the diagram below, let’s assume that Log4J2 and Logback are in use.

See also  Is there still salvation for the dying e-bike startup?

Now we have the problem that our application’s logging is routed through three different logging frameworks. Log4J and Logback also offer enough configuration options, but since the logging frameworks do not synchronize with each other, it would be a very stupid idea to have all frameworks write to the same file. It can happen here that several of the frameworks write in the same line, resulting in an illegible heap of randomly lined-up text modules or even deadlocks. Another idea is that each framework logs to its own file, as indicated in the diagram below.

This structure means that the loggings act completely independently of each other and cannot get in each other’s way. This gives you clean logging, but it is spread across several files that you have to synchronize manually or with the help of tools. In addition, you always have to configure all existing logging systems if, for example, you want to activate a higher logging level to analyze the application. To make matters worse, there are more than two dependencies in a real project, which means that there can be significantly more logging frameworks in use.

Logging facades can help here. A facade can be used to separate the code from a concrete implementation. The Simple Logging Facade for Java (SLF4J) has clearly established itself as the standard here. SLF4J provides a logging API that comes as a single dependency with no transitive dependencies and can be easily plugged into pretty much any system. In this case, the API can be used to generate specific log calls in the code. The following code shows a “Hello World” logging example:

See also  Java: Oracle's GraalVM is now free for everyone

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class HelloLogging {

private static final Logger logger =
LoggerFactory.getLogger(HelloLogging.class);

public static void main(String[] args) {
logger.info(“Hello World!”);
}
}

If you just look at this code, you can ask yourself what advantages SLF4J should bring over classic Java logging. One of the most important points is that org.slf4j.Logger is an interface. The slf4j-api module, which contains the SLF4J-Api and thus the interface mentioned, does not provide an implementation of the interface. The entire module only defines the public API api of SLF4J, the logging facade.

To use them, we need to provide an implementation. To do this, a so-called binding must be added as a dependency, which provides an implementation of the logging facade. Such a binding usually forwards the logging events to a specific logging framework. For example, if you want to use Apache Commons Logging as a concrete logging implementation, you just have to add the slf4j-jcl-VERSION.jar module to the classpath. Such bindings are not required at compile time and can therefore be specified in Maven via runtime scope or in Gradle as a “RuntimeOnly” dependency. Since SLF4J uses the Java SPI internally, no code needs to be modified to use the concrete logging implementation. We can now use this feature for our sample application:

In the diagram, Log4J2 is used as the logging implementation, and by adding an appropriate binding, all log messages generated via the org.slf4j.Logger logger are automatically propagated to Log4J2. Since in this example our “Database lib” dependency obviously also uses Log4J2, the messages from various internal and external modules are handled directly via Log4J2. In addition to the bindings for special logging implementations, SLF4J also offers the library slf4j-simple, which offers a minimal implementation of SLF4J and outputs messages on the console (System.error).

See also  Tech Diary — July 2023

However, there is also a problem in the example: The “Security lib” used uses Logback as a logger and its messages therefore continue to end up in a different output. In such cases, so-called adapters for SLF4J can be used. These allow log messages sent directly to a logging API to be forwarded to SLF4J. Depending on the logging framework, there are completely different implementation approaches for such adapters. While SLF4J offers a few such adapters, some logging frameworks ship them directly. For example, for Log4J2, the following dependency needs to be added if you want to forward messages from Log4J2 to SLF4J:

org.apache.logging.log4j
log4j-to-slf4j

Adding this dependency, which is best added to the classpath only at runtime, results in a logging history like the one in the following graphic:

SLF4J offers a good overview of the integration of various logging libraries through bindings and adapters on their website.

Based on what we have learned, now looking at our example application, adding an adapter for logback can achieve our goal. As shown in the diagram below, all log messages from the entire system are routed via Log4J2 and we therefore have the advantage that we only have to document one central location.

(rme)

To home page

You may also like

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.

This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish. Accept Read More

Privacy & Cookies Policy