Configuring and Using Logback for Java Application Logging

Required Dependencies

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.30</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-core</artifactId>
    <version>1.2.3</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
</dependency>

Log Severity Hierarchy

Levels from lowest to highest: TRACE < DEBUG < INFO < WARN < ERROR < FATAL. Only messages at or above the configured threshold are emitted.

Configuration File Naming

Logback recognizes: logback.xml, logback-spring.xml, logback-spring.groovy, logback.groovy. Spring Boot prefers -spring variants to enable profile-specific options. Place the file under src/main/resources. Override via:

logging:
  config: classpath:custom-log-config.xml

Root Logger Element

Mandatory element setting the base severity. Attribute level accepts: TRACE, DEBUG, INFO, WARN, ERROR, ALL, OFF.

<root level="debug">
  <appender-ref ref="consoleOut" />
  <appender-ref ref="fileOut" />
</root>

Appender Element

Defines output formatting strategy. Attributes: name, class. Common strategies: console, file, rolling file.

Console Output via ConsoleAppender

<configuration scan="true" scanPeriod="60 seconds" debug="false">
  <contextName>logbackDemo</contextName>
  <appender name="consoleOut" class="ch.qos.logback.core.ConsoleAppender">
    <layout class="ch.qos.logback.classic.PatternLayout">
      <pattern>%d{HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - [%method,%line] - %msg%n</pattern>
    </layout>
  </appender>
  <root level="INFO">
    <appender-ref ref="consoleOut"/>
  </root>
</configuration>

Format tokens:

  • %d{HH:mm:ss.SSS} – timestamp
  • [%thread] – thread identifier
  • %-5level – left-aligned severity in 5-width column
  • %logger{36} – logger name truncated to 36 chars
  • %method, %line – source method and line number
  • %msg – actual message
  • %n – platform newline

File Output via RollingFileAppender

Supports time/size-based log rotation to avoid unbounded growth.

Logger Element

Targets specific package or class. Attributes: name, optional level, optional additivity (default true). additivity=true causes duplicate entries if parent logger also appends.

<logger name="com.example.dao" level="DEBUG" />

Example usage:

public class Runner {
    private static final Logger auditLog = LoggerFactory.getLogger("com.example.dao");
    public static void main(String[] args) {
        auditLog.info("data access test");
    }
}

Property Element

Defines reusable variables. Referenced via ${varName}.

<property name="logDir" value="/var/logs/app" />
<property name="logFmt" value="%d{HH:mm:ss.SSS} %thread %-5level %logger{36} - %msg%n" />

Pattern Layout Tokens

Token Meaning Example Output
%logger{len} Logger name, truncated %logger{20} com.examp...
%class{len} Fully qualified caller class %class{15} com.exam...
%line Source line number %line 128
%date{pattern} Event date/time %date{yyyy-MM-dd HH:mm} 2024-03-10 14:23
%level Severity %level INFO
%thread Thread name %thread http-nio-8080-exec-1
%msg Message text %msg User login success
%-widthX Left-padded width %-5level INFO␣
%X{customKey} MDC value %X{reqId} abc123

Spring Profiles in Configuration

Wrap <root> in <springProfile> blocks to vary settings per environment.

<springProfile name="dev,test">
  <root level="info">
    <appender-ref ref="STDOUT" />
  </root>
</springProfile>
<springProfile name="prod">
  <root level="info">
    <appender-ref ref="STDOUT" />
    <appender-ref ref="FILE" />
  </root>
</springProfile>

Complete Sample Configuration

<configuration scan="true" scanPeriod="60 seconds" debug="false">
  <contextName>logback</contextName>
  <property name="logPath" value="E:/logs/app.log" />
  <property name="logFmt" value="%d{HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} %file:%line - %msg%n" />

  <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>${logFmt}</pattern>
    </encoder>
  </appender>

  <appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>${logPath}</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <fileNamePattern>${logPath}.%d{yyyy-MM-dd}.gz</fileNamePattern>
      <maxHistory>30</maxHistory>
    </rollingPolicy>
    <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
      <maxFileSize>5MB</maxFileSize>
    </triggeringPolicy>
    <encoder>
      <pattern>${logFmt}</pattern>
      <charset>UTF-8</charset>
    </encoder>
  </appender>

  <appender name="asyncFile" class="ch.qos.logback.classic.AsyncAppender">
    <discardingThreshold>0</discardingThreshold>
    <queueSize>10000</queueSize>
    <appender-ref ref="file" />
  </appender>

  <root level="info">
    <appender-ref ref="console" />
    <appender-ref ref="asyncFile" />
  </root>

  <logger name="com.sample.controller" />
  <logger name="com.sample.controller.DashboardCtrl" level="WARN" additivity="false">
    <appender-ref ref="console" />
  </logger>
</configuration>

Logger Instantiation and Hierarchy

Create a logger via:

private static final Logger eventLog = LoggerFactory.getLogger(DashboardCtrl.class);

Equivalent to passing the clas literal; logger hierarchy forms automatically (com.samplecom.sample.controllercom.sample.controller.DashboardCtrl). Root logger is available via LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME). Set additivity="false" on child loggers to prevent duplicate emission through ancestor appenders.

Appenders Overview

Appenders route log events to destinations. Core types:

  • ConsoleAppender – outputs to stdout/stderr
  • FileAppender – writes to a single file
  • RollingFileAppender – rotates based on policies

Rotation policies:

  1. TimeBasedRollingPolicy – rolls at fixed time intervals
  2. SizeAndTimeBasedRollingPolicy – rolls on size or time thresholds

Time-based example:

<appender name="dailyFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
  <file>${LOG_DIR}/service.log</file>
  <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
    <fileNamePattern>${LOG_DIR}/service.%d{yyyy-MM-dd}.log.gz</fileNamePattern>
    <maxHistory>180</maxHistory>
    <totalSizeCap>20GB</totalSizeCap>
  </rollingPolicy>
  <encoder>
    <charset>UTF-8</charset>
    <pattern>${log.pattern}</pattern>
  </encoder>
</appender>

Size-and-time example:

<appender name="errFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
  <file>${LOG_DIR}/error.log</file>
  <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
    <fileNamePattern>${LOG_DIR}/error.%d{yyyy-MM-dd}-%i.log.gz</fileNamePattern>
    <maxHistory>60</maxHistory>
    <totalSizeCap>20GB</totalSizeCap>
    <maxFileSize>50MB</maxFileSize>
  </rollingPolicy>
  <encoder>
    <pattern>${log.pattern}</pattern>
  </encoder>
  <filter class="ch.qos.logback.classic.filter.LevelFilter">
    <level>ERROR</level>
    <onMatch>ACCEPT</onMatch>
    <onMismatch>DENY</onMismatch>
  </filter>
</appender>

Using Logging in Code

No need to check log level before logging; evaluation is optimized. Classic approach:

private static final Logger opLog = LoggerFactory.getLogger(OrderService.class);
opLog.error("failure in processing");

Lombok annotation alternative:

<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <version>1.16.16</version>
</dependency>
@Slf4j
@RestController
public class ApiCtrl {
    public void handle() {
        log.info("request received");
    }
}

Tags: logback java logging Logging Configuration SLF4J Spring Boot

Posted on Tue, 23 Jun 2026 16:54:04 +0000 by ternto333