github.com/godaddy-x/freego@v1.0.156/zlog/zlog.go (about)

     1  package zlog
     2  
     3  import (
     4  	"github.com/godaddy-x/freego/utils"
     5  	"go.uber.org/zap"
     6  	"go.uber.org/zap/zapcore"
     7  	"gopkg.in/natefinch/lumberjack.v2"
     8  	stdlog "log"
     9  	"os"
    10  	"strings"
    11  	"time"
    12  )
    13  
    14  const (
    15  	DEBUG = "debug"
    16  	INFO  = "info"
    17  	WARN  = "warn"
    18  	ERROR = "error"
    19  	FATAL = "fatal"
    20  )
    21  
    22  var (
    23  	layout    = "2006-01-02T15:04:05.000"
    24  	cst_sh, _ = time.LoadLocation("Asia/Shanghai") //上海
    25  	zapLog    = &ZapLog{}
    26  )
    27  
    28  func init() {
    29  	InitDefaultLog(&ZapConfig{Layout: 0, Location: cst_sh, Level: INFO, Console: true})
    30  }
    31  
    32  type ZapLog struct {
    33  	l *zap.Logger
    34  	c *ZapConfig
    35  }
    36  
    37  // 第三方发送对象实现
    38  type ZapProducer struct {
    39  	Callfunc func([]byte) error // 回调函数
    40  }
    41  
    42  // 第三方发送回调函数实现
    43  func (self *ZapProducer) Write(b []byte) (n int, err error) {
    44  	if err := self.Callfunc(b); err != nil {
    45  		return 0, err
    46  	}
    47  	return len(b), nil
    48  }
    49  
    50  // 字符串级别类型转具体类型
    51  func GetLevel(str string) zapcore.Level {
    52  	str = strings.ToLower(str)
    53  	switch str {
    54  	case DEBUG:
    55  		return zap.DebugLevel
    56  	case INFO:
    57  		return zap.InfoLevel
    58  	case WARN:
    59  		return zap.WarnLevel
    60  	case ERROR:
    61  		return zap.ErrorLevel
    62  	case FATAL:
    63  		return zap.FatalLevel
    64  	default:
    65  		return zapcore.ErrorLevel
    66  	}
    67  }
    68  
    69  // 日志文件输出配置
    70  type FileConfig struct {
    71  	Filename   string // 日志文件路径
    72  	MaxSize    int    // 每个日志文件保存的最大尺寸 单位:M
    73  	MaxBackups int    // 日志文件最多保存多少个备份
    74  	MaxAge     int    // 文件最多保存多少天
    75  	Compress   bool   // 是否压缩
    76  }
    77  
    78  // 日志初始化配置
    79  type ZapConfig struct {
    80  	Layout     int64              // 时间格式, 0.输出日期格式 1.输出毫秒时间戳
    81  	Location   *time.Location     // 时间地区, 默认上海
    82  	Level      string             // 日志级别
    83  	Console    bool               // 是否控制台输出
    84  	FileConfig *FileConfig        // 输出文件配置
    85  	Callfunc   func([]byte) error // 回调函数
    86  }
    87  
    88  // 通过配置初始化默认日志对象
    89  func InitDefaultLog(config *ZapConfig) *zap.Logger {
    90  	zapLog.c = config
    91  	zapLog.l = buildLog(config)
    92  	return zapLog.l
    93  }
    94  
    95  // 通过配置创建新的日志对象
    96  func InitNewLog(config *ZapConfig) *zap.Logger {
    97  	z := &ZapLog{c: config, l: buildLog(config)}
    98  	return z.l
    99  }
   100  
   101  func NewTimeEncoder(layout string, location *time.Location) func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
   102  	return func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
   103  		type appendTimeEncoder interface {
   104  			AppendTimeLayout(time.Time, string)
   105  		}
   106  		if enc, ok := enc.(appendTimeEncoder); ok {
   107  			enc.AppendTimeLayout(t, layout)
   108  			return
   109  		}
   110  		enc.AppendString(t.In(location).Format(layout))
   111  	}
   112  }
   113  
   114  // 通过配置创建日志对象
   115  func buildLog(config *ZapConfig) *zap.Logger {
   116  	// 基础日志配置
   117  	encoderConfig := zapcore.EncoderConfig{
   118  		TimeKey:  "time",
   119  		LevelKey: "level",
   120  		NameKey:  "logger",
   121  		// CallerKey:      "caller",
   122  		MessageKey:    "msg",
   123  		StacktraceKey: "stacktrace",
   124  		LineEnding:    zapcore.DefaultLineEnding,
   125  		EncodeLevel:   zapcore.LowercaseLevelEncoder, // 小写编码器
   126  		//EncodeTime:     zapcore.ISO8601TimeEncoder,    // 毫秒时间戳格式
   127  		EncodeCaller:   zapcore.ShortCallerEncoder, // 全路径编码器
   128  		EncodeDuration: zapcore.SecondsDurationEncoder,
   129  		EncodeName:     zapcore.FullNameEncoder,
   130  	}
   131  	if config.Location == nil {
   132  		config.Location = cst_sh
   133  	}
   134  	if config.Layout == 0 {
   135  		encoderConfig.EncodeTime = NewTimeEncoder(layout, config.Location)
   136  	} else {
   137  		encoderConfig.EncodeTime = zapcore.EpochMillisTimeEncoder
   138  	}
   139  	// 设置日志级别
   140  	atomicLevel := zap.NewAtomicLevel()
   141  	atomicLevel.SetLevel(GetLevel(config.Level))
   142  	// 设置控制台输出模式
   143  	var writer []zapcore.WriteSyncer
   144  	if config.Console {
   145  		writer = append(writer, zapcore.AddSync(os.Stdout))
   146  	}
   147  	// 设置日志文件输出模式
   148  	conf := config.FileConfig
   149  	if conf != nil {
   150  		outfile := lumberjack.Logger{
   151  			Filename:   conf.Filename,   // 日志文件路径
   152  			MaxSize:    conf.MaxSize,    // 每个日志文件保存的最大尺寸 单位:M
   153  			MaxBackups: conf.MaxBackups, // 日志文件最多保存多少个备份
   154  			MaxAge:     conf.MaxAge,     // 文件最多保存多少天
   155  			Compress:   conf.Compress,   // 是否压缩
   156  		}
   157  		writer = append(writer, zapcore.AddSync(&outfile))
   158  	}
   159  	// 设置第三方输出模式
   160  	if config.Callfunc != nil {
   161  		writer = append(writer, zapcore.AddSync(&ZapProducer{Callfunc: config.Callfunc}))
   162  	}
   163  	// 核心配置
   164  	core := zapcore.NewCore(
   165  		zapcore.NewJSONEncoder(encoderConfig),  // 编码器配置
   166  		zapcore.NewMultiWriteSyncer(writer...), // 输出类型,控制台,文件
   167  		atomicLevel,                            // 日志级别
   168  	)
   169  	// 开启开发模式,堆栈跟踪
   170  	caller := zap.AddCaller()
   171  	// 开启文件及行号
   172  	development := zap.Development()
   173  	// 设置初始化字段
   174  	// filed := zap.Fields(zap.String("serviceName", "serviceName"))
   175  	// 构造日志
   176  	return zap.New(core, caller, development)
   177  }
   178  
   179  // debug
   180  func Debug(msg string, start int64, fields ...zap.Field) {
   181  	if start > 0 {
   182  		fields = append(fields, zap.Int64("cost", utils.UnixMilli()-start))
   183  	}
   184  	zapLog.l.Debug(msg, fields...)
   185  }
   186  
   187  // info
   188  func Info(msg string, start int64, fields ...zap.Field) {
   189  	if start > 0 {
   190  		fields = append(fields, zap.Int64("cost", utils.UnixMilli()-start))
   191  	}
   192  	zapLog.l.Info(msg, fields...)
   193  }
   194  
   195  // warn
   196  func Warn(msg string, start int64, fields ...zap.Field) {
   197  	if start > 0 {
   198  		fields = append(fields, zap.Int64("cost", utils.UnixMilli()-start))
   199  	}
   200  	zapLog.l.Warn(msg, fields...)
   201  }
   202  
   203  // error
   204  func Error(msg string, start int64, fields ...zap.Field) {
   205  	if start > 0 {
   206  		fields = append(fields, zap.Int64("cost", utils.UnixMilli()-start))
   207  	}
   208  	zapLog.l.Error(msg, fields...)
   209  }
   210  
   211  // dpanic
   212  func DPanic(msg string, start int64, fields ...zap.Field) {
   213  	if start > 0 {
   214  		fields = append(fields, zap.Int64("cost", utils.UnixMilli()-start))
   215  	}
   216  	zapLog.l.DPanic(msg, fields...)
   217  }
   218  
   219  // panic
   220  func Panic(msg string, start int64, fields ...zap.Field) {
   221  	if start > 0 {
   222  		fields = append(fields, zap.Int64("cost", utils.UnixMilli()-start))
   223  	}
   224  	zapLog.l.Panic(msg, fields...)
   225  }
   226  
   227  // fatal
   228  func Fatal(msg string, start int64, fields ...zap.Field) {
   229  	if start > 0 {
   230  		fields = append(fields, zap.Int64("cost", utils.UnixMilli()-start))
   231  	}
   232  	zapLog.l.Fatal(msg, fields...)
   233  }
   234  
   235  // is debug?
   236  func IsDebug() bool {
   237  	if zapLog.c.Level == DEBUG {
   238  		return true
   239  	}
   240  	return false
   241  }
   242  
   243  // 兼容原生log.Print
   244  func Print(v ...interface{}) {
   245  	stdlog.Print(v...)
   246  }
   247  
   248  // 兼容原生log.Printf
   249  func Printf(format string, v ...interface{}) {
   250  	stdlog.Printf(format, v...)
   251  }
   252  
   253  // 兼容原生log.Println
   254  func Println(v ...interface{}) {
   255  	stdlog.Println(v...)
   256  }