Golang logrus - how to do a centralized configuration?

后端 未结 2 1686
臣服心动
臣服心动 2020-12-23 22:51

I am using logrus in a Go app. I believe this question is applicable to any other logging package (which doesn\'t offer external file based configuration) as well.

l

相关标签:
2条回答
  • 2020-12-23 23:37

    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")
    }
    
    0 讨论(0)
  • 2020-12-23 23:47

    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.)

    0 讨论(0)
提交回复
热议问题