package config import ( "fmt" "io" "strconv" "strings" "sync" "time" "github.com/rs/zerolog" "github.com/rs/zerolog/pkgerrors" "gopkg.in/natefinch/lumberjack.v2" ) // 怎么配置 // 是否要打印到控制台 // 是否要打印到文件里,是否要轮转 100M 5 type Log struct { // 0 为打印日志全路径, 默认打印3层路径 CallerDeep int `toml:"caller_deep" json:"caller_deep" yaml:"caller_deep" env:"CALLER_DEEP"` // 日志的级别, 默认Debug Level zerolog.Level `toml:"level" json:"level" yaml:"level" env:"LEVEL"` // 控制台日志配置 Console Console `toml:"console" json:"console" yaml:"console" envPrefix:"CONSOLE_"` // 日志文件配置 File File `toml:"file" json:"file" yaml:"file" envPrefix:"FILE_"` root *zerolog.Logger lock sync.Mutex } type Console struct { Enable bool `toml:"enable" json:"enable" yaml:"enable" env:"ENABLE"` NoColor bool `toml:"no_color" json:"no_color" yaml:"no_color" env:"NO_COLOR"` } func (c *Console) ConsoleWriter() io.Writer { output := zerolog.NewConsoleWriter(func(w *zerolog.ConsoleWriter) { w.NoColor = c.NoColor w.TimeFormat = time.RFC3339 }) output.FormatLevel = func(i interface{}) string { return strings.ToUpper(fmt.Sprintf("%-6s", i)) } output.FormatMessage = func(i interface{}) string { return fmt.Sprintf("%s", i) } output.FormatFieldName = func(i interface{}) string { return fmt.Sprintf("%s:", i) } output.FormatFieldValue = func(i interface{}) string { return strings.ToUpper(fmt.Sprintf("%s", i)) } return output } type File struct { // 是否开启文件记录 Enable bool `toml:"enable" json:"enable" yaml:"enable" env:"ENABLE"` // 文件的路径 FilePath string `toml:"file_path" json:"file_path" yaml:"file_path" env:"PATH"` // 单位M, 默认100M MaxSize int `toml:"max_size" json:"max_size" yaml:"max_size" env:"MAX_SIZE"` // 默认保存 6个文件 MaxBackups int `toml:"max_backups" json:"max_backups" yaml:"max_backups" env:"MAX_BACKUPS"` // 保存多久 MaxAge int `toml:"max_age" json:"max_age" yaml:"max_age" env:"MAX_AGE"` // 是否压缩 Compress bool `toml:"compress" json:"compress" yaml:"compress" env:"COMPRESS"` } func (f *File) FileWriter() io.Writer { return &lumberjack.Logger{ Filename: f.FilePath, MaxSize: f.MaxSize, MaxAge: f.MaxAge, MaxBackups: f.MaxBackups, Compress: f.Compress, } } func (l *Log) Logger() *zerolog.Logger { l.lock.Lock() defer l.lock.Unlock() if l.root == nil { var writers []io.Writer if l.Console.Enable { writers = append(writers, l.Console.ConsoleWriter()) } if l.File.Enable { if l.File.FilePath == "" { l.File.FilePath = "logs/app.log" } writers = append(writers, l.File.FileWriter()) } zerolog.ErrorStackMarshaler = pkgerrors.MarshalStack // logger对象配置一些上下文信息: 2024-11-23T15:11:42+08:00 // 带上中间信息Any // book/controller/book.go:60 root := zerolog.New(io.MultiWriter(writers...)).With().Timestamp().Any("服务", "book-api") if l.CallerDeep > 0 { // 启用caller root = root.Caller() // 配置自定义caller zerolog.CallerMarshalFunc = l.CallerMarshalFunc } // 带有这些上下文信息的Logger对象 提前出来,作为全局Logger对象,供全局使用 l.SetRoot(root.Logger().Level(l.Level)) } return l.root } func (m *Log) SetRoot(v zerolog.Logger) { m.root = &v } // /go/src/your_project/some_file // 21 func (m *Log) CallerMarshalFunc(pc uintptr, file string, line int) string { if m.CallerDeep == 0 { return file } short := file count := 0 for i := len(file) - 1; i > 0; i-- { if file[i] == '/' { short = file[i+1:] count++ } if count >= m.CallerDeep { break } } file = short return file + ":" + strconv.Itoa(line) }