Logback is designed as a successor to the Log4J project, designed by Ceki Gulcu. Logback is faster and has a smaller footprint than all existing logging systems. Logback performs about ten times faster than Log4j on specific critical execution paths.

The Logger class in Logback-Classic natively implements the SLF4J API, so there is zero overhead when we call SLF4J’s Logger with logback-Classic as the underlying implementation. Using the SLF4J API greatly reduces the effort of switching logging frameworks.

1.Logback dependency

To run LogBack, you need to use three modules during the runtime of your application.

  • Logback-core: Provides the main classes and interfaces required by the other two modules.
  • Logback-classic: Natively implements the SLF4J API.
  • slf4j-apiLogback – the classicLoggerClass implements the SLF4J API. So we can switch back and forth between LogBack and other logging frameworks at any time.
  • logback-access(optional) : Integration with Servlet containers, such as Tomcat and Jetty, to provide remote logging capabilities.
<dependency>
	<groupId>ch.qos.logback</groupId>
	<artifactId>logback-core</artifactId>
	<version>1.2.10</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.10</version>
</dependency>
<dependency>
	<groupId>org.slf4j</groupId>
	<artifactId>slf4j-api</artifactId>
	<version>1.7.32</version>
</dependency>
Copy the code

Note that logback-classic automatically pulls in logback-core and SLf4J-API, so add the logback-classic dependency.

2. Start using Logback

2.1. Create and use recorders

After the dependencies are imported into the CLASspath, we can start logging in the application.

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

public class Main {
	public static void main(final String[] args) 
	{
		Logger logger = LoggerFactory.getLogger(Main.class);
		// OR 
		// Logger logger = LoggerFactory.getLogger("com.howtodoinjava.demo");

		logger.info("Info Message Logged !!!"); }}Copy the code
18:40:47. [the main] INFO 392 com. Howtodoinjava. Demo. Slf4j. The main - the INFO Message Logged!!!!!!Copy the code

Notice the class Main above. It imports the Logger and LoggerFactory classes defined in the SLF4J API. We use the static method LoggerFactory.getLogger() to get the Logger instance. We then use logger.info() to log the information. It supports the debug(),info(),* WARN (), and error()* methods.

The getLogger() method can take two types of arguments, a class type and a String. Both methods return a named logger corresponding to the parameter.

Note that we are not using any logBack specific packages or classes. This way, we have no direct dependence on Logback and can be replaced by other logging libraries without changing the code.

2.2. Parameterized messages

In practice, log information is not always a pure string. We need to record context data in files, such as object ids, custom error messages, and code.

These complex messages are typically created by attaching strings, which involve allocating memory, concatenating operations, and finally garbage collection when the message is printed and the object is no longer in use.

Sometimes, the string concatenation operations described above may not be necessary. For example, if we set the log level to INFO, the given debug log will not be printed in the log file, but the string concatenation will happen anyway. Such string concatenation is overhead and should be avoided.

logger.info("Article fecthed for id : " + 1 + " is : " + a.toString());
Copy the code

Logback eliminates unwanted concatenation with parameterized messages. These messages use curly braces {} as placeholders for the objects to be printed in the message.

Once Logback determines that it needs to print a log message, it sets up the log message by concatenating the original message and replacing the curly braces with the output of the Object.toString () method.

logger.info("Article fecthed for id : {} is : {}".1, article);
Copy the code

We can use parameterized messages to print any type of object or information, including exception stack traces.

3. The Logback configuration

Existing Log4j users can convert their log4j.properties files to logback.xml using our PropertiesTranslator web application.

3.1. Zero configuration default

By default, when the default configuration file is not found, Logback will add a ConsoleAppender to the root logger, which will log all messages in the console.

The format of the output is a pattern with PatternLayoutEncoder set to ‘%d{HH:mm: ss.sss}. Thread] [% % % 5 level logger {36}. MSG – % % n “. Also, by default, the root logger is assigned to the DEBUG level.

This is the equivalent configuration used by default.

<configuration debug="true">
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
  </appender>

  <root level="debug">
    <appender-ref ref="STDOUT" />
  </root>
</configuration>
Copy the code

3.2. Load the configuration file

The default configuration is enough to get us started and used for POC purposes. For production applications, however, we need to configure different file loggers at the appropriate logging level.

During startup, logback tries to find logback-test. XML or logback.xml in the classpath, in the same order. If the file is found, it will configure itself using the provided configuration file.

If you don’t have one in your classpath, It tries to find the classpath in the meta-inf/services/ch. Qos. Logback. Classic. Spi. The Configurator to file to locate the com. Qos. Logback. Classic. Spi. Configurato R interface implementation, programmatic configuration.

If no implementation of the file or Configurator is found, it configures itself with the default configuration, as described earlier.

Note that you can use a system called “logback. ConfigurationFile” attribute or launch parameters specify the location of the default configuration file. The value of this property can be a URL, a resource on the CLASspath, or the path to a file outside the application.

3.3. Check for initialization errors

If we face any errors during logback initialization, we can set debug=”true” in the Configuration TAB. This prints status information to the console as configuration is processed.

See the status information printed on the console for a given configuration file. We have created the appender STDOUT, but in the root logger we name it STDOUT_ONE. The printed log highlights this configuration problem in the console, with the message that an appender named [STDOUT1] cannot be found.

<configuration debug="true">
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">.</appender>

  <root level="debug">
    <appender-ref ref="STDOUT_ONE" />
  </root>
</configuration>
Copy the code
18:34:34, 556 | - INFOinCh. Qos. Logback. Classic. LoggerContext [default] - Could NOT find the resource logback - test. XML 18:34:34, 556 | - INFOinch.qos.logback.classic.LoggerContext[default] - Found resource [logback.xml] at File: / C: / devsetup gitrepo/opensource - examples/target/classes/logback. XML] 18:34:34, 675 | - INFOin ch.qos.logback.core.joran.action.AppenderAction - About to instantiate appender of type[ch. Qos. Logback. Core. ConsoleAppender] 18:34:34, 679 | - INFOinCh. Qos. Logback. Core. Joran. Action. AppenderAction - Naming appenders as [STDOUT] 18:34:34, 686 | - INFOin ch.qos.logback.core.joran.action.NestedComplexPropertyIA - Assuming default type [ch.qos.logback.classic.encoder.PatternLayoutEncoder] for[encoder] property 18:34:34, 708 | - INFOinCh. Qos. Logback. Classic. Joran. Action. RootLoggerAction - Setting the level of the ROOT logger to DEBUG 18:34:34, 708 | - the ERRORinch.qos.logback.core.joran.action.AppenderRefAction - Could not find an appender named [STDOUT1]. Did you define it below  instead of aboveinthe configuration file? 18:34:34, 708 | - ERRORin ch.qos.logback.core.joran.action.AppenderRefAction - See http://logback.qos.ch/codes.html#appender_order for more details.18:34:34, 708 | - INFOinCh. Qos. Logback. Classic. Joran. Action. ConfigurationAction - the End of the configuration. 18:34:34, 710 | - INFOinch.qos.logback.classic.joran.JoranConfigurator@ec756bd - Registering current configuration as safe fallback point 18:34:34, 712 | - WARNin Logger[com.howtodoinjava.demo.slf4j.Main] - No appenders present in context [default] for logger [com.howtodoinjava.demo.slf4j.Main].
Copy the code

3.4. Automatically reload the configuration file after the modification

Set scan=”true” to the configuration label to allow LogBack to scan for changes and automatically reconfigure when the configuration file changes.

In the background, a *ReconfigureOnChangeTask* runs in a separate thread and checks the configuration file at a defined interval. If the latest version of the configuration file has XML syntax errors, it returns to the previous configuration file that has no XML syntax errors.

By default, the configuration file is scanned for changes every minute. To specify different scan periods, set the scanPeriod property.

<configuration scan="true" scanPeriod="120 seconds" >.</configuration>  
Copy the code

If no time unit is specified, the time unit is assumed to be milliseconds.

3.5. Conditional Configuration

Instead of defining multiple profiles for different requirements, we can put all the profiles in one file and add conditions around the related sections with the help of if, THEN, and else tags.

For example, a given configuration will configure a console appender in the local development environment and enable debug logging. Otherwise, the root logger will append all error information to the provided file.

  <if condition='property("ENV").contains("localhost")'>
    <then>
      <appender name="CON" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
          <pattern>%d %-5level %logger{35} - %msg %n</pattern>
        </encoder>
      </appender>
      <root level="DEBUG">
        <appender-ref ref="CON" />
      </root>
    </then>
  </if>

  <root level="ERROR">
     <appender-ref ref="FILE" />
  </root>
Copy the code

Note that conditional processing requires the Janino library.

4. Configure the application

Logback delegates the writing of logging events to a component called Appenders. Appenders is responsible for exporting log events to the appropriate output device in the appropriate format. However, they can delegate the actual formatting of the event to a Layout or Encoder object.

The very basic structure of a Logback configuration file can be described as a configuration element, consisting of zero or more appender elements, followed by zero or more Logger elements, followed by at most one root element.

The configuration file must be a well-formed XML file, and all open tags must be closed properly.

Label names associated with explicit rules are case insensitive. Few labels associated with implicit rules are case sensitive, except for the first letter. So, as a best practice, just follow the camelCase convention, which is almost always the right convention.

4.1. ConsoleAppender

The console appender appends on the console or, more accurately, on System.out or System.err.

Logback, by default, configates the console application to DEBUG level. We can configure the appender properties by defining them in the logback.xml file.

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
	<encoder>
		<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
	</encoder>
</appender>

<root level="INFO">
	<appender-ref ref="STDOUT" />
</root>
Copy the code

4.2. Scroll the file Appender

The file attach attaches log events to a file. If the file already exists, it will either be appended to or truncated, depending on the value of the Append attribute.

To log to scrolling files (based on time, log file size, or a combination of both), we use RollingFileAppender. The RollingPolicy is responsible for the actions required to roll, and the TriggeringPolicy determines if and when the roll occurs.

RollingPolicy implements the TriggeringPolicy interface, so if we only define RollingPolicy, we will accept the configuration as well.

<appender name="FILE"
	class="ch.qos.logback.core.rolling.RollingFileAppender">
	<file>${LOG_ROOT}/app.log</file>
	<append>true</append>
	<immediateFlush>false</immediateFlush>
	<rollingPolicy
		class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
		<! -- Archiving daily -->
		<fileNamePattern>${LOG_ROOT}/app-%d{yyyy-MM-dd}.log.gz</fileNamePattern>
		<! -- Archiving 60 days of logs and max 10GB size limit -->
		<maxHistory>60</maxHistory>
		<totalSizeCap>10GB</totalSizeCap>
	</rollingPolicy>
	<encoder>
		<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n
		</pattern>
	</encoder>
</appender>

<root level="INFO">
	<appender-ref ref="FILE" />
</root>
Copy the code

Logback’s FileAppender and all of its subclasses, including RollingFileAppender, can be gracefully recovered from I/O failures. Therefore, if a file server fails temporarily, we no longer need to restart the application to make logging work again. As soon as the file server is back to normal, the logger will work again.

With the RollingFileAppender, compression always happens asynchronously, so applications don’t get blocked during compression, even for large log files.

By default, each logging event is flushed immediately to the underlying output stream. In the case of very high log throughput, we could set the immediateFlush property to false.

5. Faqs

5.1. How do I print the Jar file name in the log

Once configured, LogBack can include packaged data (the name and version of the JAR file) in each of the stack trace lines it outputs. It helps debug to identify classcastExceptions caused by multiple versions of jars for any library in the classpath.

By default, wrapping data is disabled.

<configuration packagingData="true">.</configuration>
Copy the code

5.2. Clean up resources during shutdown

In a standalone application, to properly shutdown logback and release related resources, use the shutdown hook. This hook closes all add-ons connected to the context-defined logger and stops any active threads in an orderly fashion. It will allow any log file compression task running in the background to complete in 30 seconds.

<configuration debug="false">
	<shutdownHook/>.</configuration>
Copy the code

The close hook will be automatically installed in the Web application, making this instruction completely redundant.

6. Summary

In this Logback tutorial, we learn about the configuration provided by default, customize the defaults as required, and troubleshoot any initialization errors. We learned to configure basic console appenders and scroll file appenders. We will learn more about both in future articles.

We also looked at best practices that can help you use Logback most effectively.

Happy study! !

Download the source code