Reputation: 471
I have integrated Zap with my go application, we have logs getting printed in two log files and i am also using Lumberjack for log rotation. But i am trying to display the logs in console as well, but no luck for this case. Following is my code in 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 = []string{logName}
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
}
I have tried appending the output paths but it is not working.
Upvotes: 7
Views: 21502
Reputation: 14501
Easiest way to log into multiple sources is to use zapper package. Create config.yml
:
outputPaths:
- stdout
- /var/log/abc.log
- /var/log/n2n.log
errorOutputPaths:
- stderr
- /var/log/abc.log
- /var/log/n2n.log
Then initialize Zap logger:
package main
import "github.com/nafigator/zapper"
func main() {
path := "/path/to/config.yml"
log, _ := zapper.New(path)
log.Info("Log into multiple sources: OK")
}
Upvotes: 0
Reputation: 471
Figured out that zapcore has zapcore.NewMultiWriteSyncer
which can write the logs in file and also on console using zapcore.addSync(os.stdout)
.
For example:
swSugar := zapcore.NewMultiWriteSyncer(
zapcore.AddSync(os.Stdout),
getWriteSyncer(logfileName),
)
Upvotes: 6
Reputation: 44728
You can also use zap.CombineWriteSyncers
:
CombineWriteSyncers is a utility that combines multiple WriteSyncers into a single, locked WriteSyncer. If no inputs are supplied, it returns a no-op WriteSyncer.
It's provided purely as a convenience; the result is no different from using zapcore.NewMultiWriteSyncer and zapcore.Lock individually.
syncer := zap.CombineWriteSyncers(os.Stdout, getWriteSyncer(logfileName))
core := zapcore.NewCore(enc, syncer, zap.NewAtomicLevelAt(zap.InfoLevel))
zap.New(core)
Upvotes: 0
Reputation: 769
Since this is one of the first things that appears after looking for this on Google, here's a simple example of how to make logs show on the Console and a log file, which can be any io.Writer as the one used by lumberjack:
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()
}
I used the default ProductionEncoderConfig but it could be a custom one like the one on OP's code.
Upvotes: 13