package main import ( "fmt" "git.frostfs.info/TrueCloudLab/zapjournald" "github.com/spf13/viper" "github.com/ssgreg/journald" "go.uber.org/zap" "go.uber.org/zap/zapcore" ) const ( destinationStdout string = "stdout" destinationJournald string = "journald" ) type Logger struct { logger *zap.Logger lvl zap.AtomicLevel } func pickLogger(v *viper.Viper) *Logger { lvl, err := getLogLevel(v.GetString(cfgLoggerLevel)) if err != nil { panic(err) } dest := v.GetString(cfgLoggerDestination) if dest == destinationStdout { return newStdoutLogger(lvl) } if dest == destinationJournald { return newJournaldLogger(lvl) } panic(fmt.Sprintf("wrong destination for logger: %s", dest)) } func newStdoutLogger(lvl zapcore.Level) *Logger { c := zap.NewProductionConfig() c.Level = zap.NewAtomicLevelAt(lvl) c.Encoding = "console" c.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder l, err := c.Build( zap.AddStacktrace(zap.NewAtomicLevelAt(zap.FatalLevel)), ) if err != nil { panic(fmt.Sprintf("build zap logger instance: %v", err)) } return &Logger{logger: l, lvl: c.Level} } func newJournaldLogger(lvl zapcore.Level) *Logger { c := zap.NewProductionConfig() c.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder c.Level = zap.NewAtomicLevelAt(lvl) // We can use NewJSONEncoder instead if, say, frontend // would like to access journald logs and parse them easily. encoder := zapjournald.NewPartialEncoder(zapcore.NewConsoleEncoder(c.EncoderConfig), zapjournald.SyslogFields) core := zapjournald.NewCore(c.Level, encoder, &journald.Journal{}, zapjournald.SyslogFields) coreWithContext := core.With([]zapcore.Field{ zapjournald.SyslogFacility(zapjournald.LogDaemon), zapjournald.SyslogIdentifier(), zapjournald.SyslogPid(), }) l := zap.New(coreWithContext, zap.AddStacktrace(zap.NewAtomicLevelAt(zap.FatalLevel))) return &Logger{logger: l, lvl: c.Level} } func getLogLevel(lvlStr string) (zapcore.Level, error) { var lvl zapcore.Level err := lvl.UnmarshalText([]byte(lvlStr)) if err != nil { return lvl, fmt.Errorf("incorrect logger level configuration %s (%v), "+ "value should be one of %v", lvlStr, err, [...]zapcore.Level{ zapcore.DebugLevel, zapcore.InfoLevel, zapcore.WarnLevel, zapcore.ErrorLevel, zapcore.DPanicLevel, zapcore.PanicLevel, zapcore.FatalLevel, }) } return lvl, nil }