github.com/zhiqiangxu/util@v0.0.0-20230112053021-0a7aee056cd5/logger/zap.go (about) 1 package logger 2 3 import ( 4 "errors" 5 "sort" 6 "time" 7 8 "go.uber.org/zap" 9 "go.uber.org/zap/zapcore" 10 ) 11 12 var errEncodingNotSupported = errors.New("encoding not supported") 13 14 // New is similar to Config.Build except that info and error logs are separated 15 // only json/console encoder is supported (zap doesn't provide a way to refer to other encoders) 16 func New(cfg zap.Config) (logger *zap.Logger, err error) { 17 18 sink, errSink, err := openSinks(cfg) 19 if err != nil { 20 return 21 } 22 23 var encoder zapcore.Encoder 24 switch cfg.Encoding { 25 case "json": 26 encoder = zapcore.NewJSONEncoder(cfg.EncoderConfig) 27 case "console": 28 encoder = zapcore.NewConsoleEncoder(cfg.EncoderConfig) 29 default: 30 err = errEncodingNotSupported 31 return 32 } 33 34 logLevel := cfg.Level.Level() 35 stdoutPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool { 36 return lvl >= logLevel && lvl < zapcore.ErrorLevel 37 }) 38 stderrPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool { 39 return lvl >= zapcore.ErrorLevel 40 }) 41 42 core := zapcore.NewTee( 43 zapcore.NewCore(encoder, sink, stdoutPriority), 44 zapcore.NewCore(encoder, errSink, stderrPriority), 45 ) 46 47 return zap.New(core, buildOptions(cfg, errSink)...), nil 48 } 49 50 func openSinks(cfg zap.Config) (zapcore.WriteSyncer, zapcore.WriteSyncer, error) { 51 sink, closeOut, err := zap.Open(cfg.OutputPaths...) 52 if err != nil { 53 return nil, nil, err 54 } 55 errSink, _, err := zap.Open(cfg.ErrorOutputPaths...) 56 if err != nil { 57 closeOut() 58 return nil, nil, err 59 } 60 return sink, errSink, nil 61 } 62 63 func buildOptions(cfg zap.Config, errSink zapcore.WriteSyncer) []zap.Option { 64 opts := []zap.Option{zap.ErrorOutput(errSink)} 65 66 if cfg.Development { 67 opts = append(opts, zap.Development()) 68 } 69 70 if !cfg.DisableCaller { 71 opts = append(opts, zap.AddCaller()) 72 } 73 74 stackLevel := zap.ErrorLevel 75 if cfg.Development { 76 stackLevel = zap.WarnLevel 77 } 78 if !cfg.DisableStacktrace { 79 opts = append(opts, zap.AddStacktrace(stackLevel)) 80 } 81 82 if cfg.Sampling != nil { 83 opts = append(opts, zap.WrapCore(func(core zapcore.Core) zapcore.Core { 84 return zapcore.NewSampler(core, time.Second, int(cfg.Sampling.Initial), int(cfg.Sampling.Thereafter)) 85 })) 86 } 87 88 if len(cfg.InitialFields) > 0 { 89 fs := make([]zap.Field, 0, len(cfg.InitialFields)) 90 keys := make([]string, 0, len(cfg.InitialFields)) 91 for k := range cfg.InitialFields { 92 keys = append(keys, k) 93 } 94 sort.Strings(keys) 95 for _, k := range keys { 96 fs = append(fs, zap.Any(k, cfg.InitialFields[k])) 97 } 98 opts = append(opts, zap.Fields(fs...)) 99 } 100 101 return opts 102 }