1. Overview

In this tutorial, we’ll explain how to access Spring Boot logs in Docker, from local development to sustainable multi-container solutions.

2. Basic Console Output

To begin with, let’s build our Spring Boot Docker image from our previous article:

$> mvn spring-boot:build-image

Then, when we run our container, we can immediately see STDOUT logs in the console:

$> docker run --name=demo-container docker.io/library/spring-boot-docker:0.0.1-SNAPSHOT
Setting Active Processor Count to 1
WARNING: Container memory limit unset. Configuring JVM for 1G container.

This command follows the logs like Linux shell tail -f  command.

Now, let’s configure our Spring Boot application with a log file appender by adding a line to the application.properties file:

logging.file.path=logs

Then, we can obtain the same result by running the tail -f command in our running container:

$> docker exec -it demo-container tail -f /workspace/logs/spring.log > $HOME/spring.log
Setting Active Processor Count to 1
WARNING: Container memory limit unset. Configuring JVM for 1G container.

That’s it for single-container solutions. In the next chapters, we’ll learn how to analyze log history and log output from composed containers.

3. Docker Volume for Log Files

If we must access log files from the host filesystem, we have to create a Docker volume.

To do this, we can run our application container with the command:

$> mvn spring-boot:build-image -v /path-to-host:/workspace/logs

Then, we can see the spring.log  file in the /path-to-host directory.

Starting with our previous article on Docker Compose, we can run multiple containers from a Docker Compose file.

If we’re using a Docker Compose file, we should add the volumes configuration:

network-example-service-available-to-host-on-port-1337:
image: karthequian/helloworld:latest
container_name: network-example-service-available-to-host-on-port-1337
volumes:
- /path-to-host:/workspace/logs

Then, let’s run the article Compose file:

$> docker-compose up

The log files are available in the /path-to-host directory.

Now that we’ve reviewed the basic solutions, let’s explore the more advanced docker logs command.

In the following chapters, we assume that our Spring Boot application is configured to print logs to STDOUT.

4. Docker Logs for Multiple Containers

As soon as we run multiple containers at once, we’ll no longer be able to read mixed logs from multiple containers.

We can find in the Docker Compose documentation that containers are set up by default with the json-file log driver, which supports the docker logs command.

Let’s see how it works with our Docker Compose example.

First, let’s find our container id:

$> docker ps
CONTAINER ID        IMAGE                           COMMAND                  
877bb028a143        karthequian/helloworld:latest   "/runner.sh nginx"       

Then, we can display our container logs with the docker logs -f command. We can see that, despite the json-file driver, the output is still plain text — JSON is only used internally by Docker:

$> docker logs -f 877bb028a143
172.27.0.1 - - [22/Oct/2020:11:19:52 +0000] "GET / HTTP/1.1" 200 4369 "
172.27.0.1 - - [22/Oct/2020:11:19:52 +0000] "GET / HTTP/1.1" 200 4369 "

The -f option behaves like the tail -f shell command: it echoes the log output as it’s produced.

Note that if we’re running our containers in Swarm mode, we should use the docker service ps and docker service logs commands instead.

In the documentation, we can see that the docker logs command supports limited output options: json-file, local, or journald.

5. Docker Drivers for Log Aggregation Services

The docker logs command is especially useful for instant watching: it doesn’t provide complex filters or long-term statistics.

For that purpose, Docker supports several log aggregation service drivers. As we studied Graylog in a previous article, we’ll configure the appropriate driver for this platform.

This configuration can be global for the host in the daemon.json file. It’s located in /etc/docker on Linux hosts or C:\ProgramData\docker\config on Windows servers.

Note that we should create the daemon.json file if it doesn’t exist:

{ 
    "log-driver": "gelf",
    "log-opts": {
        "gelf-address": "udp://1.2.3.4:12201"
    }
}

The Graylog driver is called GELF — we simply specify the IP address of our Graylog instance.

We can also override this configuration when running a single container:

$> docker run \
      --log-driver gelf –-log-opt gelf-address=udp://1.2.3.4:12201 \
      alpine echo hello world

6. Conclusion

In this article, we’ve reviewed different ways to access Spring Boot logs in Docker.

Logging to STDOUT makes log watching quite easy from a single-container execution.

However, using file appenders isn’t the best option if we want to benefit from the Docker logging features, as containers don’t have the same constraints as proper servers.

Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.