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