在包

时间:2016-04-12 21:38:57

标签: logging go scope package

所以我使用了结构化日志库(logrus),并且我有一个core包用作其他包的基础,我们可以调用此包me/core ,然后单独的包,如me/foo-serviceme/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/coreme/foo-service都有logrus库的托管版本,那些log.Set*命令会修改变量logrus.std记录器拥有标准的全局记录器,但这是两个包的单独实例,因为me/core/vendor/.../logrus/stdme/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.stdme/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使用,或者如果我以完全错误的方式考虑这个问题,我可以采取更好的方法它

1 个答案:

答案 0 :(得分:1)

您只能镜像WithFields,因为其他人接受内置类型。此外,由于logging.Fieldslogrus.Fields属于同一类型,因此您可以更简单地执行

func WithFields(f Fields) log.*Entry {
    return Log.WithFields(log.Fields(f))
}

然后在您的服务中,您可以致电

logging.Log.Debug("message")
logging.WithFields(logging.Fields{"k":"v"}).Debug("message")