如何初始化一次 zap 记录器并在其他 Go 文件中重用它?
Posted
技术标签:
【中文标题】如何初始化一次 zap 记录器并在其他 Go 文件中重用它?【英文标题】:How to initialize a zap logger once and reuse it in other Go files? 【发布时间】:2020-01-04 18:53:15 【问题描述】:我正在尝试从漂亮的 Logrus 迁移我的应用程序(对调试非常有帮助)并引入 Uber 日志框架 Zap。
使用 Logrus,我可以只初始化一次记录器并从其他 Go 文件中重复使用它,例如:
package main
import(
// Print filename on log
filename "github.com/onrik/logrus/filename"
// Very nice log library
log "github.com/sirupsen/logrus"
)
func main()
// ==== SET LOGGING
Formatter := new(log.TextFormatter)
Formatter.TimestampFormat = "Jan _2 15:04:05.000000000"
Formatter.FullTimestamp = true
Formatter.ForceColors = true
log.AddHook(filename.NewHook()) // Print filename + line at every log
log.SetFormatter(Formatter)
从其他 Go 文件中,我无需任何其他初始化即可重用该记录器:
// VerifyCommandLineInput is delegated to manage the inputer parameter provide with the input flag from command line
func VerifyCommandLineInput() datastructures.Configuration
log.Debug("VerifyCommandLineInput | Init a new configuration from the conf file")
c := flag.String("config", "./conf/test.json", "Specify the configuration file.")
flag.Parse()
if strings.Compare(*c, "") == 0
log.Fatal("VerifyCommandLineInput | Call the tool using --config conf/config.json")
file, err := os.Open(*c)
if err != nil
log.Fatal("VerifyCommandLineInput | can't open config file: ", err)
defer file.Close()
decoder := json.NewDecoder(file)
cfg := datastructures.Configuration
err = decoder.Decode(&cfg)
if err != nil
log.Fatal("VerifyCommandLineInput | can't decode config JSON: ", err)
log.Debug("VerifyCommandLineInput | Conf loaded -> ", cfg)
return cfg
我的问题是:使用 Zap 日志框架,如何在 main 函数中初始化日志并使用另一个 Go 文件中的记录器?
【问题讨论】:
【参考方案1】:您可以在主函数中设置您的记录器并调用https://godoc.org/go.uber.org/zap#ReplaceGlobals 将其用作默认的全局记录器。
【讨论】:
Github 上的常见问题解答明确指出,您应该尽可能避免使用全局变量。【参考方案2】:用 zaps 的实现替换默认的 go Global 记录器是可能的,但不鼓励。
根据他们的FAQ
为什么要包含包全局记录器?由于有这么多其他日志记录 软件包包括一个全局记录器,许多应用程序并非旨在 接受记录器作为显式参数。更改函数签名是 通常是重大更改,因此 zap 包含全局记录器以简化 迁移。
尽可能避免使用它们。
根据您的需要,您可以在 main 中创建一个记录器并将其传递或在每个包中创建一个新记录器。我选择在 main 中创建一个并传递它,因为我使用的是 Atomic 记录器,它允许我在我的应用程序通过 API 调用运行时更改日志级别。由于使用 DI 和整合代码的悠久历史,它确实感觉像代码异味,但显然 zap 如何通过单例或全局传递它的性能要高得多。
【讨论】:
【参考方案3】:@alessiosavi 最初发布到问题中的答案。
初始化一个新日志并设置为@Mikhail 所指的全局。
package main
import(
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
func initZapLog() *zap.Logger
config := zap.NewDevelopmentConfig()
config.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
config.EncoderConfig.TimeKey = "timestamp"
config.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
logger, _ := config.Build()
return logger
func main()
loggerMgr := initZapLog()
zap.ReplaceGlobals(loggerMgr)
defer loggerMgr.Sync() // flushes buffer, if any
logger := loggerMgr.Sugar()
logger.Debug("START!")
db2.GetToken(`alessio`, `savi`, `pass`)
datastructure.LoadConfiguration()
你可以在其他 Go 文件中使用记录器:
func GetToken(url, user, pass string) string
var User datastructure.User
var data string
var jsonData []byte
User.User = user
User.Pass = pass
jsonData, err := json.Marshal(User)
if err != nil
zap.S().Errorw("Error during marshalling...", err)
return ""
data = string(jsonData)
zap.S().Info("Data encoded => ", data)
return ""
【讨论】:
我相信首选的方法是使用依赖注入,因此将记录器作为参数传递给 GetToken。我希望文档对此更清楚。以上是关于如何初始化一次 zap 记录器并在其他 Go 文件中重用它?的主要内容,如果未能解决你的问题,请参考以下文章
如何将 Sentry 与 go.uber.org/zap/zapcore 记录器一起使用