Zap logger 打印到控制台和日志文件

Posted

技术标签:

【中文标题】Zap logger 打印到控制台和日志文件【英文标题】:Zap logger print both to console and to log file 【发布时间】:2018-11-28 17:51:21 【问题描述】:

我已将 Zap 与我的 go 应用程序集成,我们将日志打印在两个日志文件中,并且我还使用 Lumberjack 进行日志轮换。但我也试图在控制台中显示日志,但这种情况没有运气。 以下是我在 logger.go 中的代码

var (
    Logger *zap.Logger
    N2n    *zap.Logger
)

type WriteSyncer struct 
    io.Writer


func (ws WriteSyncer) Sync() error 
    return nil


func InitLogging(mode string) 
    var cfg zap.Config
    var logName = "abc.log"
    var slogName = "n2n.log"

    if mode == "production" 
        cfg = zap.NewProductionConfig()
        cfg.DisableCaller = true
     else 
        cfg = zap.NewDevelopmentConfig()
        cfg.EncoderConfig.LevelKey = "level"
        cfg.EncoderConfig.NameKey = "name"
        cfg.EncoderConfig.MessageKey = "msg"
        cfg.EncoderConfig.CallerKey = "caller"
        cfg.EncoderConfig.StacktraceKey = "stacktrace"
    

    cfg.Encoding = "json"
    cfg.EncoderConfig.TimeKey = "timestamp"
    cfg.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
    cfg.OutputPaths = []stringlogName
    sw := getWriteSyncer(logName)
    swSugar := getWriteSyncer(slogName)

    l, err := cfg.Build(SetOutput(sw, cfg))
    if err != nil 
        panic(err)
    
    defer l.Sync()

    ls, err := cfg.Build(SetOutput(swSugar, cfg))
    if err != nil 
        panic(err)
    
    defer ls.Sync()

    Logger = l
    N2n = ls


// SetOutput replaces existing Core with new, that writes to passed WriteSyncer.
func SetOutput(ws zapcore.WriteSyncer, conf zap.Config) zap.Option 
    var enc zapcore.Encoder
    switch conf.Encoding 
    case "json":
        enc = zapcore.NewJSONEncoder(conf.EncoderConfig)
    case "console":
        enc = zapcore.NewConsoleEncoder(conf.EncoderConfig)
    default:
        panic("unknown encoding")
    

    return zap.WrapCore(func(core zapcore.Core) zapcore.Core 
        return zapcore.NewCore(enc, ws, conf.Level)
    )


func getWriteSyncer(logName string) zapcore.WriteSyncer 
    var ioWriter = &lumberjack.Logger
        Filename:   logName,
        MaxSize:    10, // MB
        MaxBackups: 3,  // number of backups
        MaxAge:     28, //days
        LocalTime:  true,
        Compress:   false, // disabled by default
    
    var sw = WriteSyncer
        ioWriter,
    
    return sw

我已尝试附加输出路径,但它不起作用。

【问题讨论】:

【参考方案1】:

由于这是在 Google 上查找此内容后首先出现的内容之一,因此这里有一个简单示例,说明如何在控制台上显示日志和一个日志文件,该文件可以是任何 io.Writer 作为由伐木工人:

func logInit(d bool, f *os.File) *zap.SugaredLogger 

    pe := zap.NewProductionEncoderConfig()

    fileEncoder := zapcore.NewJSONEncoder(pe)

    pe.EncodeTime = zapcore.ISO8601TimeEncoder # The encoder can be customized for each output
    consoleEncoder := zapcore.NewConsoleEncoder(pe)

    level := zap.InfoLevel
    if d 
        level = zap.DebugLevel
    

    core := zapcore.NewTee(
        zapcore.NewCore(fileEncoder, zapcore.AddSync(f), level),
        zapcore.NewCore(consoleEncoder, zapcore.AddSync(os.Stdout), level),
    )

    l := zap.New(core) # Creating the logger

    return l.Sugar()

我使用了默认的 ProductionEncoderConfig,但它可以是自定义的,就像 OP 代码中的那样。

【讨论】:

【参考方案2】:

发现zapcore 有zapcore.NewMultiWriteSyncer,它可以将日志写入文件中,也可以使用zapcore.addSync(os.stdout) 将日志写入控制台。

例如:

swSugar := zapcore.NewMultiWriteSyncer(
    zapcore.AddSync(os.Stdout), 
    getWriteSyncer(logfileName),
)

【讨论】:

【参考方案3】:

你也可以使用zap.CombineWriteSyncers:

CombineWriteSyncers 是一种实用程序,可将多个 WriteSyncer 组合成一个锁定的 WriteSyncer。如果未提供输入,则返回无操作 WriteSyncer。

提供它纯粹是为了方便;结果与单独使用zapcore.NewMultiWriteSyncer和zapcore.Lock没有什么不同。

    syncer := zap.CombineWriteSyncers(os.Stdout, getWriteSyncer(logfileName))

    core := zapcore.NewCore(enc, syncer, zap.NewAtomicLevelAt(zap.InfoLevel))
    zap.New(core)

【讨论】:

以上是关于Zap logger 打印到控制台和日志文件的主要内容,如果未能解决你的问题,请参考以下文章

Go语言系列之日志库zap

Uber Zap 记录器未在日志语句中打印调用者信息

如何使用 go.uber.org/zap lib 以不同的日志级别打印不同的颜色,并根据日志级别将日志附加到不同的文件?

如何测试从自定义配置构建的 zap Logger 的日志记录?

day17 logging 日志模块

Go语言项目中使用zap日志库(翻译)