To collect logs for reading and processing by observability tools we need structured data, such as logfmt or JSON. Surprisingly, this in (not yet) implemented as a simple configuration option in Spring Boot.

Luckily, it’s not difficult to set up. Everything we need is already included in Spring Boot. All we need to do, is to configure Spring’s default logging system - Logback.

We can do that by providing a logback.xml configuration file in our /src/main/resources directory. The simplest version would look like this:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration>

<configuration>
  <import class="ch.qos.logback.classic.encoder.JsonEncoder"/>
  <import class="ch.qos.logback.core.FileAppender"/>

  <appender name="FILE" class="FileAppender">
    <file>foo.json</file>
    <encoder class="JsonEncoder"/>
  </appender>

  <root>
    <level value="DEBUG"/>
    <appender-ref ref="FILE"/>
  </root>
</configuration>

JsonEncoder is already provided by Logback (see documentation), we just need to configure one of the appenders to use it. We could set it up to encode ConsoleAppender instead, if we are collecting the logs from there, e.g. k8s log collectors.

Improved configuration

This works, but we are completely overriding Spring’s logging setup. Instead we can use logging-spring.xml configuration to leverage Spring Boot’s Logback Extensions (read more here).

An improved configuration might look like:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <import class="ch.qos.logback.classic.encoder.JsonEncoder"/>
    <import class="ch.qos.logback.core.FileAppender"/>
    <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
    <include resource="org/springframework/boot/logging/logback/console-appender.xml" />
    
    <appender name="FILE" class="FileAppender">
        <file>${LOG_FILE}</file>
        <encoder class="JsonEncoder"/>
    </appender>

    <root level="INFO">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="FILE" />
    </root>
    <logger name="org.springframework.web" level="DEBUG"/>
</configuration>

This way we can use variables like ${LOG_FILE} which is set in application.properties under logging.file.name. We also leverage preconfigured ConsoleAppender. It will output logs to stdout in Spring’s default format, which is nicely colored. This way both humans and computers can use their preferred format.