package zap import ( "IotAdmin/core/logger" "context" "fmt" "io" "os" "sync" "go.uber.org/zap" "go.uber.org/zap/zapcore" ) type zapLogger struct { cfg zap.Config zap *zap.Logger opts logger.Options sync.RWMutex fields map[string]interface{} } // NewLogger 构建新的记录器 func NewLogger(opts ...logger.Option) (logger.Logger, error) { // Default options options := logger.Options{ Level: logger.InfoLevel, Fields: make(map[string]interface{}), Out: os.Stderr, Context: context.Background(), } l := &zapLogger{opts: options} if err := l.Init(opts...); err != nil { return nil, err } return l, nil } func (l *zapLogger) Init(opts ...logger.Option) error { //var err error for _, o := range opts { o(&l.opts) } zapConfig := zap.NewProductionConfig() if zConfig, ok := l.opts.Context.Value(configKey{}).(zap.Config); ok { zapConfig = zConfig } if zeConfig, ok := l.opts.Context.Value(encoderConfigKey{}).(zapcore.EncoderConfig); ok { zapConfig.EncoderConfig = zeConfig } writer, ok := l.opts.Context.Value(writerKey{}).(io.Writer) if !ok { writer = os.Stdout } skip, ok := l.opts.Context.Value(callerSkipKey{}).(int) if !ok || skip < 1 { skip = 1 } // 设置日志级别 zapConfig.Level = zap.NewAtomicLevel() if l.opts.Level != logger.InfoLevel { zapConfig.Level.SetLevel(loggerToZapLevel(l.opts.Level)) } zapConfig.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder logCore := zapcore.NewCore( zapcore.NewConsoleEncoder(zapConfig.EncoderConfig), zapcore.NewMultiWriteSyncer(zapcore.AddSync(writer)), zapConfig.Level) log := zap.New(logCore, zap.AddCaller(), zap.AddCallerSkip(skip), zap.AddStacktrace(zap.DPanicLevel)) // 添加种子字段(如果存在) if l.opts.Fields != nil { var data []zap.Field for k, v := range l.opts.Fields { data = append(data, zap.Any(k, v)) } log = log.With(data...) } // 添加命名空间 if namespace, ok := l.opts.Context.Value(namespaceKey{}).(string); ok { log = log.With(zap.Namespace(namespace)) } // defer log.Sync() ?? l.cfg = zapConfig l.zap = log l.fields = make(map[string]interface{}) return nil } func (l *zapLogger) Fields(fields map[string]interface{}) logger.Logger { l.Lock() newFields := make(map[string]interface{}, len(l.fields)) for k, v := range l.fields { newFields[k] = v } l.Unlock() for k, v := range fields { newFields[k] = v } data := make([]zap.Field, 0, len(newFields)) for k, v := range fields { data = append(data, zap.Any(k, v)) } zl := &zapLogger{ cfg: l.cfg, zap: l.zap, opts: l.opts, fields: newFields, } return zl } func (l *zapLogger) Error(err error) logger.Logger { return l.Fields(map[string]interface{}{"error": err}) } func (l *zapLogger) Log(level logger.Level, args ...interface{}) { l.RLock() data := make([]zap.Field, 0, len(l.fields)) for k, v := range l.fields { data = append(data, zap.Any(k, v)) } l.RUnlock() lvl := loggerToZapLevel(level) msg := fmt.Sprint(args...) switch lvl { case zap.DebugLevel: l.zap.Debug(msg, data...) case zap.InfoLevel: l.zap.Info(msg, data...) case zap.WarnLevel: l.zap.Warn(msg, data...) case zap.ErrorLevel: l.zap.Error(msg, data...) case zap.FatalLevel: l.zap.Fatal(msg, data...) } } func (l *zapLogger) Logf(level logger.Level, format string, args ...interface{}) { l.RLock() data := make([]zap.Field, 0, len(l.fields)) for k, v := range l.fields { data = append(data, zap.Any(k, v)) } l.RUnlock() lvl := loggerToZapLevel(level) msg := fmt.Sprintf(format, args...) switch lvl { case zap.DebugLevel: l.zap.Debug(msg, data...) case zap.InfoLevel: l.zap.Info(msg, data...) case zap.WarnLevel: l.zap.Warn(msg, data...) case zap.ErrorLevel: l.zap.Error(msg, data...) case zap.FatalLevel: l.zap.Fatal(msg, data...) } } func (l *zapLogger) String() string { return "zap" } func (l *zapLogger) Options() logger.Options { return l.opts } func loggerToZapLevel(level logger.Level) zapcore.Level { switch level { case logger.TraceLevel, logger.DebugLevel: return zap.DebugLevel case logger.InfoLevel: return zap.InfoLevel case logger.WarnLevel: return zap.WarnLevel case logger.ErrorLevel: return zap.ErrorLevel case logger.FatalLevel: return zap.FatalLevel default: return zap.InfoLevel } } func zapToLoggerLevel(level zapcore.Level) logger.Level { switch level { case zap.DebugLevel: return logger.DebugLevel case zap.InfoLevel: return logger.InfoLevel case zap.WarnLevel: return logger.WarnLevel case zap.ErrorLevel: return logger.ErrorLevel case zap.FatalLevel: return logger.FatalLevel default: return logger.InfoLevel } }