Logging in Spring Boot

Learn to customize the default logging or implement a new logging facility in a Spring boot application.

1. Overview

Spring Boot uses Commons Logging for all logging internal to the framework and thus it is a mandatory dependency. For other logging needs, Spring boot supports default configuration for Java Util Logging, Log4J2, and Logback.

When using the spring boot starters, each starter depends on spring-boot-starter-logging which in turn includes logback, log4j2 and Java util logging in the project.

Each Spring boot 2.x starter also depends on Spring 5 that brings in the spring-jcl module for commons-logging.

[INFO]    |  +- org.springframework.boot:spring-boot-starter-logging:jar:2.6.1:compile
[INFO]    |  |  +- ch.qos.logback:logback-classic:jar:1.2.7:compile
[INFO]    |  |  |  +- ch.qos.logback:logback-core:jar:1.2.7:compile
[INFO]    |  |  |  \- org.slf4j:slf4j-api:jar:1.7.32:compile
[INFO]    |  |  +- org.apache.logging.log4j:log4j-to-slf4j:jar:2.14.1:compile
[INFO]    |  |  |  \- org.apache.logging.log4j:log4j-api:jar:2.14.1:compile
[INFO]    |  |  \- org.slf4j:jul-to-slf4j:jar:1.7.32:compile
...
[INFO]    |  +- org.springframework:spring-core:jar:5.3.13:compile
[INFO]    |  |  \- org.springframework:spring-jcl:jar:5.3.13:compile

2. Default Logging Configuration

The default logging for the application is done by Logback. We can use directly use the Logback API or use the SLF4J APIs to write the log messages.

For demo purposes, we have bootstrapped a very simple spring boot application with minimum dependencies.

We have added a few log statements in LoggerController for testing purposes. we are using the SLF4J provided Logger and LoggerFactory API.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class LoggerController {

  Logger logger = LoggerFactory.getLogger(LoggerController.class);

  @GetMapping ("/logs")
  public String logs() {

    logger.trace("A TRACE Message");
    logger.debug("A DEBUG Message");
    logger.info("An INFO Message");
    logger.warn("A WARN Message");
    logger.error("An ERROR Message");

    return "SUCCESS";
  }
}

Start the application and hit the URL: http://localhost:8080/logs and note the logs in console.

2021-12-24 14:00:16.880  INFO 2828 --- [nio-8080-exec-1] c.s.demo.web.LoggerController            : An INFO Message
2021-12-24 14:00:16.880  WARN 2828 --- [nio-8080-exec-1] c.s.demo.web.LoggerController            : A WARN Message
2021-12-24 14:00:16.880 ERROR 2828 --- [nio-8080-exec-1] c.s.demo.web.LoggerController            : An ERROR Messa

As seen in the logged messages, the default logging level is preset to INFO. That’s why the TRACE and DEBUG messages are not visible.

3. Customizing Default Logging

3.1. Log Level

To enable debug or trace logs, we can start our application with a --debug or --trace flag.

$ java -jar myapp.jar --debug

Alternatively, we can set debug=true in application.properties file. This enables debug logging for a selection of core loggers (embedded container, Hibernate schema generation, and all spring modules).

debug=true

For more fine-grained control over logging levels for different packages, we can make the application configuration level change in application.properties file.

logging.level.root=WARN 
logging.level.com.springexamples=DEBUG

Note that Logback does not have a FATAL level. If specified, it is mapped to ERROR.

3.2. Log Format

By default, spring boot prints color-coded logs which include the following information:

  • Date and Time
  • Log Level: ERROR, WARN, INFO, DEBUG, or TRACE
  • Process ID
  • A — separator
  • Thread name
  • Logger name: usually the class name
  • The log message

We can read the complete default configuration in defaults.xml.

To override the default log formats, we can provide the custom formats using the properties logging.pattern.console and logging.pattern.file.

logging.pattern.console= %d{yyyy-MM-dd HH:mm:ss} - %msg%n

logging.file=${java.io.tmpdir}/application.log
logging.pattern.file= %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%

3.3. File Logger

By default, Spring Boot logs only to the console and does not write log files.

To enable file logging, set the logging.file.name or logging.file.path properties. The default file log level is INFO, similar to console logging.

logging.file.path=${java.io.tmpdir}
logging.file.name=app.log

Note that file logs rotate when they reach 10 MB. If using Logback, we can customize the log rotation policy using the following properties.

  • logging.logback.rollingpolicy.file-name-pattern
  • logging.logback.rollingpolicy.clean-history-on-start
  • logging.logback.rollingpolicy.max-file-size
  • logging.logback.rollingpolicy.total-size-cap
  • logging.logback.rollingpolicy.max-history

For other logging frameworks, we need to configure loggers and rotation policies in their specific configuration files.

3.4. ANSI Color Coded Logs

Configure the value of spring.output.ansi.enabled property to customize the color-coded logs. The supported values are:

  • DETECT – detects whether ANSI coloring capabilities are available. This is the default behavior.
  • ALWAYS – always enables ANSI-colored output.
  • NEVER – completely disables ANSI-colored output.
spring.output.ansi.enabled=ALWAYS

4. Configuring Custom Logging

The default console and file logs are good for bootstrapping the application and simple POCs. As the application matures, we need to provide an extensive logging configuration to capture each kind of log with suitable rotation policies.

To configure the custom logging, we have the following options:

4.1. org.springframework.boot.logging.LoggingSystem Property

We can force Spring Boot to use a particular logging system by using the org.springframework.boot.logging.LoggingSystem system property. Its value should be the fully qualified class name of a LoggingSystem implementation.

  • none – disables the logging configuration entirely
  • org.springframework.boot.logging.log4j2.Log4J2LoggingSystem – configures Log4j2. Searches for a file named in sequence logback-spring.xml, logback-spring.groovy, logback.xml, or logback.groovy.
  • org.springframework.boot.logging.logback.LogbackLoggingSystem – configures Logback. Searches for a file named in sequence log4j2-spring.xml or log4j2.xml.
  • org.springframework.boot.logging.java.JavaLoggingSystem – configures Java util logging. Searches for logging.properties.

Using the -spring variants for the logging configuration files is the recommended approach.

4.2. Exclude Logback

Another approach to configuring logging is to exclude Logback and include another logging framework such as Log4j2.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <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>
</dependency>

This way Spring auto-detects the dependencies and configures the appropriate logging framework for us.

We still need to place the logging configuration file in the classpath. We can use the property logging.config to give the location of the configuration file, too.

logging.config=classpath:log4j2.properties

Note that if we are using the file name as listed in the previous section which Spring searches for, then we should provide the file name using logging.config property.

If we use log4j2.properties, then logging.config=classpath:log4j2.properties should be specified.

On the other hand, If we use log4j2-spring.xml, then there is no need to specify logging.config.

Also note that with such configuration, we are free to use native Log4j2 classes or SLF4J classes to write the log statements. Under the hood, Log4j2 will be used.

5. Logging with Lombok

Spring boot does not have inbuilt support for Lombok, so to use Lombok, we must include its dependency explicitly.

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.20</version>
    <scope>provided</scope>
</dependency>

The recommended way is to use SLF4J APIs that act as an abstraction over other logging implementation frameworks. To do this, use @Slf4j annotation for the application classes.

The @Slf4j annotation automatically adds a field named log which we can use to write log statements.

@Slf4j
@RestController
public class LoggerController {

  @GetMapping ("/logs")
  public String logs() {

    log.trace("A TRACE Message");
    log.debug("A DEBUG Message");
    log.info("An INFO Message");
    log.warn("A WARN Message");
    log.error("An ERROR Message");

    return "SUCCESS";
  }
}

Generate log statements again and note the console logs. Note that we have enabled the debug logging in previous steps.

2021-12-24 15:45:32.145 DEBUG 23356 --- [nio-8080-exec-1] c.s.demo.web.LoggerController            : A DEBUG Message
2021-12-24 15:45:32.145  INFO 23356 --- [nio-8080-exec-1] c.s.demo.web.LoggerController            : An INFO Message
2021-12-24 15:45:32.145  WARN 23356 --- [nio-8080-exec-1] c.s.demo.web.LoggerController            : A WARN Message
2021-12-24 15:45:32.145 ERROR 23356 --- [nio-8080-exec-1] c.s.demo.web.LoggerController            : An ERROR Message

6. Conclusion

In this Spring boot tutorial, we learn many things about boot-provided logging defaults and how to customize them properly. We also learned to use custom logging frameworks and provide more extensive logging configuration files.

You can check out the source code of these examples over Github.

Leave a Comment