【发布时间】:2016-08-03 17:34:44
【问题描述】:
所以我正在使用结构化日志库 (logrus),并且我有一个 core 包用作其他一些包的基础,让我们将此包称为 me/core,然后是单独的包,如 me/foo-service , me/bar-service 等使用此核心库进行常见的依赖项/实用程序,例如设置,配置加载,我还想将它用于标准化的事情,例如日志记录,所以我希望 me/core 能够为其他包,使用 Logrus 你可以做类似的事情
import(
log "github.com/Sirupsen/logrus"
)
[...]
log.SetLevel(log.DebugLevel)
log.SetFormatter(&log.TextFormatter{FullTimestamp:true})
然后做;
log.Debug("Moo")
log.WithFields(log.Fields{"structured":"data"}).Debug("I have structure data")
得到类似的输出
> DEBU[2016-04-12T22:11:38+01:00] Moo
> DEBU[2016-04-12T22:11:38+01:00] I have structure data structured=data
所以我想在我的 me/foo-service 包中配置它,比如
import(
"me/core/logging"
)
func main(){
logging.Setup()
}
仅出于各种原因,我遇到了问题。主要问题似乎是me/core 和me/foo-service 都有logrus 库的供应版本,那些log.Set* 命令修改变量logrus.std 记录器,它包含标准的全局记录器,但这是两个包的单独实例,因为 me/core/vendor/.../logrus/std 和 me/foo-service/vendor/.../logrus/std 是不同的对象。
我尝试的第一件事是在me/core/logging 中创建一个可以在父级中使用的变量,例如
package logging
import(
log "github.com/Sirupsen/logrus"
)
var Log *log.Logger
func Setup(verbose bool){
Log = log.New()
if verbose{
Log.Level = log.DebugLevel
} else {
Log.Level = log.InfoLevel
}
Log.Formatter = &log.TextFormatter{FullTimestamp:true}
Log.Debug("Logging verbosely")
}
这适用于像这样的简单情况
package main
import(
"me/core/logging"
)
func main() {
logging.Setup(parsedOptions.Verbose)
logging.Log.Debug("Moo")
}
但是尝试使用结构化数据 Fields 会导致问题,我无法使用本地供应的 logrus 字段,例如
logging.Log.WithFields(log.Fields{"data":"hi"}).Debug("test")
当我得到
cannot use "me/foo-service/vendor/github.com/Sirupsen/logrus".Fields literal (type "me/foo-service/vendor/github.com/Sirupsen/logrus".Fields) as type "me/core/vendor/github.com/Sirupsen/logrus".Fields in argument to logging.Log.WithFields
并尝试使用类似的东西来镜像me/core/logging 中的字段
type Fields log.Fields
以太不工作,因为它仍然是不同的类型
cannot use logging.Fields literal (type logging.Fields) as type "me/core/vendor/github.com/Sirupsen/logrus".Fields in argument to logging.Log.WithFields
我也想不出任何方法可以将我的本地 log.std 从 me/foo-service 传递到 me/core,因为它也是一种不同的类型,因为供应商的包。
我目前的工作涉及为每个方法创建一个镜像,所以在me/core/logging 我有一个类似的设置
package logging
import(
log "github.com/Sirupsen/logrus"
)
var Log *log.Logger
type Fields map[string]interface{}
func Setup(verbose bool){
Log = log.New()
if verbose{
Log.Level = log.DebugLevel
} else {
Log.Level = log.InfoLevel
}
Log.Formatter = &log.TextFormatter{FullTimestamp:true}
Log.Debug("Logging verbosely")
}
func Debug(msg interface{}){
Log.Debug(msg)
}
func WithFields(fields Fields) *log.Entry{
lf := log.Fields{}
for k,v := range fields{
lf[k] = v
}
return Log.WithFields(lf)
}
但这将涉及为 每个 方法创建一个镜像,这似乎真的很低效。
所以我想要一个关于如何使me/core/vendor/.../logrus/std 对me/foo-service 可用的建议,或者如果我以完全错误的方式考虑这个问题,那么我想一个更好的方法。
【问题讨论】:
-
我认为拥有自己的库供应商通常是不可取的,特别是出于版本不兼容和重复的原因。应用程序(主包)应该供应每个人的部门并处理冲突(如果有)。