gologgingzerolog

How to use zerolog to filter INFO logs to stdout and ERROR logs to stderr?


I'm using zerolog for Go logging:

zerolog.SetGlobalLevel(zerolog.InfoLevel)
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: "15:04:05"})

This prints all the messages into the os.Stderr, but I want to split the logs into multiple outputs, with the next condition:

DebugLevel, InfoLevel, and WarnLevel will be printed to os.Stdout,
and ErrorLevel, FatalLevel, and PanicLevel will be printed to os.Stderr.

How can I achieve that?


Solution

  • You need to use MultiLevelWriter, to forward the logs into multiple LevelWriters outputs (although it is not in the function signature, you should give it LevelWriters, otherwise it will not do any special logic).

    The LevelWriter is an interface with io.Writer and WriteLevel(level Level, p []byte) (n int, err error), so you can add any zerolog writer you want (since it is an io.Writer), and use it with a level condition on WriteLevel.

    Here is an example for a LevelWriter:

    type SpecificLevelWriter struct {
        io.Writer
        Levels []zerolog.Level
    }
    
    func (w SpecificLevelWriter) WriteLevel(level zerolog.Level, p []byte) (int, error) {
        for _, l := range w.Levels {
            if l == level {
                return w.Write(p)
            }
        }
        return len(p), nil
    }
    

    Now you need to use it twice with MultiLevelWriter:

    func CreateLogger() zerolog.Logger {
        writer := zerolog.MultiLevelWriter(
            SpecificLevelWriter{
                Writer: zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: "15:04:05"},
                Levels: []zerolog.Level{
                    zerolog.DebugLevel, zerolog.InfoLevel, zerolog.WarnLevel,
                },
            },
            SpecificLevelWriter{
                Writer: zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: "15:04:05"},
                Levels: []zerolog.Level{
                    zerolog.ErrorLevel, zerolog.FatalLevel, zerolog.PanicLevel,
                },
            },
        )
    
        return zerolog.New(writer).Logger()
    }
    

    Note that as I said, zerologs loggers are io.Writer, you can replace the os.Stdout with zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: "15:04:05"}