github.com/JohanShen/go-utils@v1.1.4-0.20201117124024-901319a2b2a0/logger/zap_logger.go (about)

     1  package logger
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/JohanShen/go-utils/utils"
     6  	"go.uber.org/zap"
     7  	"go.uber.org/zap/zapcore"
     8  	"os"
     9  	"os/signal"
    10  	"sync"
    11  	"syscall"
    12  	"time"
    13  )
    14  
    15  // zap 日志的具体实现
    16  //  可能存在的BUG:
    17  //   1 日志不是顺序输出的
    18  //   2 日志没有按生成时间输出到对应文件
    19  //
    20  type zapLogger struct {
    21  	config      *Config
    22  	logger      *zap.Logger
    23  	sugarLogger *zap.SugaredLogger
    24  	delayQueue  []*ZapBody   // 存放延迟处理的列队
    25  	delayNum    int          // 延迟写入的数量
    26  	ticker      *time.Ticker // 用于处理延迟数据
    27  	stopTicker  chan os.Signal
    28  	locker      *sync.Mutex
    29  }
    30  
    31  var createdObject map[string]*zapLogger
    32  
    33  func NewZapLogger(config *Config) *zapLogger {
    34  
    35  	if len(config.Name) == 0 {
    36  		config.Name = "default"
    37  	}
    38  
    39  	if obj, ok := createdObject[config.Name]; ok {
    40  		return obj
    41  	}
    42  
    43  	obj := &zapLogger{
    44  		config: config,
    45  	}
    46  
    47  	if config.WriteDelay > 0 {
    48  		//delay = queue.NewDelayQueue(config.WriteMode, obj.callback)
    49  		config.WriteDelay = utils.IfElseInt(config.WriteDelay > 10, config.WriteDelay, 10)
    50  		config.WriteDelay = utils.IfElseInt(config.WriteDelay > 10000, 10000, config.WriteDelay)
    51  
    52  		obj.locker = &sync.Mutex{}
    53  		obj.delayQueue = make([]*ZapBody, 0, 10000)
    54  		obj.delayNum = 10000
    55  		obj.stopTicker = make(chan os.Signal, 1)
    56  		obj.ticker = time.NewTicker(time.Duration(config.WriteDelay) * time.Millisecond)
    57  		signal.Notify(obj.stopTicker, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
    58  
    59  		go obj.listenTicker()
    60  	}
    61  
    62  	cores := make([]zapcore.Core, 0, 2)
    63  	// 实现多个输出
    64  	if len(config.LogPath) > 0 {
    65  		encoder := getEncoder()
    66  		writer := getLogWriter(config.LogPath)
    67  		cores = append(cores, zapcore.NewCore(encoder, writer, zapcore.DebugLevel))
    68  	}
    69  	if config.ConsoleLog {
    70  		cores = append(cores, zapcore.NewCore(zapcore.NewConsoleEncoder(getEncoderConfig()), zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout)), zapcore.DebugLevel))
    71  	}
    72  	core := zapcore.NewTee(cores...)
    73  
    74  	//zap.New(core, zap.AddCaller(), zap.AddStacktrace(zap.WarnLevel))
    75  	obj.logger = zap.New(core, zap.AddStacktrace(zap.WarnLevel))
    76  	obj.sugarLogger = obj.logger.Sugar()
    77  
    78  	return obj
    79  }
    80  
    81  func getEncoderConfig() zapcore.EncoderConfig {
    82  	encoderConfig := zap.NewProductionEncoderConfig()
    83  	encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
    84  	encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
    85  	encoderConfig.EncodeCaller = zapcore.ShortCallerEncoder
    86  	return encoderConfig
    87  }
    88  func getEncoder() zapcore.Encoder {
    89  	encoderConfig := getEncoderConfig()
    90  	return zapcore.NewJSONEncoder(encoderConfig)
    91  }
    92  
    93  func getLogWriter(path string) zapcore.WriteSyncer {
    94  	//now := time.Now()
    95  	//logPath := utils.XTime(now).Format(path)
    96  	//file, _ := os.OpenFile(logPath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
    97  	file := NewTimeWriter(path)
    98  	return zapcore.AddSync(file)
    99  }
   100  
   101  // 监听定时器
   102  func (z *zapLogger) listenTicker() {
   103  
   104  	defer z.ticker.Stop()
   105  
   106  Loop:
   107  	for {
   108  		select {
   109  		case <-z.ticker.C:
   110  
   111  			len1 := len(z.delayQueue)
   112  			idx := utils.IfElseInt(len1 > z.delayNum, z.delayNum, len1)
   113  
   114  			if idx > 0 {
   115  				z.locker.Lock()
   116  				//单次回调传入的数组
   117  				result := z.delayQueue[:idx]
   118  				//从原数组中移除已经回调的数据
   119  				z.delayQueue = z.delayQueue[idx:]
   120  				//result1 := make([]ZapBody,1000)
   121  				//copy(result1, result)
   122  				z.locker.Unlock()
   123  
   124  				fmt.Println("总长度:", len1, "取出数:", idx)
   125  				// 将最终的执行函数单独包装成方法
   126  				// 有利于其中一个或多个回调函数出错时,保证程序继续运行
   127  				go z.writeMsg(result...)
   128  			}
   129  
   130  		case <-z.stopTicker:
   131  			z.locker.Lock()
   132  			len1 := len(z.delayQueue)
   133  			if len1 > 0 {
   134  				// 将剩余未写入的一次性写入
   135  				//fmt.Println("剩余:", len1)
   136  				go z.writeMsg(z.delayQueue...)
   137  			}
   138  			z.locker.Unlock()
   139  
   140  			break Loop
   141  
   142  		}
   143  	}
   144  	//println("退出延迟等候列队")
   145  }
   146  
   147  func (z *zapLogger) writeMsg(bodies ...*ZapBody) {
   148  
   149  	defer func() {
   150  		if err := recover(); err != nil {
   151  			// 这个位置出错说明IO操作出现问题
   152  			// 无法写入到错误 为了程序稳定 也不宜 panic
   153  			println("写入日志时出错 writeMsg() panic ", err)
   154  		}
   155  	}()
   156  
   157  	defer func() {
   158  		if err := z.logger.Sync(); err != nil {
   159  			println("写入日志时出错 writeMsg() Sync() ", err)
   160  		}
   161  	}()
   162  
   163  	for _, body := range bodies {
   164  		fields := make([]zap.Field, 0, len(body.TopLevelData)+2)
   165  		fields = append(fields, zap.String("name", z.config.Name))
   166  		for key, val := range body.TopLevelData {
   167  			fields = append(fields, zap.Any(key, val))
   168  		}
   169  		if body.Data != nil {
   170  			fields = append(fields, zap.Any("data", body.Data))
   171  		}
   172  
   173  		switch body.LogLevel {
   174  		case DebugLevel:
   175  			z.logger.Debug(body.Desc, fields...)
   176  		case ErrorLevel:
   177  			z.logger.Error(body.Desc, fields...)
   178  		case WarnLevel:
   179  			z.logger.Warn(body.Desc, fields...)
   180  		case PanicLevel:
   181  			z.logger.Panic(body.Desc, fields...)
   182  		case FatalLevel:
   183  			z.logger.Fatal(body.Desc, fields...)
   184  		default:
   185  			z.logger.Info(body.Desc, fields...)
   186  		}
   187  	}
   188  }
   189  
   190  func (z *zapLogger) write(level Level, desc string, args ...*LogArg) {
   191  
   192  	body := &ZapBody{
   193  		LogLevel:     level,
   194  		Desc:         desc,
   195  		TopLevelData: make(map[string]interface{}),
   196  	}
   197  	for _, item := range args {
   198  		if len(z.config.ShowInTopLevel) > 0 && utils.IndexOfWithoutCase(z.config.ShowInTopLevel, item.Key) > -1 {
   199  			body.TopLevelData[item.Key] = item.Value
   200  		} else {
   201  			if body.Data == nil {
   202  				body.Data = make(map[string]interface{})
   203  			}
   204  			body.Data[item.Key] = item.Value
   205  		}
   206  
   207  	}
   208  
   209  	if z.config.WriteDelay == 0 {
   210  		//需要即时处理的数据
   211  		go z.writeMsg(body)
   212  	} else {
   213  		//延迟处理的数据
   214  		//此处可能会存在性能问题
   215  		z.locker.Lock()
   216  		z.delayQueue = append(z.delayQueue, body)
   217  		z.locker.Unlock()
   218  	}
   219  
   220  }
   221  
   222  func (z *zapLogger) Debug(desc string, args ...*LogArg) {
   223  	z.write(DebugLevel, desc, args...)
   224  }
   225  func (z *zapLogger) Error(desc string, args ...*LogArg) {
   226  	z.write(ErrorLevel, desc, args...)
   227  }
   228  func (z *zapLogger) Fatal(desc string, args ...*LogArg) {
   229  	z.write(FatalLevel, desc, args...)
   230  }
   231  func (z *zapLogger) Info(desc string, args ...*LogArg) {
   232  	z.write(InfoLevel, desc, args...)
   233  }
   234  func (z *zapLogger) Panic(desc string, args ...*LogArg) {
   235  	z.write(PanicLevel, desc, args...)
   236  }
   237  func (z *zapLogger) Warn(desc string, args ...*LogArg) {
   238  	z.write(WarnLevel, desc, args...)
   239  }