2.1 First logger - log4j

As you already know, the history of logs began with System.err.println()the output of a record to the console. It is still actively used for debugging, for example, Intellij IDEA uses it to display error messages to the console. But this option does not have any settings, so let's move on.

The first and most popular logger was called Log4j. It was a good and highly customizable solution. Due to various circumstances, this decision never got into the JDK, which greatly upset the entire community.

This logger was not just able to log, it was created by programmers for programmers and allowed them to solve problems that constantly arose in connection with logging.

As you already know, logs are written in the end so that some person reads them and tries to understand what happened during the program's operation - what and when went wrong as expected.

There log4jwere three things for this:

  • subpackage logging;
  • set of appenders (results);
  • hot reload settings.

Firstly, the settings log4jcould be written in such a way as to enable logging in one package and disable it in another. For example, it was possible to enable logging in the com.codegym.server, but disable it in com.codegym.server.payment. This made it possible to quickly remove unnecessary information from the log.

Secondly, log4jit allowed writing logging results to several log files at once. And the output to each could be configured individually. For example, in one file it was possible to write only information about serious errors, in another - logs from a specific module, and in a third - logs for a certain time.

Each log file was thus tuned to a particular type of expected problem. This greatly simplifies the life of programmers who do not enjoy looking through gigabyte log files manually.

And finally, thirdly, log4jit allowed changing the log settings directly while the program was running, without restarting it. This was very handy when it was necessary to correct the work of the logs in order to find additional information on a specific error.

Important! There are two versions of the log log4j: 1.2.x and 2.xx , which are incompatible with each other .

You can connect the logger to the project using the code:

<dependencies>
  <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.17.2</version>
  </dependency>
 
  <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.17.2</version>
  </dependency>
</dependencies>

2.2 First official logger - JUL: java.util.logging

After the zoo of loggers appeared in the Java community, the developers JDKdecided to make one standard logger that everyone would use. This is how the logger appeared JUL: package java.util.logging.

However, during its development, the creators of the logger took as a basis not log4j, but a variant of the logger from IBM, which influenced its development. The good news is that the logger JULis included JDK, the bad news is that few people use it.

JUL

Not only did the developers JULmake “another universal standard” , they also made their own logging levels for it, which differed from those accepted by popular loggers at that time.

And that was a big problem. After all, products are Javaoften collected from a large number of libraries, and each such library had its own logger. So it was necessary to configure all the loggers that are in the application.

Although the logger itself is pretty good. Creating a logger is more or less the same. To do this, you need to import:


java.util.logging.Logger log = java.util.logging.Logger.getLogger(LoggingJul.class.getName());

The class name is specially passed in order to know where the logging is coming from.

Only with the release, the developers solved important problems, after which it JULis really convenient to use. Before that, it was some kind of second-rate logger.

This logger also supports lambda expressions and lazy evaluation. Starting with Java 8, you can pass Supplier<String>. This helps to read and create a string only at the moment when it is really needed, and not every time, as it was before.

Methods with an argument Supplier<String> msgSupplierlook like this:

public void info(Supplier msgSupplier) {
   log(Level.INFO, msgSupplier);
}

2.3 First logger wrapper - JCL: jakarta commons logging

For a long time there was no single standard among loggers, it JULshould have become one, but it was worse log4j, so a single standard never appeared. But a whole zoo of loggers appeared, each of which wanted to become the same.

JCL

However, ordinary Java developers did not like that almost every library has its own logger and needs to be configured somehow in a special way. Therefore, the community decided to create a special wrapper over other loggers - this is howJCL: jakarta commons logging

And again, the project, which was created to be a leader, did not become one. You can't create a winner, you can only become a winner. The functionality JCLwas very poor and no one wanted to use it. The logger, designed to replace all loggers, met the same fate as it JULwas not used.

Although it has been added to many libraries released by the Apache community, the zoo of loggers has only grown.

2.4 First last logger - Logback

But that's not all. The developer log4jdecided that he was the smartest (well, after all, most people used his logger) and decided to write a new improved logger that would combine the advantages log4jof other loggers.

The new logger was called Logback. It was this logger that was supposed to become the future single logger that everyone would use. It was based on the same idea as in log4j.

You can connect this logger to the project using the code:


<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.6</version>
</dependency>

The differences were in Logback:

  • improved performance;
  • added native support slf4j;
  • expanded filtering option.

Another advantage of this logger was that it had very good default settings. And you had to configure the logger only if you wanted to change something in them. Also, the settings file was better adapted to corporate software - all its configurations were set as xml/.

By default, Logbackit does not require any settings and records all logs from the level DEBUGand above. If you need different behavior, it can be configured via xmlconfiguration:

<configuration>
    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>app.log</file>
        <encoder>
            <pattern>%d{HH:mm:ss,SSS} %-5p [%c] - %m%n</pattern>
        </encoder>
    </appender>
    <logger name="org.hibernate.SQL" level="DEBUG" />
    <logger name="org.hibernate.type.descriptor.sql" level="TRACE" />
    <root level="info">
        <appender-ref ref="FILE" />
    </root>
</configuration>

2.5 Latest universal logger - SLF4J: Simple Logging Facade for Java

How long can it be to find the golden mean...

In 2006, one of the creators log4jleft the project and decided to try again to create a universal logger. But this time it was not a new logger, but a new universal standard (wrapper) that allowed different loggers to interact together.

This logger was called slf4j — Simple Logging Facade for Java, it was a wrapper around log4j, JUL, common-loggins and logback. This logger solved a real problem - managing a zoo of loggers, so everyone immediately started using it.

We heroically solve the problems we create for ourselves. As you can see, progress has reached the point that we have created a wrapper over the wrapper ...

The wrap itself consists of two parts:

  • API, which is used in applications;
  • Implementations that are added as separate dependencies for each logger.

You can connect the logger to the project using the code:

<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.17.2</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.17.2</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j-impl</artifactId>
    <version>2.17.2</version>
</dependency>

It is enough to connect the correct implementation and that's it: the whole project will work with it.

2.6 Optimization in slf4j

Slf4jsupports all new features such as string formatting for logging . Before this there was such a problem. Let's say you want to print a message to the log:

log.debug("User " + user + " connected from " + request.getRemoteAddr());

There is a problem with this code. Suppose your application works on productionand does not write any to the log DEBUG-messages, however, the method log.debug()will still be called, and when it is called, the following methods will also be called:

  • user.toString();
  • request.getRemoteAddr();

Calling these methods slows down the application. Their call is needed only during debugging, but they are called anyway.

From the point of view of logic, this problem had to be solved in the logging library itself. And in the first version of log4j the solution came up:

if (log.isDebugEnabled()) {
    log.debug("User " + user + " connected from " + request.getRemoteAddr());
}

Instead of one line for the log, now it was necessary to write three. Which dramatically worsened the readability of the code, and lowered the popularity of log4j.

The logger slf4jwas able to slightly improve the situation by offering smart logging. It looked like this:

log.debug("User {} connected from {}", user, request.getRemoteAddr());

where {}denote the insertion of arguments that are passed in the method. That is, the first {}corresponds to user, the second {}to request.getRemoteAddr().

These parameters will be concatenated into a single message only if the logging level allows logging. Not perfect, but better than all the other options.

After that, SLF4Jit began to grow rapidly in popularity, at the moment this is the best solution.

Therefore, we will consider logging using the example of a bundle slf4j-log4j12.