16

我正在尝试从漂亮的 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 日志框架,我如何在主函数中初始化日志并使用另一个 Go 文件中的记录器?

4

4 回答 4

10

您可以在主函数中设置您的记录器并调用zap.ReplaceGlobals以将其用作默认的全局记录器。

ReplaceGlobals 替换全局 Logger 和 SugaredLogger,并返回一个函数来恢复原始值。同时使用是安全的。

于 2019-09-01T10:16:45.877 回答
9

用 zaps 的实现替换默认的 go Global 记录器是可能的,但不鼓励。

根据他们的常见问题

为什么要包含包全局记录器?由于许多其他日志记录包都包含全局记录器,因此许多应用程序并未设计为接受记录器作为显式参数。更改函数签名通常是一项重大更改,因此 zap 包含全局记录器以简化迁移。

尽可能避免它们。

根据您的需要,您可以在 main 中创建一个记录器并将其传递或在每个包中创建一个新记录器。我选择在 main 中创建一个并传递它,因为我使用的是 Atomic 记录器,它允许我在我的应用程序通过 API 调用运行时更改日志级别。由于使用 DI 和整合代码的悠久历史,它确实感觉像代码异味,但显然 zap 如何通过单例或全局传递它的性能要高得多。

于 2020-01-02T19:30:02.317 回答
2

@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 ""
}
于 2021-07-22T14:43:54.563 回答
0

我想避免替换默认的 go 记录器是个好主意,正如@ammills01所提到的。我的方法是为zap logger的配置和初始化创建一个单独的包。它还提供了包装函数实现,这在将 zap 更改为另一个日志记录工具的情况下非常有用。

package logger
import (
    "go.uber.org/zap"
    "go.uber.org/zap/zapcore"
)

var zapLog *zap.Logger

func init() {
    var err error
    config := zap.NewProductionConfig()
    enccoderConfig := zap.NewProductionEncoderConfig()
    zapcore.TimeEncoderOfLayout("Jan _2 15:04:05.000000000")
    enccoderConfig.StacktraceKey = "" // to hide stacktrace info
    config.EncoderConfig = enccoderConfig

    zapLog, err = config.Build(zap.AddCallerSkip(1))
    if err != nil {
        panic(err)
    }
}

func Info(message string, fields ...zap.Field) {
    zapLog.Info(message, fields...)
}

func Debug(message string, fields ...zap.Field) {
    zapLog.Debug(message, fields...)
}

func Error(message string, fields ...zap.Field) {
    zapLog.Error(message, fields...)
}

func Fatal(message string, fields ...zap.Field) {
    zapLog.Fatal(message, fields...)
}

因此,您项目中的任何其他文件将如下所示

import "github.com/[your_repo_path_here]/logger"

func SomeFunc() datastructures.Configuration {
    logger.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 {
        logger.Fatal("VerifyCommandLineInput | Call the tool using --config conf/config.json")
    }
    file, err := os.Open(*c)
    if err != nil {
        logger.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 {
        logger.Fatal("VerifyCommandLineInput | can't decode config JSON: ", err)
    }
    logger.Debug("VerifyCommandLineInput | Conf loaded -> ", cfg)

    return cfg
}
于 2022-02-03T15:48:09.403 回答