Skip to content

Instantly share code, notes, and snippets.

@rnyrnyrny
Last active October 23, 2023 05:28
Show Gist options
  • Save rnyrnyrny/282fe705d6e8dc012e482582d7c8ec0b to your computer and use it in GitHub Desktop.
Save rnyrnyrny/282fe705d6e8dc012e482582d7c8ec0b to your computer and use it in GitHub Desktop.
log using uber zap and lumberjack
// NOTE
// This gist was created long time ago.
// According to zap's doc, now we can use zapcore.AddSync to directly add lumberjack as a zap sync
// see https://github.com/uber-go/zap/blob/master/FAQ.md#does-zap-support-log-rotation
// So I wrote a new gist if anyone is interested:
// https://gist.github.com/rnyrnyrny/a6dc926ae11951b753ecd66c00695397
// 下面的代码已经过时了,现在直接用zapcore.AddSync就行,参考zap文档
// thanks to:
// https://studygolang.com/articles/17394
// https://stackoverflow.com/questions/54395407/zap-logging-with-1-customized-config-and-2-lumberjack
package logger
import (
"fmt"
"net/url"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
lumberjack "gopkg.in/natefinch/lumberjack.v2"
)
const (
// DPanic, Panic and Fatal level can not be set by user
DebugLevelStr string = "debug"
InfoLevelStr string = "info"
WarningLevelStr string = "warning"
ErrorLevelStr string = "error"
)
var (
globalLogger *zap.Logger
devMode bool = false
)
type lumberjackSink struct {
*lumberjack.Logger
}
func (lumberjackSink) Sync() error {
return nil
}
func Init(logLevel string, logFile string, dev bool) error {
devMode = dev
var level zapcore.Level
switch logLevel {
case DebugLevelStr:
level = zap.DebugLevel
case InfoLevelStr:
level = zap.InfoLevel
case WarningLevelStr:
level = zap.WarnLevel
case ErrorLevelStr:
level = zap.ErrorLevel
default:
return fmt.Errorf("unknown log level %s", logLevel)
}
encoderConfig := zapcore.EncoderConfig{
TimeKey: "ts",
LevelKey: "level",
NameKey: "logger",
CallerKey: "caller",
MessageKey: "msg",
StacktraceKey: "stacktrace",
LineEnding: zapcore.DefaultLineEnding,
EncodeLevel: zapcore.LowercaseLevelEncoder,
EncodeTime: zapcore.ISO8601TimeEncoder,
EncodeDuration: zapcore.SecondsDurationEncoder,
EncodeCaller: zapcore.ShortCallerEncoder,
}
ll := lumberjack.Logger{
Filename: logFile,
MaxSize: 1024, //MB
MaxBackups: 30,
MaxAge: 90, //days
Compress: true,
}
zap.RegisterSink("lumberjack", func(*url.URL) (zap.Sink, error) {
return lumberjackSink{
Logger: &ll,
}, nil
})
loggerConfig := zap.Config{
Level: zap.NewAtomicLevelAt(level),
Development: dev,
Encoding: "console",
EncoderConfig: encoderConfig,
OutputPaths: []string{fmt.Sprintf("lumberjack:%s", logFile)},
}
_globalLogger, err := loggerConfig.Build()
if err != nil {
panic(fmt.Sprintf("build zap logger from config error: %v", err))
}
zap.ReplaceGlobals(_globalLogger)
globalLogger = _globalLogger
return nil
}
func NewSugar(name string) *zap.SugaredLogger {
return globalLogger.Named(name).Sugar()
}
@rnyrnyrny
Copy link
Author

ZAP build returns *Logger, error not logger, therefore globalLogger zap.Logger should be a pointer globalLogger *zap.Logger Or am I missing something?

fixed

@rnyrnyrny
Copy link
Author

ZAP build returns *Logger, error not logger, therefore globalLogger zap.Logger should be a pointer globalLogger *zap.Logger Or am I missing something?

fixed

@chinglinwen
Copy link

chinglinwen commented Nov 17, 2021

found that, log filename need to prefix lumberjack://, otherwise still calling the fileSink ( which don't do rotate ).

@duanbiaowu
Copy link

duanbiaowu commented Aug 5, 2022

The following code works:

package main

import (
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"gopkg.in/natefinch/lumberjack.v2"
)

func main() {
	lumberJackLogger := &lumberjack.Logger{
		Filename:   "server.log",
		MaxSize:    1,
		MaxBackups: 3,
		MaxAge:     1,
		Compress:   true,
	}

	writeSyncer := zapcore.AddSync(lumberJackLogger)
	encoder := zapcore.NewJSONEncoder(zapcore.EncoderConfig{
		LevelKey:       "L",
		TimeKey:        "T",
		MessageKey:     "M",
		NameKey:        "N",
		CallerKey:      "C",
		FunctionKey:    "F",
		StacktraceKey:  "S",
		LineEnding:     "\r\n",
		EncodeTime:     zapcore.ISO8601TimeEncoder,
		EncodeDuration: zapcore.SecondsDurationEncoder,
		EncodeLevel:    zapcore.LowercaseLevelEncoder,
		EncodeCaller:   zapcore.ShortCallerEncoder,
	})
	core := zapcore.NewCore(encoder, writeSyncer, zapcore.DebugLevel)

	logger := zap.New(core, zap.AddStacktrace(zap.DebugLevel))
	defer func(logger *zap.Logger) {
		_ = logger.Sync()
	}(logger)

	for i := 0; i < 10240; i++ {
		logger.Debug("hello world")
	}

        // Now, you can see some server*.log files
}

@wu0407
Copy link

wu0407 commented Aug 16, 2022

writeSyncer := zapcore.AddSync(lumberJackLogger)

👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment