Wednesday, July 26, 2023

Why use Log4j logging vs System.out.println in Java? Answer

Printing messages to the console is an integral part of the development, testing, and debugging of a Java program. If you are working on a Server-side application, where you can not see what's going on inside the server, your only visibility tool is a log file; without logs, you can not do any debugging or see what's going on inside your application. Though, Java has a pretty handy System.out.println() method to print something on the console, which can also be routed to log file but not sufficient for a real-world Java application. 

If you are running a Java program in Linux or any UNIX-based system, Log4j or SLF4j or any other logging framework offers a lot more features, flexibility, and improvement on message quality, which is not possible using the System.out.println() statement.

I strongly discourage using System.out.println() or System.err.println() methods for printing anything in production quality code, its simply not acceptable, and you will learn why you should prefer to use Log4j over System.out.println() in this post.

By the way, if you are using modern IDE like Eclipse or Netbeans, you may get a warning while using System.out.println() for logging purposes, which is good, otherwise, you may end up with a scenario where some messages are going to log file while other going somewhere else, probably on a file where the console is redirected.

It's also a best practice to use the Logging framework while coding in Java, even books like Clean Code also suggest learning Log4j for logging. 



Why prefer Log4j over System.out.println

Many Java programmers have their own reason for using a logging framework like Log4j, java.util.Logger, SL4j, or even Apache Commons logging, but they all are better than using the System.out.println().  Though my advice is to prefer SLF4j over Log4j for logging in Java as discussed in that article.

Anyway, here are some of the reasons, which I think are enough to stop you using System.out.println() statements in production code:



1. Information segregation using Log Level
Any logging framework including Log4j, SL4J, logback, and java.util.logger allows you to log debugging information with a log level, later you can use that level as filtering criteria, I mean, you can disable messages belongs to one particular log level like you would be more concerned to see WARN messages than DEBUG messages in production.


2. Performance and Flexibility
The second point, which is related to the previous one is that the logging framework allows you to suppress messages from another logging level, for example, you can run your application in DEBUG mode in the test environment, but on ERROR mode in a production environment. 

This will not only generate fewer logs but also improves the performance of your application because of less logging, see 10 tips on logging in Java to learn more about this.

This is not possible with System.out.println() statements which can not be controlled by any configuration or dynamically at runtime using JMX or any watchdog facility.

On the other hand, you can change the log level for log4j based logger without restarting your application by using a watchdog thread, which monitors a location for updated log4j.xml, the configuration file for Apache Log4j. The java.util.Logger also allows you to change the logging level using JMX without restarting the server.


3. Better Log Messages
By using a Logging framework, you can produce better outputs and metadata, which will help during troubleshooting and debug. Most logging framework e.g. Log4j allows you to print formatted output by specifying a formatting pattern by using PatterLayout, which can include a timestamp, name of the class, the Thread which is executing code, etc.

All of this information can be really useful while debugging concurrent applications where the output from multiple threads is overlapping. You don't get these facilities when you use the System.out.println() statements for logging messages. 

What more, even Joshua Bloch has also suggested using a properly logging facility like java.util.Logger for logging in his classic book Effective Java, one of the must-read books for experienced Java programmers.

Using System.out or System.err rather than a dedicated logging facility makes it difficult to monitor the behavior of the program.

Example 1: The first Java program that a developer learns to write often looks like this:


public class MyClass

  public static void main(String[] args) {

    System.out.println("hello world");

  }

}

While most programmers go on to learn many nuances and subtleties about Java, a surprising number hang on to this first lesson and never give up on writing messages to standard output using System.out.println() statement. 

Well, this is Ok if you are writing small test programs but it certainly not right if you coding on a production system that lives with millions of users or trades.

Logging also affects performance in a big way, I have seen a live example where the support team left the production system on DEBUG level only to find the latency shoots up by 500 ms and users complaining about delayed execution. 



Log4j in Java application



That's all about why a Java programmer should use a Logging framework over System.out.println() statement in production code. As I said, it's perfectly ok if you are writing test programs and small applications but it's not Ok in your real-world Java application.

You might know that you can also use Log4j without XML configuration or property files if that will encourage you to use it overprint() statements. Though, formatted output with metadata, controlling log level at runtime are some of the features you certainly don't want to ignore.

P.S. - If you want to learn more best practices, you can also check my post on 10 Java Concurrency Best Practices, every Java developer should follow.

7 comments :

Ashish Agarwal said...

logging also provide some benefits like for error we can send mails or we can insert into database without some extra code for that.

javin paul said...

@Ashish, good points, Indeed, you can configure Log4j to insert log statements into database or send email.

Unknown said...

It would be great if you and other bloggers would write about Log4j 2. As you may know, Log4j-1.2 became End Of Life in 2015 and is no longer supported. That’s a nice way to say it is dead.

Log4j 2 on the other hand is actively being developed and is very much alive. Log4j 2 has some cool features like support for Java 8 lambdas, it is garbage-free(!) and performance-wise it runs circles around the competition (log4j-1.2, Logback and JUL).

There is a lot of interesting stuff to write about, take a look at its Async Loggers.

For us as an industry it is important to keep learning and switch to modern technology when something becomes outdated.

I think it’s great that bloggers like yourself help to make knowledge of modern Java technology available to many people!

javin paul said...

Hello @Remko, Sure, I'll write about Log4j 2. I have already used it as an asynchronous logging library, as you mentioned to improve performance of mission critical Java application. Though, this article is in general using logger over System.out.println, Log4j is just a symbolic representation for logging library. Thanks for suggestion though.

Balaji Manoharan said...

Very Good article. Though its simple when think about logging. But we think about performance its matters more.

javin paul said...

@Balaji, Indeed, performance is a big issue here, with logging you can always reduce logging to improve performance, btw, in practice attaining right balance of performance and logging is easier said than done.

Unknown said...

Logging can indeed be a cause of performance issues. Modern hardware is extremely fast, but old logging libraries (like Log4j 1.2 and Logback) suffer from lock contention. Log4j 2 has Async Loggers based on the LMAX Disruptor which makes a huge performance difference. Don't "log less", upgrade!

Post a Comment