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
From:一号门
Previous:Java How to Iterate a HashMap
COMMENTS