package logger import ( "os" "go.uber.org/zap" "go.uber.org/zap/zapcore" ) type Logger struct { *zap.Logger } func New(level, output string, diagnostics ...DiagnosticOptions) *Logger { var zapLevel zapcore.Level switch level { case "debug": zapLevel = zapcore.DebugLevel case "info": zapLevel = zapcore.InfoLevel case "warn": zapLevel = zapcore.WarnLevel case "error": zapLevel = zapcore.ErrorLevel default: zapLevel = zapcore.InfoLevel } config := zap.NewProductionConfig() config.Level = zap.NewAtomicLevelAt(zapLevel) config.EncoderConfig.TimeKey = "timestamp" config.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder var writeSyncer zapcore.WriteSyncer if output == "stdout" { writeSyncer = zapcore.AddSync(os.Stdout) } else if output == "stderr" { writeSyncer = zapcore.AddSync(os.Stderr) } else { file, err := os.OpenFile(output, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) if err != nil { writeSyncer = zapcore.AddSync(os.Stdout) } else { writeSyncer = zapcore.AddSync(file) } } core := zapcore.NewCore( zapcore.NewJSONEncoder(config.EncoderConfig), writeSyncer, zapLevel, ) options := DiagnosticOptions{} if len(diagnostics) > 0 { options = diagnostics[0] } if !options.Disabled { // The diagnostic threshold is independent of the primary output level. core = zapcore.NewTee(core, zapcore.NewCore( zapcore.NewJSONEncoder(config.EncoderConfig), newDailyWriter(options), zapcore.WarnLevel, )) } logger := zap.New(core, zap.AddCaller(), zap.AddStacktrace(zapcore.ErrorLevel)) return &Logger{Logger: logger} } func (l *Logger) Fatal(msg string, fields ...interface{}) { zapFields := make([]zap.Field, 0, len(fields)) for _, f := range fields { switch v := f.(type) { case error: zapFields = append(zapFields, zap.Error(v)) default: zapFields = append(zapFields, zap.Any("field", v)) } } l.Logger.Fatal(msg, zapFields...) }