Slf4j Spring Boot Example
In this example, we are going to learn how to use SLF4J in Spring projects with an example of Spring Boot application.
1. Introduction
The Simple Logging Facade for Java (SLF4J) serves as a simple facade or abstraction for various logging frameworks (e.g. java.util.logging, logback, log4j) allowing the end user to plug in the desired logging framework at deployment time.
SLF4J facilitates your code to make logging calls without binding to a specific logging implementation. This comes real handy for libraries where it is not desired to hard bind the API to a particular logging framework as the program where it may be used might be using another logging implementation.
To get started with SLF4J, read this tutorial.
SLF4J has now become a logging abstraction of choice and probably fast ruling out Commons logging due to it’s advantages (read here for a head-on comparison).
Spring (what started as a Java enterprise application framework) has evolved into an ecosystem now with framework for enterprise applications, transaction management, web services, security, mobile development etc. Let’s see in this example what Spring has to offer when it comes to logging framework support.
2. Technologies Used
For this example, we use the following tools on a Windows 10 platform:
- Eclipse IDE
- Apache Maven
- JDK 1.8
- Slf4j 1.7.22
- Spring Boot 1.5.3
3. Slf4j Spring Boot Example
3.1 Create a Maven Project
We will create a bare minimum Maven project. Once you have the Maven installed and running on your machine, issue the following command from the command line.
mvn archetype:generate -DgroupId=com.javacodegeeks -DartifactId=slf4-spring-boot -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
In this example, Maven will manage dependencies for us and we don’t need to download any jars explicitly.
3.2 Add Maven Dependencies
Add the required dependencies for just Spring Boot. Your pom.xml should look like this.
pom.xml
<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.javacodegeeks</groupId> <artifactId>slf4-spring-boot</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>slf4-spring-boot</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <version>1.5.3.RELEASE</version> </dependency> </dependencies> </project>
With just the single dependency, spring boot will download the logging dependency (spring-boot-starter-logging) as well among other core dependencies. If you open pom.xml and go to the “Dependency Hierarchy” tab, it looks like this:
Note the jar files spring-boot-starter-logging
brings along in the figure above. jcl-over-slf4j
, jul-to-slf4j
and log4j-over-slf4j
are the bridging modules which redirect calls made to log4j, JCL and java.util.logging APIs to behave as if they were made to the SLF4J API instead. logback-classic
along with logback-core
enables logback as the default logging implementation for Spring Boot. This may have to do with the fact that logback is the native implementation of SLF4J; using SLF4J in conjunction with logback involves strictly zero memory and computational overhead.
3.3 Logback Configuration
Create logback.xml and put the basic configuration settings. If we don’t create this file, even then logback will configure itself automatically using the BasicConfigurator
which will cause logging output to be directed to the console.
logback.xml
<configuration> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <!-- encoders are assigned the type ch.qos.logback.classic.encoder.PatternLayoutEncoder by default --> <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>
3.4 Test Class
Slf4jSpringBootApplication.java
package com.javacodegeeks; import java.lang.invoke.MethodHandles; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.impl.StaticLoggerBinder; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import com.javacodegeeks.service.HelloWorldService; @SpringBootApplication public class Slf4jSpringBootApplication implements CommandLineRunner { // SLF4J's logging instance for this class // We could have used LoggerFactory.getLogger(Slf4jSpringBootApplication.class) as well private static final Logger LOGGER = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); // This is what SLF4J uses to bind to a specific logging implementation final StaticLoggerBinder binder = StaticLoggerBinder.getSingleton(); @Autowired private HelloWorldService helloWorldService; public void run(String... args) { System.out.println(binder.getLoggerFactory()); System.out.println(binder.getLoggerFactoryClassStr()); LOGGER.debug(this.helloWorldService.getHelloMessage()); if (args.length > 0 && args[0].equals("exitcode")) { LOGGER.error("Exit Code encountered", new ExitException()); } } public static void main(String[] args) throws Exception { SpringApplication.run(Slf4jSpringBootApplication.class, args); } }
Since the logging level is set to debug, it’s going to output a lot of Spring messages. Our logging specific calls is shown below.
Output Snippet
ch.qos.logback.classic.LoggerContext[default] ch.qos.logback.classic.util.ContextSelectorStaticBinder 19:48:58.844 [main] INFO c.j.service.HelloWorldService - Name registered World 19:48:58.846 [main] DEBUG c.j.Slf4jSpringBootApplication - Hello World 19:48:58.848 [main] ERROR c.j.Slf4jSpringBootApplication - Exit Code encountered java.lang.Exception: null at com.javacodegeeks.Slf4jSpringBootApplication.run(Slf4jSpringBootApplication.java:34) at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:776) at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:760) at org.springframework.boot.SpringApplication.afterRefresh(SpringApplication.java:747) at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1162) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1151) at com.javacodegeeks.Slf4jSpringBootApplication.main(Slf4jSpringBootApplication.java:39)
3.5 Configuring With Log4J
You can use spring-boot-starter-log4j2
in place of spring-boot-starter-logging
so that log4j2 becomes the default dependency for your Spring Boot app. In this case our pom.xml will look like this.
pom.xml
<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.javacodegeeks</groupId> <artifactId>slf4-spring-boot</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>slf4-spring-boot</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <version>1.5.3.RELEASE</version> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> <version>1.5.3.RELEASE</version> </dependency> </dependencies> </project>
Create log4j.properties for the logging configuration.
log4j.properties
# Root logger option log4j.rootLogger=INFO, stdout # Direct log messages to stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target=System.out log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1} - %m%n
Let’s re-run Slf4jSpringBootApplication.java
to see the output.
Output Snippet
org.apache.logging.slf4j.Log4jLoggerFactory@38b27cdc org.apache.logging.slf4j.Log4jLoggerFactory 2017-04-29 20:28:02.924 INFO 14356 --- [ main] c.j.s.HelloWorldService : Name registered World 2017-04-29 20:28:02.925 ERROR 14356 --- [ main] c.j.Slf4jSpringBootApplication : Exit Code encountered java.lang.Exception: null at com.javacodegeeks.Slf4jSpringBootApplication.run(Slf4jSpringBootApplication.java:34) [classes/:?] at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:776) [spring-boot-1.5.3.RELEASE.jar:1.5.3.RELEASE] at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:760) [spring-boot-1.5.3.RELEASE.jar:1.5.3.RELEASE] at org.springframework.boot.SpringApplication.afterRefresh(SpringApplication.java:747) [spring-boot-1.5.3.RELEASE.jar:1.5.3.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) [spring-boot-1.5.3.RELEASE.jar:1.5.3.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1162) [spring-boot-1.5.3.RELEASE.jar:1.5.3.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1151) [spring-boot-1.5.3.RELEASE.jar:1.5.3.RELEASE] at com.javacodegeeks.Slf4jSpringBootApplication.main(Slf4jSpringBootApplication.java:39) [classes/:?]
Note in the above output, the SLF4J binding has switched to log4j2.
4. Summary
Spring Boot provides out of the box support for SLF4J and Logback is the default logging implementation for Spring Boot.
Default logging implementation can be changed by excluding corresponding bridging modules (jcl-over-slf4j, jult-to-slf4j and log4j-over-slf4j) as well as logback-classic and then add required logging library with the corresponding slf4j bridge.
5. References
- https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#overview-logging-slf4j
- https://projects.spring.io/spring-boot/
- https://docs.spring.io/spring-boot/docs/current/reference/html/howto-logging.html
- https://www.slf4j.org/legacy.html
6. Download the Eclipse Project
You can download the full source codes of this example here: slf4j-log4j-spring-boot & slf4j-spring-boot