【问题标题】:Centralised logging configuration when sharing libraries between packages在包之间共享库时集中记录配置
【发布时间】: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/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/stdme/foo-service 可用的建议,或者如果我以完全错误的方式考虑这个问题,那么我想一个更好的方法。

【问题讨论】:

  • 我认为拥有自己的库供应商通常是不可取的,特别是出于版本不兼容和重复的原因。应用程序(主包)应该供应每个人的部门并处理冲突(如果有)。

标签: logging go scope package


【解决方案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")

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-07-31
    • 1970-01-01
    • 2023-04-10
    • 2021-08-02
    • 1970-01-01
    • 2021-07-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多