英文:
Golang logrus - how to do a centralized configuration?
问题
我正在使用Go应用程序中的logrus。我相信这个问题也适用于其他日志记录包(不提供外部文件配置)。
logrus提供了设置各种配置的函数,例如SetOutput、SetLevel等。
和其他应用程序一样,我需要从多个源文件/包进行日志记录,似乎你需要在每个文件中设置这些选项。
有没有办法在一个中心位置设置这些选项,以便在整个应用程序中共享?这样,如果我需要更改日志记录级别,我只需在一个地方进行更改,就会应用于应用程序的所有组件。
英文:
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.
logrus provides functions to setup various configuration, e.g. SetOutput, SetLevel etc.
Like any other application I need to do logging from multiple source files/packages, it seems you need to setup these options in each file with logrus.
Is there any way to setup these options once somewhere in a central place to be shared all over the application. That way if I have to make logging level change I can do it in one place and applies to all the components of the app.
答案1
得分: 44
你不需要在每个文件中设置这些选项来使用Logrus。
你可以将Logrus作为log
导入:
import log "github.com/Sirupsen/logrus"
然后像log.SetOutput()
这样的函数就是普通的函数,会修改全局的日志记录器,并适用于包含此导入的任何文件。
你可以创建一个包级别的全局log
变量:
var log = logrus.New()
然后像log.SetOutput()
这样的函数就是方法,会修改你的包级别的全局变量。如果你的程序中有多个包,这种方式可能会有些尴尬,因为每个包都有不同的日志记录器和不同的设置(但对于某些用例来说可能是好事)。我也不喜欢这种方式,因为它会让goimports
感到困惑(它会想要将log
插入到你的导入列表中)。
或者你可以创建自己的包装器(这是我所做的)。我有自己的log
包,其中有自己的logger
变量:
var logger = logrus.New()
然后我创建顶层函数来包装Logrus:
func Info(args ...interface{}) {
logger.Info(args...)
}
func Debug(args ...interface{}) {
logger.Debug(args...)
}
这有点繁琐,但允许我添加特定于我的程序的函数:
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))
}
因此,我可以这样做:
log.WithConn(c).Info("Connected")
(我计划将logrus.Entry
包装成我自己的类型,以便更好地链式调用这些方法;目前我无法调用log.WithConn(c).WithRequest(r).Error(...)
,因为我无法将WithRequest()
添加到logrus.Entry
中。)
英文:
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
.)
答案2
得分: 1
这是我为我的应用程序提供的解决方案,允许向日志上下文中添加字段。由于上下文基本字段的复制,它确实会对性能产生一些影响。
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")
}
英文:
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")
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论