ale*_*avi 14 logging go go-zap
我正在尝试从漂亮的 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)
}
Run Code Online (Sandbox Code Playgroud)
从其他 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
}
Run Code Online (Sandbox Code Playgroud)
我的问题是:使用 Zap 日志框架,如何在主函数中初始化日志并使用其他 Go 文件中的记录器?
小智 14
我认为避免替换默认的 go 记录器是个好主意,正如@ammills01所提到的提到的那样。\n我的方法是为 zap logger\xe2\x80\x99s 配置和初始化创建一个单独的包。它还提供了包装函数实现,在将 zap 更改为另一个日志记录工具时非常有用。
\npackage logger\nimport (\n "go.uber.org/zap"\n "go.uber.org/zap/zapcore"\n)\n\nvar zapLog *zap.Logger\n\nfunc init() {\n var err error\n config := zap.NewProductionConfig()\n enccoderConfig := zap.NewProductionEncoderConfig()\n zapcore.TimeEncoderOfLayout("Jan _2 15:04:05.000000000")\n enccoderConfig.StacktraceKey = "" // to hide stacktrace info\n config.EncoderConfig = enccoderConfig\n\n zapLog, err = config.Build(zap.AddCallerSkip(1))\n if err != nil {\n panic(err)\n }\n}\n\nfunc Info(message string, fields ...zap.Field) {\n zapLog.Info(message, fields...)\n}\n\nfunc Debug(message string, fields ...zap.Field) {\n zapLog.Debug(message, fields...)\n}\n\nfunc Error(message string, fields ...zap.Field) {\n zapLog.Error(message, fields...)\n}\n\nfunc Fatal(message string, fields ...zap.Field) {\n zapLog.Fatal(message, fields...)\n}\nRun Code Online (Sandbox Code Playgroud)\n所以您的项目中的任何其他文件将如下所示
\nimport "github.com/[your_repo_path_here]/logger"\n\nfunc SomeFunc() datastructures.Configuration {\n logger.Debug("VerifyCommandLineInput | Init a new configuration from the conf file")\n c := flag.String("config", "./conf/test.json", "Specify the configuration file.")\n flag.Parse()if strings.Compare(*c, "") == 0 {\n logger.Fatal("VerifyCommandLineInput | Call the tool using --config conf/config.json")\n }\n file, err := os.Open(*c)\n if err != nil {\n logger.Fatal("VerifyCommandLineInput | can\'t open config file: ", err)\n }\n defer file.Close()\n decoder := json.NewDecoder(file)\n cfg := datastructures.Configuration{}\n err = decoder.Decode(&cfg)\n if err != nil {\n logger.Fatal("VerifyCommandLineInput | can\'t decode config JSON: ", err)\n }\n logger.Debug("VerifyCommandLineInput | Conf loaded -> ", cfg)\n\n return cfg\n}\nRun Code Online (Sandbox Code Playgroud)\n
您可以在主函数中设置记录器并调用https://godoc.org/go.uber.org/zap#ReplaceGlobals将其用作默认全局记录器。
用 zaps 的实现替换默认的 go Global 记录器是可能的,但不鼓励。
根据他们的常见问题解答
为什么包括包全局记录器?由于许多其他日志包包含全局记录器,因此许多应用程序并未设计为接受记录器作为显式参数。更改函数签名通常是一个重大更改,因此 zap 包含全局记录器以简化迁移。
尽可能避免它们。
根据您的需要,您可以在 main 中创建一个记录器并将其传递或在每个包中创建一个新的记录器。我选择在 main 中创建一个并传递它,因为我使用的是 Atomic 记录器,它允许我在我的应用程序通过 API 调用运行时更改日志级别。使用 DI 和合并代码的历史悠久,一般来说确实感觉像代码异味,但显然 zap 如何在单例或全局上传递它的性能要高得多。