Golang logrus - how to do a centralized configuration?

You don't need to set these options in each file with Logrus.

You can import Logrus as log:

import log "github.com/Sirupsen/logrus"

Then functions like log.SetOutput() are just functions and modify the global logger and apply to any file that includes this import.

You can create a package global log variable:

var log = logrus.New()

Then functions like log.SetOutput() are methods and modify your package global. This is awkward IMO if you have multiple packages in your program, because each of them has a different logger with different settings (but maybe that's good for some use cases). I also don't like this approach because it confuses goimports (which will want to insert log into your imports list).

Or you can create your own wrapper (which is what I do). I have my own log package with its own logger var:

var logger = logrus.New()

Then I make top-level functions to wrap Logrus:

func Info(args ...interface{}) {
    logger.Info(args...)
}

func Debug(args ...interface{}) {
    logger.Debug(args...)
}

This is slightly tedious, but allows me to add functions specific to my program:

func WithConn(conn net.Conn) *logrus.Entry {
    var addr string = "unknown"
    if conn != nil {
        addr = conn.RemoteAddr().String()
    }
    return logger.WithField("addr", addr)
}

func WithRequest(req *http.Request) *logrus.Entry {
    return logger.WithFields(RequestFields(req))
}

So I can then do things like:

log.WithConn(c).Info("Connected")

(I plan in the future to wrap logrus.Entry into my own type so that I can chain these better; currently I can't call log.WithConn(c).WithRequest(r).Error(...) because I can't add WithRequest() to logrus.Entry.)


This is the solution that I arrived at for my application that allows adding of fields to the logging context. It does have a small performance impact due to the copying of context base fields.

package logging

import (
    log "github.com/Sirupsen/logrus"
)

func NewContextLogger(c log.Fields) func(f log.Fields) *log.Entry {
    return func(f log.Fields) *log.Entry {
        for k, v := range c {
            f[k] = v
        }
        return log.WithFields(f)
    }
}

package main

import (
    "logging"
)

func main {
    app.Logger = logging.NewContextLogger(log.Fields{
        "module":    "app",
        "id":   event.Id,
    })
    app.Logger(log.Fields{
        "startTime": event.StartTime,
        "endTime":   event.EndTime,
        "title":     event.Name,
    }).Info("Starting process")
}