package log import ( "encoding/json" "fmt" "github.com/spf13/pflag" "go.uber.org/zap" "go.uber.org/zap/zapcore" "strings" ) const ( flagLevel = "log.level" flagDisableCaller = "log.disable-caller" flagDisableStacktrace = "log.disable-stacktrace" flagFormat = "log.format" flagEnableColor = "log.enable-color" flagOutputPaths = "log.output-paths" flagErrorOutputPaths = "log.error-output-paths" flagDevelopment = "log.development" flagName = "log.name" ConsoleFormat = "console" JsonFormat = "json" ) // Options 日志有关的配置. 设置参考zap的配置 type Options struct { OutputPaths []string `json:"output-paths" mapstructure:"output-paths"` ErrorOutputPaths []string `json:"error-output-paths" mapstructure:"error-output-paths"` Level string `json:"level" mapstructure:"level"` Format string `json:"format" mapstructure:"format"` DisableCaller bool `json:"disable-caller" mapstructure:"disable-caller"` DisableStacktrace bool `json:"disable-stacktrace" mapstructure:"disable-stacktrace"` EnableColor bool `json:"enable-color" mapstructure:"enable-color"` Development bool `json:"development" mapstructure:"development"` Name string `json:"name" mapstructure:"name"` } // NewOptions 新建带默认参数的日志配置 func NewOptions() *Options { return &Options{ Level: zapcore.InfoLevel.String(), DisableCaller: false, DisableStacktrace: false, Format: ConsoleFormat, EnableColor: false, Development: false, OutputPaths: []string{"stdout"}, ErrorOutputPaths: []string{"stderr"}, } } // Validate 验证日志配置. func (o *Options) Validate() []error { var errs []error var zapLevel zapcore.Level if err := zapLevel.UnmarshalText([]byte(o.Level)); err != nil { errs = append(errs, err) } format := strings.ToLower(o.Format) if format != ConsoleFormat && format != JsonFormat { errs = append(errs, fmt.Errorf("not a valid log format: %q", o.Format)) } return errs } // AddFlags 读取命令行参数设置日志配置 func (o *Options) AddFlags(fs *pflag.FlagSet) { fs.StringVar(&o.Level, flagLevel, o.Level, "Minimum log output `LEVEL`.") fs.BoolVar(&o.DisableCaller, flagDisableCaller, o.DisableCaller, "Disable output of caller information in the log.") fs.BoolVar(&o.DisableStacktrace, flagDisableStacktrace, o.DisableStacktrace, "Disable the log to record a stack trace for all messages at or above panic level.") fs.StringVar(&o.Format, flagFormat, o.Format, "Log output `FORMAT`, support plain or json format.") fs.BoolVar(&o.EnableColor, flagEnableColor, o.EnableColor, "Enable output ansi colors in plain format logs.") fs.StringSliceVar(&o.OutputPaths, flagOutputPaths, o.OutputPaths, "Output paths of log.") fs.StringSliceVar(&o.ErrorOutputPaths, flagErrorOutputPaths, o.ErrorOutputPaths, "Error output paths of log.") fs.BoolVar( &o.Development, flagDevelopment, o.Development, "Development puts the logger in development mode, which changes "+ "the behavior of DPanicLevel and takes stacktraces more liberally.", ) fs.StringVar(&o.Name, flagName, o.Name, "The name of the logger.") } func (o *Options) String() string { data, _ := json.Marshal(o) return string(data) } // Build 将设置安装到全局zap logger func (o *Options) Build() error { var zapLevel zapcore.Level if err := zapLevel.UnmarshalText([]byte(o.Level)); err != nil { zapLevel = zapcore.InfoLevel } encodeLevel := zapcore.CapitalLevelEncoder if o.Format == ConsoleFormat && o.EnableColor { encodeLevel = zapcore.CapitalColorLevelEncoder } zc := &zap.Config{ Level: zap.NewAtomicLevelAt(zapLevel), Development: o.Development, DisableCaller: o.DisableCaller, DisableStacktrace: o.DisableStacktrace, Sampling: &zap.SamplingConfig{ Initial: 100, Thereafter: 100, }, Encoding: o.Format, EncoderConfig: zapcore.EncoderConfig{ MessageKey: "message", LevelKey: "level", TimeKey: "timestamp", NameKey: "logger", CallerKey: "caller", StacktraceKey: "stacktrace", LineEnding: zapcore.DefaultLineEnding, EncodeLevel: encodeLevel, EncodeTime: timeEncoder, EncodeDuration: autoDurationEncoder, EncodeCaller: zapcore.ShortCallerEncoder, EncodeName: zapcore.FullNameEncoder, }, OutputPaths: o.OutputPaths, ErrorOutputPaths: o.ErrorOutputPaths, } logger, err := zc.Build(zap.AddStacktrace(zapcore.PanicLevel)) if err != nil { return err } zap.RedirectStdLog(logger.Named(o.Name)) zap.ReplaceGlobals(logger) return nil }