Make a Docker application write to stdout

Solution 1:

An amazing recipe is given in the nginx Dockerfile:

# forward request and error logs to docker log collector
RUN ln -sf /dev/stdout /var/log/nginx/access.log \
    && ln -sf /dev/stderr /var/log/nginx/error.log

Simply, the app can continue writing to it as a file, but as a result the lines will go to stdout & stderr!

Solution 2:

For a background process in a docker container, e.g. connecting with exec to /bin/bash I was able to use.

echo "test log1" >> /proc/1/fd/1

This sends the output to the stdout of pid 1, which is the one docker pickups up.


Solution 3:

In another question, Kill child process when the parent exits, I got the response that helped to sort this out.

This way, we configure the application so it logs to a file, and continuously tail -f it. Luckily, tail can accept --pid PID: it will exit when the specified process exits. We put $$ there: PID of the current shell.

As a final step, the launched application is exec'ed, which means that the current shell is completely replaced with that application.

Runner script, run.sh, will look like this:

#! /usr/bin/env bash
set -eu

rm -rf /var/log/my-application.log
tail --pid $$ -F /var/log/my-application.log &

exec /path/to/my-application --logfile /var/log/my-application.log

NOTE: by using tail -F we list filenames, and it will read them even if they appear later!

Finally, the minimalistic Dockerfile:

FROM ubuntu
ADD run.sh /root/run.sh
CMD ['/root/run.sh']

Note: to workaroung some extremely strange tail -f behavior (which says "has been replaced with a remote file. giving up on this name") i tried another approach: all known log files are created & truncated on start up: this way I ensure they exist, and only then -- tail them:

#! /usr/bin/env bash
set -eu

LOGS=/var/log/myapp/

( umask 0 && truncate -s0 $LOGS/http.{access,error}.log )
tail --pid $$ -n0 -F $LOGS/* &

exec /usr/sbin/apache2 -DFOREGROUND

Solution 4:

for nginx you can have nginx.conf pointing to /dev/stderr and /dev/stdout like this

user  nginx;
worker_processes  4;
error_log  /dev/stderr;
http {
    access_log  /dev/stdout  main;
...

and your Dockerfile entry should be

/usr/sbin/nginx -g 'daemon off;'