343 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			343 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Package logger...
 | |
| //
 | |
| // Description : config 日志配置
 | |
| //
 | |
| // Author : go_developer@163.com<白茶清欢>
 | |
| //
 | |
| // Date : 2021-01-02 3:07 下午
 | |
| package logger
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"os"
 | |
| 	"path/filepath"
 | |
| 	"strings"
 | |
| 	"time"
 | |
| 
 | |
| 	"go.uber.org/zap/zapcore"
 | |
| )
 | |
| 
 | |
| // TimeIntervalType 日志时间间隔类型
 | |
| type TimeIntervalType uint
 | |
| 
 | |
| const (
 | |
| 	// DefaultDivisionChar 默认的时间格式分隔符
 | |
| 	DefaultDivisionChar = "-"
 | |
| )
 | |
| 
 | |
| // RotateLogConfig 日志切割的配置
 | |
| type RotateLogConfig struct {
 | |
| 	TimeIntervalType LogSplit      `json:"time_interval_type" yaml:"time_interval_type"` // 日志切割的时间间隔类型 0 - 小时 1 - 天 2 - 月 3 - 年
 | |
| 	TimeInterval     time.Duration `json:"time_interval"  yaml:"time_interval"`          // 日志切割的时间间隔
 | |
| 	LogPath          string        `json:"log_path" yaml:"log_path"`                     // 存储日志的路径
 | |
| 	LogFileName      string        `json:"log_file_name" yaml:"log_file_name"`           // 日志文件名
 | |
| 	DivisionChar     string        `json:"division_char" yaml:"division_char"`           // 日志文件拼时间分隔符
 | |
| 	FullLogFormat    string        `json:"full_log_format"  yaml:"full_log_format"`      // 完整的日志格式
 | |
| 	MaxAge           int64         `json:"max_age" yaml:"max_age"`                       // 日志最长保存时间, 单位: s
 | |
| }
 | |
| 
 | |
| // SetRotateLogConfigFunc 设置日志切割的选项
 | |
| type SetRotateLogConfigFunc func(rlc *RotateLogConfig)
 | |
| 
 | |
| // WithTimeIntervalType 设置日志切割时间间隔
 | |
| func WithTimeIntervalType(timeIntervalType LogSplit) SetRotateLogConfigFunc {
 | |
| 	return func(rlc *RotateLogConfig) {
 | |
| 		rlc.TimeIntervalType = timeIntervalType
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // WithDivisionChar 设置分隔符
 | |
| func WithDivisionChar(divisionChar string) SetRotateLogConfigFunc {
 | |
| 	return func(rlc *RotateLogConfig) {
 | |
| 		rlc.DivisionChar = divisionChar
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // WithMaxAge 设置日志保存时间
 | |
| func WithMaxAge(maxAge int64) SetRotateLogConfigFunc {
 | |
| 	return func(rlc *RotateLogConfig) {
 | |
| 		if maxAge <= 0 {
 | |
| 			maxAge = 3 * 24 * 3600 // 默认3天
 | |
| 		}
 | |
| 		rlc.MaxAge = maxAge
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // NewRotateLogConfig 生成日志切割的配置
 | |
| func NewRotateLogConfig(logPath string, logFile string, option ...SetRotateLogConfigFunc) (*RotateLogConfig, error) {
 | |
| 	if len(logPath) == 0 || len(logFile) == 0 {
 | |
| 		return nil, LogPathEmptyError()
 | |
| 	}
 | |
| 	c := &RotateLogConfig{
 | |
| 		TimeIntervalType: LogSplitHour,
 | |
| 		LogPath:          logPath,
 | |
| 		LogFileName:      logFile,
 | |
| 		DivisionChar:     "",
 | |
| 	}
 | |
| 
 | |
| 	for _, o := range option {
 | |
| 		o(c)
 | |
| 	}
 | |
| 
 | |
| 	if err := formatConfig(c); nil != err {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	return c, nil
 | |
| }
 | |
| 
 | |
| // formatConfig 格式化配置
 | |
| func formatConfig(c *RotateLogConfig) error {
 | |
| 
 | |
| 	if len(c.DivisionChar) == 0 {
 | |
| 		c.DivisionChar = DefaultDivisionChar
 | |
| 	}
 | |
| 	// 格式化路径
 | |
| 	c.LogPath = strings.TrimRight(c.LogPath, string(filepath.Separator)) + string(filepath.Separator)
 | |
| 
 | |
| 	// 检测路径是否存在,不存在自动创建
 | |
| 	if _, err := os.Stat(c.LogPath); nil != err {
 | |
| 		if !os.IsNotExist(err) {
 | |
| 			// 异常不是路径不存在,抛异常
 | |
| 			return DealLogPathError(err, c.LogPath)
 | |
| 		}
 | |
| 		if err = os.Mkdir(c.LogPath, os.ModePerm); nil != err {
 | |
| 			return DealLogPathError(err, "创建日志目录失败")
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	c.TimeIntervalType = LogSplit(strings.ToUpper(c.TimeIntervalType.String()))
 | |
| 	if !c.TimeIntervalType.IsValid() {
 | |
| 		// 非法的日志切割规则,默认按天切
 | |
| 		c.TimeIntervalType = LogSplitDay
 | |
| 	}
 | |
| 	// 生成格式化日志全路径
 | |
| 	switch c.TimeIntervalType {
 | |
| 	case LogSplitHour:
 | |
| 		c.TimeInterval = time.Hour
 | |
| 		c.FullLogFormat = c.LogPath + "%Y" + c.DivisionChar + "%m" + c.DivisionChar + "%d" + c.DivisionChar + "%H" + c.DivisionChar + c.LogFileName
 | |
| 	case LogSplitDay:
 | |
| 		c.TimeInterval = time.Hour * 24
 | |
| 		c.FullLogFormat = c.LogPath + "%Y" + c.DivisionChar + "%m" + c.DivisionChar + "%d" + c.DivisionChar + c.LogFileName
 | |
| 	case LogSplitMonth:
 | |
| 		c.TimeInterval = time.Hour * 24 * 30
 | |
| 		c.FullLogFormat = c.LogPath + "%Y" + c.DivisionChar + "%m" + c.DivisionChar + c.LogFileName
 | |
| 	case LogSplitYear:
 | |
| 		c.TimeInterval = time.Hour * 24 * 365
 | |
| 		c.FullLogFormat = c.LogPath + "%Y" + c.DivisionChar + c.LogFileName
 | |
| 	default:
 | |
| 		return LogSplitTypeError(c.TimeIntervalType.String())
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // ============== 以下为zap相关配置
 | |
| 
 | |
| const (
 | |
| 	// defaultMessageKey 默认的message key
 | |
| 	defaultMessageKey = "message"
 | |
| 	// defaultLevelKey 默认的level
 | |
| 	defaultLevelKey = "level"
 | |
| 	// defaultTimeKey 默认时间key
 | |
| 	defaultTimeKey = "time"
 | |
| 	// defaultCallerKey 默认的文件key
 | |
| 	defaultCallerKey = "file"
 | |
| 	// defaultUserShortCaller 是否使用短的文件调用格式
 | |
| 	defaultUseShortCaller = true
 | |
| 	// defaultUseJsonFormat 日志默认使用json格式
 | |
| 	defaultUseJsonFormat = true
 | |
| )
 | |
| 
 | |
| // defaultTimeEncoder 默认的时间处理
 | |
| func defaultTimeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
 | |
| 	sec := t.UnixNano() / 1e9
 | |
| 	ms := t.UnixNano() / 1e6 % 1e3
 | |
| 	ns := t.UnixNano() % 1e6
 | |
| 	enc.AppendString(time.Unix(sec, ns).Format(time.DateTime) + "." + fmt.Sprintf("%v", ms) + "+" + fmt.Sprintf("%v", ns))
 | |
| }
 | |
| 
 | |
| // SecondTimeEncoder 秒级时间戳格式化
 | |
| func SecondTimeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
 | |
| 	enc.AppendString(t.Format(time.DateTime))
 | |
| }
 | |
| 
 | |
| // MsTimeEncoder 毫秒时间格式化方法
 | |
| func MsTimeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
 | |
| 	sec := t.UnixNano() / 1e9
 | |
| 	ms := t.UnixNano() / 1e6 % 1e3
 | |
| 	enc.AppendString(time.Unix(sec, 0).Format(time.DateTime) + "." + fmt.Sprintf("%v", ms))
 | |
| }
 | |
| 
 | |
| // defaultEncodeDuration 默认的原始时间处理
 | |
| func defaultEncodeDuration(d time.Duration, enc zapcore.PrimitiveArrayEncoder) {
 | |
| 	enc.AppendInt64(int64(d) / 1000000)
 | |
| }
 | |
| 
 | |
| // OptionLogger 日志配置的选项
 | |
| type OptionLogger struct {
 | |
| 	UseJsonFormat     bool                    // 日志使用json格式
 | |
| 	MessageKey        string                  // message 字段
 | |
| 	LevelKey          string                  // level 字段
 | |
| 	TimeKey           string                  // 时间字段
 | |
| 	CallerKey         string                  // 记录日志的文件的代码行数
 | |
| 	UseShortCaller    bool                    // 使用短的调用文件格式
 | |
| 	TimeEncoder       zapcore.TimeEncoder     // 格式化时间的函数
 | |
| 	EncodeDuration    zapcore.DurationEncoder // 原始时间信息
 | |
| 	WithCaller        bool                    // 是否打印文件行号
 | |
| 	WithCallerSkip    int                     // 跳过的调用数
 | |
| 	ConsoleOutput     bool                    // 控制台输出
 | |
| 	Encoder           zapcore.Encoder         // 编码函数
 | |
| 	ZincCollectConfig *ZincConfig             // zinc采集配置
 | |
| }
 | |
| 
 | |
| // SetLoggerOptionFunc 设置日志配置
 | |
| type SetLoggerOptionFunc func(o *OptionLogger)
 | |
| 
 | |
| // WithCaller 打开文件行号记录
 | |
| func WithCaller() SetLoggerOptionFunc {
 | |
| 	return func(o *OptionLogger) {
 | |
| 		o.WithCaller = true
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // WithCallerSkip ...
 | |
| func WithCallerSkip(skip int) SetLoggerOptionFunc {
 | |
| 	return func(o *OptionLogger) {
 | |
| 		o.WithCallerSkip = skip
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // WithConsoleOutput 日志控制台输出
 | |
| func WithConsoleOutput() SetLoggerOptionFunc {
 | |
| 	return func(o *OptionLogger) {
 | |
| 		o.ConsoleOutput = true
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // WithEncoder ...
 | |
| func WithEncoder(encoder zapcore.Encoder) SetLoggerOptionFunc {
 | |
| 	return func(o *OptionLogger) {
 | |
| 		o.Encoder = encoder
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // WithUseJsonFormat 日志是否使用json格式数据
 | |
| func WithUseJsonFormat(isJsonFormat bool) SetLoggerOptionFunc {
 | |
| 	return func(o *OptionLogger) {
 | |
| 		o.UseJsonFormat = isJsonFormat
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // WithMessageKey 使用message key
 | |
| func WithMessageKey(messageKey string) SetLoggerOptionFunc {
 | |
| 	return func(o *OptionLogger) {
 | |
| 		messageKey = strings.Trim(messageKey, " ")
 | |
| 		if len(messageKey) == 0 {
 | |
| 			return
 | |
| 		}
 | |
| 		o.MessageKey = messageKey
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // WithLevelKey 设置level key
 | |
| func WithLevelKey(levelKey string) SetLoggerOptionFunc {
 | |
| 	return func(o *OptionLogger) {
 | |
| 		levelKey = strings.Trim(levelKey, " ")
 | |
| 		if len(levelKey) == 0 {
 | |
| 			return
 | |
| 		}
 | |
| 		o.LevelKey = levelKey
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // WithTimeKey 设置time key ...
 | |
| func WithTimeKey(timeKey string) SetLoggerOptionFunc {
 | |
| 	return func(o *OptionLogger) {
 | |
| 		timeKey = strings.Trim(timeKey, " ")
 | |
| 		if len(timeKey) == 0 {
 | |
| 			return
 | |
| 		}
 | |
| 		o.TimeKey = timeKey
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // WithCallerKey 设置caller key
 | |
| func WithCallerKey(callerKey string) SetLoggerOptionFunc {
 | |
| 	return func(o *OptionLogger) {
 | |
| 		callerKey = strings.Trim(callerKey, " ")
 | |
| 		if len(callerKey) == 0 {
 | |
| 			return
 | |
| 		}
 | |
| 		o.CallerKey = callerKey
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // WithShortCaller 是否使用短caller格式
 | |
| func WithShortCaller(useShortCaller bool) SetLoggerOptionFunc {
 | |
| 	return func(o *OptionLogger) {
 | |
| 		o.UseShortCaller = useShortCaller
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // WithTimeEncoder 设置格式化时间方法
 | |
| func WithTimeEncoder(encoder zapcore.TimeEncoder) SetLoggerOptionFunc {
 | |
| 	return func(o *OptionLogger) {
 | |
| 		if nil == encoder {
 | |
| 			return
 | |
| 		}
 | |
| 		o.TimeEncoder = encoder
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // WithEncodeDuration 原始时间
 | |
| func WithEncodeDuration(encoder zapcore.DurationEncoder) SetLoggerOptionFunc {
 | |
| 	return func(o *OptionLogger) {
 | |
| 		if nil == encoder {
 | |
| 			return
 | |
| 		}
 | |
| 		o.EncodeDuration = encoder
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // WithZincLogCollect zinc日志采集
 | |
| func WithZincLogCollect(zincCfg *ZincConfig) SetLoggerOptionFunc {
 | |
| 	return func(o *OptionLogger) {
 | |
| 		o.ZincCollectConfig = zincCfg
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // GetEncoder 获取空中台输出的encoder
 | |
| func GetEncoder(option ...SetLoggerOptionFunc) zapcore.Encoder {
 | |
| 	ol := &OptionLogger{
 | |
| 		UseJsonFormat:  defaultUseJsonFormat,
 | |
| 		MessageKey:     defaultMessageKey,
 | |
| 		LevelKey:       defaultLevelKey,
 | |
| 		TimeKey:        defaultTimeKey,
 | |
| 		TimeEncoder:    defaultTimeEncoder,
 | |
| 		CallerKey:      defaultCallerKey,
 | |
| 		EncodeDuration: defaultEncodeDuration,
 | |
| 		UseShortCaller: defaultUseShortCaller,
 | |
| 	}
 | |
| 	for _, o := range option {
 | |
| 		o(ol)
 | |
| 	}
 | |
| 	ec := zapcore.EncoderConfig{
 | |
| 		MessageKey:     ol.MessageKey,
 | |
| 		LevelKey:       ol.LevelKey,
 | |
| 		EncodeLevel:    zapcore.CapitalLevelEncoder,
 | |
| 		TimeKey:        ol.TimeKey,
 | |
| 		EncodeTime:     ol.TimeEncoder,
 | |
| 		CallerKey:      ol.CallerKey,
 | |
| 		EncodeCaller:   zapcore.ShortCallerEncoder,
 | |
| 		EncodeDuration: ol.EncodeDuration,
 | |
| 	}
 | |
| 	if !ol.UseShortCaller {
 | |
| 		ec.EncodeCaller = zapcore.FullCallerEncoder
 | |
| 	}
 | |
| 	if !ol.UseJsonFormat {
 | |
| 		return zapcore.NewConsoleEncoder(ec)
 | |
| 	}
 | |
| 	return zapcore.NewJSONEncoder(ec)
 | |
| }
 |