squarebrackets
squarebrackets

Reputation: 997

Docker Compose: Log output to both a file and stdout

I am trying to log the output of an application to both a file and stdout. Only logging the output to stdout and only logging the output to a file works, however the combination of the two does not work as expected.

Here are simplified versions of docker-compose.yml and a startup script.

docker-compose.yml:

version: "3.8"

services:
    web:
        image: node:14
        command: sh "/app/scripts/init-app.sh"
        init: true
        volumes:
            - ./:/app

init-app.sh:

#!/usr/bin/env sh

# Exit script immediately if a command exits with a non-zero status.
set -e

# Install and configure app
[...]

# Start app
exec ./app

The above configuration works, but outputs only to stdout.

Modification #1 (last line of init script):

# Start app and log output to file
exec ./app >> "/app/log.txt" 2>&1

This configuration works also, logging the output to a file, but not to stdout.

Modification #2 (last line of init script):

# Start app and log output to both a file and stdout
exec ./app 2>&1 | tee -a "/app/log.txt"

This correctly outputs to both a file and stdout, but it breaks the container's start/stop functionality.

Details: Despite being called with exec, ./app doesn't run as PID 1 when called with tee. This is a problem, because when the container is stopped (via CLI or GUI), docker sends a stop signal to the process with PID 1. The ./app process doesn't receive the signal and therefore ./app doesn't stop.

How is it possible to log the output to both a file and stdout without breaking the start/stop functionality?

// Edit: Fixed modification #1

// Edit2: Added "init: true" to docker-compose.yml

Upvotes: 4

Views: 16841

Answers (2)

Raphael PICCOLO
Raphael PICCOLO

Reputation: 2175

I've heard a best practice :

  • Logs are to be treated as a stream.
  • the app itself should not manage logging (redirections, storage, etc), only writing data.

If i apply this, docker should be the only one in charge for managing this stream.

If you accept this principle you can leave you start script with only

exec ./app

you can start your app by running

docker-compose up web

control-c is available if needed.

You can access the logs in another terminal and redirect them to a file

docker-compose logs -f web > web.log

I dont see the use case, but if you want to do both starting and logging to stdout and loging to a file all the time then

# run and detach
docker-compose up -d web

# save logs to a file in the background
docker-compose logs -f web > web.log 2>&1 &

# reattach to the container to be able to do control-c
# it will not rerun the container, just reattach
docker-compose up web

Upvotes: 6

wbob
wbob

Reputation: 461

could you utilize the logging capabilties of docker-compose to have both, printed stdout and a log file?

Only the json-file and journald drivers make the logs available directly from docker-compose up and docker-compose logs. Using any other driver does not print any logs

Upvotes: 2

Related Questions