Logging in Java using Logback with Example

  • Last updated Apr 25, 2024

Logback is a widely used logging framework for Java applications. Logback was created to replace the popular log4j project by Ceki Gülcü, the founder of Log4j.

Logback is divided into three modules:

  1. Logback Core: The logback-core module provides the core functionality and is also responsible for laying the foundation for the other two modules.
  2. Logback Classic: The logback-classic module extends Logback's core functionality to provide support for logging libraries, such as SLF4J, Log4j. It natively implements the SLF4J API, allowing a developer to easily switch between logback and other logging frameworks such as java.util.logging or log4j 1.x.
  3. Logback Access: The logback-access module helps to integrate with Servlet containers like Tomcat and Jetty to provide HTTP-access log functionality.

Logback is built upon Logger, Appender, and Layout components to enable developers to log messages based on message type and level, as well as manage how these log messages are formatted and reported at runtime.

Logger

A Logger component is part of the logback-classic module. The Logger component helps to log messages. Following is the basic template for logging:

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

public class Example {
    private static final Logger LOGGER = LoggerFactory.getLogger(Transaction.class);

	public void methodName(){
		LOGGER.info("calling methodName()....")
	}
}
Appenders

An Appender component is part of the logback-core module. The Appenders help to write log messages to different destinations. A logger can be configured with multiple appenders. Logback provides the following ready to use appenders:

  • OutputStreamAppender: It appends log events to a java.io.OutputStream.
  • ConsoleAppender: It appends log events on the console.
  • FileAppender: It is a subclass of OutputStreamAppender. It appends log events into a file.
  • RollingFileAppender: It is a subclass of FileAppender. It appends logs events into a file with the capability to rollover log files.
  • SocketAppender and SSLSocketAppender: The SocketAppender is designed to send logs to remote destinations. The SSLSocketAppender extends the capability of SocketAppender to send log messages over Secure Sockets Layer (SSL).
  • ServerSocketAppender and SSLServerSocketAppender: The ServerSocketAppender is designed to send log messages to remote destinations. When ServerSocketAppender is used, the appender acts as a server, actively listening on a TCP socket for inbound connections from interested clients. All connected clients receive logging events supplied to the appender. The SSLServerSocketAppender extends the capability of ServerSocketAppender to send log messages over Secure Sockets Layer (SSL).
  • SMTPAppender: SMTPAppender collects logging events in one or more fixed-size buffers and sends the contents of the relevant buffer in an email. The email is sent in an asynchronous manner. By default, email is triggered by a logging level of ERROR.
  • DBAppender: The DBAppender writes logging events to three database tables in a format that is not dependent on Java programming language. The three tables are logging_event_property, logging_event, and logging_event_exception. Before DBAppender can be used, the three tables must exist. Logback includes SQL scripts for creating the tables in the logback-classic/src/main/java/ch/qos/logback/classic/db/script directory. If a script for your specific sort of database system isn't available, it should be quite simple to create one based on existing scripts.
  • SyslogAppender: The SyslogAppender sends log events to a remote syslog receiver, also commonly called syslog daemon or syslog server.
  • AsyncAppender: The AsyncAppender appends log events asynchronously.
  • SiftingAppender: The SiftingAppender appends log events to a separate log file.
Layouts

A Layout component is part of the logback-core module. Layouts help to transform an incoming event into a formatted string.

Logback Configuration

Logback can be configured programmatically or by a configuration script written in XML or Groovy.

Logback tries to configure itself by looking for a file named logback-test.xml in the classpath. If no such file is found, it looks for logback.xml file in the classpath. If Logback could not find any configurations, it uses the BasicConfigurator that directs the logging output to the console.

Logback Example

In this example, we will show you how to use Logback framework for logging in a Java application.

This example uses logback core, logback classic, and SLF4J. SLF4J stands for Simple Logging Facade for Java. It is a simple facade that provides abstraction for other logging frameworks.

Follow the steps below to complete this example:

  1. Adding Logback Dependencies:
  2. Add logback core, logback classic, and slf4j api dependencies to your project.

    For Maven:

    Add the Logback dependencies to the pom.xml file:

    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-core</artifactId>
        <version>1.4.11</version>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.4.11</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>2.0.9</version>
    </dependency>

    For Gradle:

    Add the Logback dependencies to the build.gradle file:

    implementation group: 'ch.qos.logback', name: 'logback-core', version: '1.4.11'
    testImplementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.4.11'
    implementation group: 'org.slf4j', name: 'slf4j-api', version: '2.0.9'

    NOTE: The versions of the above given Logback dependencies must be compatible with one another, else your application will fail to run.

  3. Adding Logback Configuration File:
  4. Create a file named logback.xml inside the src/main/resources folder of your application and add the following configuration to it:

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration scan="true" scanPeriod="30 seconds">
    
    	<property name="application-name" value="product-service"
    		scope="context" />
    	<property name="LOG_FILE" value="LogFile" />
    
    	<appender name="Stdout"	class="ch.qos.logback.core.ConsoleAppender">
    		<encoder>
    			<pattern>
    				%d{YYYY-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} -
    				%msg%n
    			</pattern>
    		</encoder>
    	</appender>
    
    	<appender name="RollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
    		<file>/logs/app.log</file>
    		<encoder>
    			<pattern>
    				%d{YYYY-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} -
    				%msg%n
    			</pattern>
    		</encoder>
    		<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
    			<!-- daily rollover -->
    			<fileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}.gz</fileNamePattern>
    			<!-- keep 30 days' worth of history capped at 3GB total size -->
    			<maxHistory>30</maxHistory>
    			<totalSizeCap>3GB</totalSizeCap>
    		</rollingPolicy>
    
    		<triggeringPolicy
    			class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
    			<maxFileSize>3GB</maxFileSize>
    		</triggeringPolicy>
    	</appender>
    
    	<logger	name="com.tutorialsbuddy.logging.example.transaction.impl.TransactionServiceImpl"
    		level="ERROR">
    		<appender-ref ref="RollingFile" />
    	</logger>
    
    	<root level="DEBUG">
    		<appender-ref ref="Stdout" />
    	</root>
    
    </configuration>
  5. Logging Data:
  6. Here's an example class that demonstrates how to log data in Java using Logback:

    package com.tutorialsbuddy.logging.example.transaction;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class TransactionService {
    	private static final Logger LOGGER = LoggerFactory.getLogger(TransactionServiceImpl.class);
    
    	public void inititate(String senderId, String receiverId, double trxnAmount) {
    		LOGGER.debug("calling initiating(senderId : {}, receiverId : {}, trxnAmount : {}) method...", senderId,
    				receiverId, trxnAmount);
    		try {
    			int testResult = (int) trxnAmount / 0;
    			LOGGER.info("Result = {}", testResult);
    		} catch (Exception ex) {
    			LOGGER.error("Exception caught while initiating transaction " + ex);
    		}
    	}
    
    	public void refund(String transactionId, double refundAmount) {
    		LOGGER.debug("calling initiating(transactionId : {}, refundAmount : {}) method...", transactionId,
    				refundAmount);
    		try {
    
    		} catch (Exception ex) {
    			LOGGER.warn("Exception caught while refunding transaction " + ex);
    		}
    	}
    
    }