SLF4J Logback Tutorial
A simple SLF4J with Logback example.
Tested with
- SLF4J API 1.7.25
- Logback 1.2.3
- Maven 3
- Java 8
Logback natively implements the SLF4J API.
1. Project Directory
2. Maven
2.1 Declares logback-classic
, it will pull in the logback-core
and slf4j-api
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
com.mkyong:slf4j-logback:jar:1.0
[INFO] +- ch.qos.logback:logback-classic:jar:1.2.3:compile
[INFO] | +- ch.qos.logback:logback-core:jar:1.2.3:compile
[INFO] | \- org.slf4j:slf4j-api:jar:1.7.25:compile
2.2 Complete pom.xml
example.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mkyong</groupId>
<artifactId>slf4j-logback</artifactId>
<version>1.0</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<logback.version>1.2.3</logback.version>
<javax.mail.version>1.6.2</javax.mail.version>
</properties>
<dependencies>
<!-- pull in logback-core and slf4j-api -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<!-- SMTPAppender need this to send email
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>${javax.mail.version}</version>
</dependency>
-->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<!-- build a single executable JAR -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.0</version>
<executions>
<!-- Attach the shade into the package phase -->
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.mkyong.HelloWorld</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
3. logback.xml
3.1 Create a logback.xml
in the project classpath.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>
%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n
</Pattern>
</layout>
</appender>
<logger name="com.mkyong" level="debug" additivity="false">
<appender-ref ref="CONSOLE"/>
</logger>
<root level="error">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>
4. Hello Logback
package com.mkyong;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HelloWorld {
private static final Logger logger = LoggerFactory.getLogger(HelloWorld.class);
public static void main(String[] args) {
logger.debug("Hello from Logback");
logger.debug("getNumber() : {}", getNumber());
}
static int getNumber() {
return 5;
}
}
Output
11:28:18.350 [main] DEBUG com.mkyong.HelloWorld - Hello from Logback
11:28:18.352 [main] DEBUG com.mkyong.HelloWorld - getNumber() : 5
5. Logback Configuration
5.1 For development, it’s recommended to enable the debug mode. It will display a lot of useful INFO and also error message if any.
<configuration debug="true">
</Configuration>
Read this Logback configuration
6. Logback Appenders
Some of the common Logback appenders.
6.1 ConsoleAppender
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>
%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n
</Pattern>
</layout>
</appender>
<logger name="com.mkyong" level="debug" additivity="false">
<appender-ref ref="CONSOLE"/>
</logger>
<root level="error">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>
6.2 FileAppender
<configuration>
<property name="HOME_LOG" value="logs/app.log"/>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>
%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n
</Pattern>
</layout>
</appender>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>${HOME_LOG}</file>
<append>true</append>
<immediateFlush>true</immediateFlush>
<encoder>
<pattern>%d %p %c{1.} [%t] %m%n</pattern>
</encoder>
</appender>
<logger name="com.mkyong" level="debug" additivity="false">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</logger>
<root level="error">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>
2019-03-29 11:42:44,827 DEBUG com.mkyong.HelloWorld [main] Hello from Logback
2019-03-29 11:42:44,836 DEBUG com.mkyong.HelloWorld [main] getNumber() : 5
6.3 RollingFileAppender
– Rotate log file, by date and size. This is the one you need in production, most likely.
<configuration>
<property name="HOME_LOG" value="logs/app.log"/>
<appender name="FILE-ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${HOME_LOG}</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>logs/archived/app.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!-- each archived file, size max 10MB -->
<maxFileSize>10MB</maxFileSize>
<!-- total size of all archive files, if total size > 20GB, it will delete old archived file -->
<totalSizeCap>20GB</totalSizeCap>
<!-- 60 days to keep -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d %p %c{1.} [%t] %m%n</pattern>
</encoder>
</appender>
<logger name="com.mkyong" level="debug" additivity="false">
<appender-ref ref="FILE-ROLLING"/>
</logger>
<root level="error">
<appender-ref ref="FILE-ROLLING"/>
</root>
</configuration>
Add an .gz
extension, Logback will compress the archived files.
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>logs/archived/app.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
</rollingPolicy>
6.4 SMTPAppender
– Need javax.mail
to send email.
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.6.2</version>
</dependency>
<configuration debug="true">
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>
%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n
</Pattern>
</layout>
</appender>
<appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">
<smtpHost>smtp.mailgun.org</smtpHost>
<smtpPort>25</smtpPort>
<username>123</username>
<password>123</password>
<to>TO_EMAIL</to>
<to>RO_ANOTHER_EMAIL</to>
<from>FROM_EMAIL</from>
<subject>TESTING: %logger{20} - %m</subject>
<layout class="ch.qos.logback.classic.html.HTMLLayout"/>
<!-- for testing , comment in production, default 256 -->
<cyclicBufferTracker class="ch.qos.logback.core.spi.CyclicBufferTracker">
<!-- Send just one log entry per email, ready for a lot of emails if you put one. -->
<bufferSize>1</bufferSize>
</cyclicBufferTracker>
<!-- for testing , comment in production, default asynchronousSending = true -->
<asynchronousSending>false</asynchronousSending>
</appender>
<logger name="com.mkyong" level="error" additivity="false">
<appender-ref ref="EMAIL"/>
</logger>
<root level="error">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>
Simulate an error
package com.mkyong;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HelloWorldError {
private static final Logger logger = LoggerFactory.getLogger(HelloWorldError.class);
public static void main(String[] args) {
try {
System.out.println(getData());
} catch (IllegalArgumentException e) {
logger.error("{}", e);
}
}
static int getData() throws IllegalArgumentException {
throw new IllegalArgumentException("Sorry IllegalArgumentException!");
}
}
Here’s the email
6.5 AsyncAppender
– Logs asynchronously, faster, but drop events of level TRACE, DEBUG and INFO if its queue is 80% full, keeping only events of level WARN and ERROR. Read this AsyncAppender
<configuration debug="true">
<property name="HOME_LOG" value="logs/app.log"/>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>
%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n
</Pattern>
</layout>
</appender>
<appender name="FILE-ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${HOME_LOG}</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>logs/archived/app.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!-- each archived file, size max 10MB -->
<maxFileSize>10MB</maxFileSize>
<!-- total size of all archive files, if total size > 20GB, it will delete old archived file -->
<totalSizeCap>20GB</totalSizeCap>
<!-- 60 days to keep -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d %p %c{1.} [%t] %m%n</pattern>
</encoder>
</appender>
<!-- https://logback.qos.ch/manual/appenders.html#AsyncAppender -->
<!-- AsyncAppender will drop events of level TRACE, DEBUG and INFO if its queue is 80% full -->
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="FILE-ROLLING" />
<!-- defaulr 256 -->
<queueSize>512</queueSize>
</appender>
<logger name="com.mkyong" level="debug" additivity="false">
<appender-ref ref="ASYNC"/>
<appender-ref ref="CONSOLE"/>
</logger>
<root level="error">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>
Read more Logback appenders
Download Source Code
$ cd slf4j-logback
$ mvn clean package
$ java -jar target\slf4j-logback-1.0.jar
Great stuff, however the same tutorial does not work when logback.xml is put outside a built jar which is a typical requirement in an enterprise application. is there any specific setting need to be done?
Hi, great article.
I have one question related to smtp appender.
Is there any way to send additional meta information inside email.
For example, at the end of the email body, I would like to list some metadata about VM that generated an error.
Some service Id, few links related to this VM etc.
I know there is a way to send some of this via smtp_subject. Or via pattern.
But it would be great to append to the end of body one large set of metadata with more details about the source.
Thanks in advance.