Project

General

Profile

Actions

Feature #2731

closed

Cannot log to standard output in Docker (user error)

Added by acaron about 8 years ago. Updated almost 8 years ago.

Status:
Invalid
Priority:
Low
Category:
core
Target version:
-
ASK QUESTIONS IN Forums:

Description

Hi there!

I'm trying to use lighttpd inside a Docker container. There are a few recipes out there, but none of them seem to be able to send the access logs and error logs to the standard output when running in foreground mode (if you haven't used Docker before, let me know and I'll explain why this is important).

Anyways, the usual trick (for Apache and NGINX) is to do something like this:

server.errorlog = "/dev/stderr" 
accesslog.filename = "/dev/stdout" 

However, this doesn't work with lighttpd: when I use that, there are no errors but all logs disappear. I looked up the source code and it seems like the standard streams are explicitly closed and redirected to /dev/null like so:

/* close stdin and stdout, as they are not needed */
openDevNull(STDIN_FILENO);
openDevNull(STDOUT_FILENO);

While this is fine when running lighttpd as a daemon, I'm wondering if we could add an exception when running in foreground mode lilke this:

/* close stdin and stdout, as they are not needed */
if (srv->srvconf.dont_daemonize == 0) {
    openDevNull(STDIN_FILENO);
    openDevNull(STDOUT_FILENO);
}

I tried this out locally and it works like a charm. I get all the output on stdout, my Docker setup collects the logs and sends them all to ElasticSearch for real-time searching of all my logs.

Any chance you'd be willing to accept a patch that changes this?

Thanks!

André


Files

keep-stdio-in-foreground.patch (795 Bytes) keep-stdio-in-foreground.patch acaron, 2016-05-17 23:10
Actions #1

Updated by acaron about 8 years ago

Adding a patch as described. Hoping you'll consider this!

Actions #2

Updated by gstrauss about 8 years ago

  • Tracker changed from Bug to Feature

Changing to feature request. Please don't open bugs for feature requests.

lighttpd re-opens stdin and stdout to /dev/null to ensure that no child process (such as CGI, SSI, etc) inherits these descriptors from the terminal or parent process, whether or not lighttpd is run as foreground or background daemon. For that reason, I'm sorry, but your patch can not be accepted.

Why is combining stdout and stderr a good idea? Please explain. (This is a more general question than "convenience with ElasticSearch", which is, in turn, more general than "this is the way I have configured Docker with ElasticSearch".) Do you really think you're the first person to use lighttpd with Docker on AWS, and use ElasticSearch? That seems unlikely.

If you start lighttpd with ./lighttpd -D, then lighttpd will stay in the foreground, and stderr will remain open.
Starting lighttpd with ./lighttpd -D 2>&1 will allow you to have stderr sent to stdout.

Now, access logs are something completely different from stderr. You can use lighttpd without mod_accesslog.

However, if you use the above suggestion and keep lighttpd in the foreground and send stderr to stdout, I suppose that you can set your accesslog to "/dev/stderr" to have your access logs sent to the same place stderr is sent. (I have not tested this, but think it will work for you.)

Actions #3

Updated by gstrauss about 8 years ago

  • Status changed from New to Need Feedback
  • Priority changed from Normal to Low
Actions #4

Updated by gstrauss about 8 years ago

  • Subject changed from Cannot log to standard output in Docker to Cannot log to standard output in Docker (user error)
  • Status changed from Need Feedback to Fixed

As above:

server.modules += ( "mod_accesslog" )
accesslog.filename  = "/dev/stderr" 

and start up lighttpd with
/path/to/lighttpd -D -f /path/to/lighttpd.conf 2>&1

Actions #5

Updated by willydee68 about 8 years ago

I am currently struggling with the very same problem. In the meantime I've found out that the error output can be shown in the docker logs by omitting server.errorlog in lighttpd.conf. But for a useful debugging workflow, one needs also to be able to inspect the access logs when attaching to the container's log collector. Please kindly have another look at the issue.

Dockerfile:

FROM ubuntu:latest
RUN apt-get update && apt-get install -y --allow-unauthenticated --no-install-recommends lighttpd
COPY lighttpd.conf /etc/lighttpd/lighttpd.conf
CMD ["lighttpd", "-D", "-f", "/etc/lighttpd/lighttpd.conf", "2>&1"]

docker-compose.yml:

version: '2'
services:
  www:
    build: www
    ports:
      - "80:80" 

Relevant parts of lighttpd.conf:

#server.errorlog = "/dev/stderr" # omitting it makes error output work
server.modules += ( "mod_accesslog" )
$HTTP["host"] == "localhost" {
  accesslog.filename = "/dev/stderr" 
}

Output of docker-compose up:
Creating network "lighttpd_default" with the default driver
Creating lighttpd_www_1
Attaching to lighttpd_www_1
www_1  | 2016-05-19 06:59:15: (log.c.118) opening errorlog '/dev/stderr' failed: Permission denied
www_1  | 2016-05-19 07:04:36: (server.c.1022) Configuration of plugins failed. Going down.
lighttpd_www_1 exited with code 255

Actions #6

Updated by gstrauss about 8 years ago

willydee68: you're using the instructions I gave and you noted that server.errorlog should be commented out.

What is not working as you expect? Please be more specific.

Why aren't you using accesslog.filename = "/dev/stderr" at the global scope instead of only in $HTTP["host"] conditional?

Actions #7

Updated by acaron about 8 years ago

Thanks for the tip about sending stuff to stderr. Works for me :-)

I guess you can close this as "not a defect" if you like since it's actually possible to do what I was requesting out of the box.

Actions #8

Updated by willydee68 about 8 years ago

gstrauss: I cannot be more specific than pasting the error message (again):

2016-05-19 06:59:15: (log.c.118) opening errorlog '/dev/stderr' failed: Permission denied

It does not matter if the statement accesslog.filename = "/dev/stderr" is placed in global scope or a location, it raises an error each time the service is started, and the service exits. No access log output.

Actions #9

Updated by gstrauss about 8 years ago

acaron: would you mind posting your Docker config for willydee68?

willydee68: As you can see above, what I posted works for acaron. Did you google "docker and your error"?
Permission denied on /dev/stderr #6880
https://github.com/docker/docker/issues/6880
Perhaps you're running an old version of Docker? See the link for potential workarounds.
Also suggested: http://unix.stackexchange.com/questions/38538/bash-dev-stderr-permission-denied

Actions #10

Updated by willydee68 about 8 years ago

acaron: Yes a dockerfile might be helpful; it seems I've missed something...

gstrauss: Docker version 1.11.1, should be the most recent release. I've found an approach on Stackexchange to launch Node.js in a container as nonprivileged user, but this also does not work for lighttpd, since it cannot bind to port 80 or 443 then.

Actions #11

Updated by gstrauss about 8 years ago

willydee68: if you're starting as root, then once lighttpd drops privileges, it won't be able to open /dev/stderr

However, you can change the permissions (as root) before running lighttpd as root.
$ chown lighttpd /dev/stderr && /path/to/lighttpd -D -f /path/to/lighttpd.conf 2>&1

Actions #12

Updated by willydee68 about 8 years ago

gstrauss: Understood. Created a docker-entrypoint.sh script doing that:

#!/bin/bash
/bin/chown www-data /dev/stderr && /usr/sbin/lighttpd -D -f /etc/lighttpd/lighttpd.conf 2>&1

Alas, same error:
2016-05-20 11:57:57: (log.c.118) opening errorlog '/dev/stderr' failed: Permission denied
2016-05-20 11:57:57: (server.c.1022) Configuration of plugins failed. Going down.

Actions #13

Updated by gstrauss about 8 years ago

Please test your script outside a docker environment to make sure it works outside Docker.

The usage here (which works for acaron) is similar to what I have seen posted for working with nginx inside Docker.

I'm sorry, but this isn't a Docker help forum, so I recommend the Docker forums. Please post a link here to your post so that we can all learn.

If all else fails, I suppose lighttpd could special case the string "/dev/stderr" when opening log files and simply dup2() STDERR_FILENO. That wouldn't be a difficult patch in log.c. Before doing that, I'd like to hear what the Docker forum recommends since what works for nginx logging should, in a similar fashion, also work for lighttpd logging.

Actions #14

Updated by willydee68 about 8 years ago

Checked the same command line outside Docker under Ubuntu 16.04 LTS, running the given command line as root. Without the chown www-data /dev/stderr, it fails with permission denied, but with chown, it works indeed as expected, and both access and error log are echoed into the console. So it is a Docker-only problem. I will raise the issue there. Thanks for helping to track this down.

Actions #15

Updated by willydee68 about 8 years ago

Yay, got it running! https://github.com/docker/docker/issues/6880#issuecomment-170214851 has the workaround.

docker-entrypoint.sh:

#!/bin/bash
mkfifo -m 600 /tmp/logpipe
cat <> /tmp/logpipe 1>&2 &
chown www-data /tmp/logpipe
/usr/sbin/lighttpd -D -f /etc/lighttpd/lighttpd.conf 2>&1

lighttpd.conf:
accesslog.filename = "/tmp/logpipe" 

Both error and access log are now printed to the docker logs collector.

Actions #16

Updated by stbuehler almost 8 years ago

  • Status changed from Fixed to Invalid
  • Target version deleted (1.4.x)
Actions

Also available in: Atom