使用在代码库其他部分的 main 中初始化的记录器

问题描述 投票:0回答:3

我正在努力了解如何使用zap。在文档中,他们提供了一些有关如何配置记录器以及如何使用预设的示例。但是,我不明白应该如何使用在

main.go
中初始化的记录器,它位于
cmd/server/server.go
中。根据 this SO post 和其他几篇文章,无法从包外部的
main
包导入。那么,根据 Zap 示例,我应该如何使用
pkg/endpoint/my_requests
中的记录器(
pkg
cmd
处于同一级别)?我还没有找到任何关于如何完成这样的事情的明确示例(甚至与 zap 无关);然而,我确信这是一个非常简单的问题。

go logging
3个回答
7
投票

我个人倾向于将其视为任何其他正常依赖项,并将其传递到需要的地方

package foo

type Bar struct {
    Logger logger.Logger
}

func (b *Bar) Something() {
    b.Logger.Debug("starting something")
}

func DoSomething(logger logger.Logger) {
    b := Bar{Logger: logger}
    b.Something()
}

任何涉及 init 函数的东西基本上都是全局变量

我还倾向于对我使用的任何记录器使用抽象,并赋予零值无操作行为(不记录任何内容),这在测试时特别有用,缺点是速度有点慢,因为所有方法都不是指针接收器并需要一个副本,并且我必须定义相同的方法(事实上,我抽象了糖化版本,因此我不在我的包上导入 zap)

package logger

import "go.uber.org/zap"

type Logger struct {
    zap *zap.Logger
}

func Must(logger *Logger, err error) *Logger {
    if err != nil {
        panic(err)
    }
    return logger
}

func NewLogger(logFile string) (*Logger, error) {
    zap.NewProductionConfig()
    config := zap.NewProductionConfig()
    config.OutputPaths = []string{"stdout", "./logs/" + logFile}
    logger, err := config.Build(zap.AddCaller())
    if err != nil {
        return nil, err
    }   
    return &Logger{zap: logger}, err
}

func (l Logger) Debug(msg string, fields ...zap.Field) {
    l.writer().Debug(msg, fields...)
}

func (l Logger) Info(msg string, fields ...zap.Field) {
    l.writer().Info(msg, fields...)
}
// define all the methdos

var noOpLogger = zap.NewNop()

func (l Logger) writer() *zap.Logger {
    if l.zap == nil {
        return noOpLogger
    }
    return l.zap
}

零值无操作记录器对于并发使用是安全的,并且记录器在测试期间不再处于中间

var b Bar
b.Something() // no panics

4
投票

一个好主意是创建一个负责记录器的包,或者只是创建一个像“config”或“settings”这样的包来处理像记录器这样的全局配置。

我确实在我的项目中使用 zap,并且通常有一个名为 logger 的包,它提供了一个名为

NewLogger
的基本方法,当我的包生成大量日志时,我从其他包中调用该方法来创建特定于包的记录器,并且它们是相当大的。在相当小的项目中,我只是在记录器包中初始化记录器并从外部调用它。

// /my-project/pkg/logging/logging.go
func NewLogger(logFile string) *zap.Logger {
    zap.NewProductionConfig()
    config := zap.NewProductionConfig()
    config.OutputPaths = []string{"stdout", "./logs/" + logFile}
    logger, err := config.Build(zap.AddCaller())
    if err != nil {
        panic(err)
    }
    return logger
}

然后在其他包中使用:

// /my-project/pkg/a/a.go

package a

var logger *zap.Logger

func init() {
    logger = logging.NewLogger("a.log")
}

func MyFunction() {
    logger.Info("log from package a to a.log")
}

另一个包裹:

// /my-project/pkg/b/b.go

package b

var logger *zap.Logger

func init() {
    logger = logging.NewLogger("b.log")
}

func MyFunction() {
    logger.Info("log from package b to b.log")
}

您还可以直接在包中初始化记录器,但是将记录器放在单独的包中可以帮助您随时更改配置或整个记录器,而无需在各处进行更改。

您还可以向记录器包中添加更多方法和帮助器来统一您的日志,或者只是让您的记录工作变得更轻松。


0
投票

更新的(2024 年 4 月)是使用 go 1.22 中的“log/slog”内置包

您可以创建日志,配置它,然后 SetDefault(configuredLogger)

从现在开始,您只需导入“log/slog”并直接使用它即可。这有点像你在 python 中使用 getLogger 所做的事情

完整帖子在这里: https://betterstack.com/community/guides/logging/logging-in-go/#getting-started-with-slog

© www.soinside.com 2019 - 2024. All rights reserved.