I code dreams™


The issue

I ran into a problem where no logging was being written to a file.

The problematic code was this:

f, err := os.OpenFile(...)
if err != nil {
	return err

mw := io.MultiWriter(os.Stdout, f)

This construct is used to log to a file and for convenience to os.Stdout as well.

At first glance it seems nothing wrong with it. However reading the docs for io.MultiWriter carefully, it says:

Each write is written to each listed writer, one at a time. If a listed writer returns an error, that overall write operation stops and returns the error; it does not continue down the list.

So what’s going on? Why would writing to STDOUT return an error? There can be several reasons, but mine was using (awesome!) to run the application at startup.

The point is - when running as a service - there is no os.Stdout because services are not interactive (in short).

There you have it :-)

The solution

This was easily remedied by reversing the order of arguments to MultiWriter.

  Non-interactive writers must be specified first, otherwise there
  will be no logging when running as a service (because there is no
  Stdout and the MultiWriter fails)

log.SetOutput(io.MultiWriter(logf, os.Stdout))

But what if writing to a file fails? Next up!

Lessons learned

Do not assume STDOUT is available and RTFM.