How to configure uber-go/zap logger for rolling filesystem log?
Asked Answered
A

3

6

How to configure uber-go/zap logger api to append logs to a specified file-path. Can it be made to work like rolling file-appender (based on file-size or date) without affecting performance?

Alvira answered 1/8, 2017 at 14:23 Comment(2)
What os are you on? How is your app running? How are you logging now?Essence
I generally recommend apps log to stdout/stderr and have syslog or some other tool redirect that to rotating log files.Essence
R
8

A hook can be added to the zap logger which writes the entries to lumberjack, a rolling log for Go.

A simple usage would look like this:

The rolling log:

// remember to call this at app (or scope) exit:
// logger.Close()
var lumlog = &lumberjack.Logger{
    Filename:   "/tmp/my-zap.log",
    MaxSize:    10, // megabytes
    MaxBackups: 3,  // number of log files
    MaxAge:     3,  // days
}

The zap compatible hook:

func lumberjackZapHook(e zapcore.Entry) error {
    lumlog.Write([]byte(fmt.Sprintf("%+v", e)))
    return nil
}

And use it like:

logger, _ := zap.NewProduction(zap.Hooks(lumberjackZapHook))

Edit 1: I'm not sure if this meets your requirement in terms of performance. There are many factors there. For example using SSD hards make a big difference, or even logging into some timeseries databases with batch writes.

Edit 2: In zap documentation too, it uses lumberjack (but not as a hook).

Rheostat answered 1/8, 2017 at 17:18 Comment(0)
A
1

If you want to use both console log and rolling log without hook then you can do the following:

// NewProductionZapLogger will return a new production logger backed by zap
func NewProductionZaplogger() (Logger, error) {
    conf := zap.NewProductionConfig()
    conf.Level = zap.NewAtomicLevelAt(zap.DebugLevel)
    conf.DisableCaller = true
    conf.DisableStacktrace = true
    zapLogger, err := conf.Build(zap.WrapCore(zapCore))

    return zpLg{
        lg: zapLogger.Sugar(),
    }, err
}

func zapCore(c zapcore.Core) zapcore.Core {
    // lumberjack.Logger is already safe for concurrent use, so we don't need to
    // lock it.
    w := zapcore.AddSync(&lumberjack.Logger{
        Filename:   "./chat.log",
        MaxSize:    50, // megabytes
        MaxBackups: 30,
        MaxAge:     28, // days
    })

    core := zapcore.NewCore(
        zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()),
        w,
        zap.DebugLevel,
    )
    cores := zapcore.NewTee(c, core)

    return cores
}
Aidoneus answered 16/11, 2021 at 13:44 Comment(0)
G
0

I wrote a simpler library rzap for zap and lumberjack.

rzap.NewGlobalLogger([]zapcore.Core{
    rzap.NewCore(&lumberjack.Logger{
        Filename:   "/your/log/path/app.log",
        MaxSize:    10,   // 10 megabytes, defaults to 100 megabytes
        MaxAge:     10,   // 10 days, default is not to remove old log files
        MaxBackups: 10,   // 10 files, default is to retain all old log files
        Compress:   true, // compress to gzio, default is not to perform compression
    }, zap.InfoLevel),
})

zap.L().Info("some message", zap.Int("status", 0))
Glomerule answered 12/1, 2022 at 9:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.