How to Log in JSON with Logback

The complete source code is available at https://github.com/larose/logback-json-example.

End result:

logger.debug("Hello world.");
{
  "timestamp" : "2018-05-26T14:51:07.505Z",
  "level" : "DEBUG",
  "thread" : "main",
  "logger" : "com.mathieularose.Main",
  "message" : "Hello world.",
  "context" : "default"
}

Step 1: logback.xml

Define the appender that writes to stdout:

<configuration>
    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
    </appender>

    <root level="debug">
        <appender-ref ref="stdout"/>
    </root>
</configuration>

Define the encoder:

<configuration>
    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
        </encoder>
    </appender>

    <root level="debug">
        <appender-ref ref="stdout"/>
    </root>
</configuration>

Define the JSON layout and customize the timestamp:

<configuration>
    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="ch.qos.logback.contrib.json.classic.JsonLayout">
                <timestampFormat>yyyy-MM-dd'T'HH:mm:ss.SSSX</timestampFormat>
                <timestampFormatTimezoneId>Etc/UTC</timestampFormatTimezoneId>
            </layout>
        </encoder>
    </appender>

    <root level="debug">
        <appender-ref ref="stdout"/>
    </root>
</configuration>

Define the JSON formatter:

<configuration>
    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="ch.qos.logback.contrib.json.classic.JsonLayout">
                <timestampFormat>yyyy-MM-dd'T'HH:mm:ss.SSSX</timestampFormat>
                <timestampFormatTimezoneId>Etc/UTC</timestampFormatTimezoneId>

                <jsonFormatter class="ch.qos.logback.contrib.jackson.JacksonJsonFormatter">
                    <prettyPrint>true</prettyPrint>
                </jsonFormatter>
            </layout>
        </encoder>
    </appender>

    <root level="debug">
        <appender-ref ref="stdout"/>
    </root>
</configuration>

Step 2: pom.xml

...
    <properties>
        <logback.contrib.version>0.1.5</logback.contrib.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <!-- ch.qos.logback.contrib.jackson.JacksonJsonFormatter -->
        <dependency>
            <groupId>ch.qos.logback.contrib</groupId>
            <artifactId>logback-jackson</artifactId>
            <version>${logback.contrib.version}</version>
        </dependency>

        <!-- ch.qos.logback.contrib.json.classic.JsonLayout -->
        <dependency>
            <groupId>ch.qos.logback.contrib</groupId>
            <artifactId>logback-json-classic</artifactId>
            <version>${logback.contrib.version}</version>
        </dependency>

        <!-- com.fasterxml.jackson.databind.ObjectMapper -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.5</version>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.25</version>
        </dependency>
    </dependencies>
...