// Package zapx 提供了 zap 日志的对接 package zapx import ( "encoding/base64" "encoding/json" "fmt" "strconv" "time" "go.uber.org/zap/buffer" "go.uber.org/zap/zapcore" ) var pool = buffer.NewPool() // 创建新的 encoder 对象 func NewEncoder(category string, formatter CallerFormatFunc) zapcore.Encoder { return &encoder{ key: "", category: category, formatCallerPath: formatter, entries: &recordEntries{ stringEntries: []StringEntry{}, floatEntries: []FloatEntry{}, intEntries: []IntEntry{}, boolEntries: []BoolEntry{}, }, } } // 调用方路径格式化函数类型 type CallerFormatFunc = func(zapcore.EntryCaller) string // 格式化为全路径 func CallerFullPath(c zapcore.EntryCaller) string { return c.FullPath() } // 格式化为相对路径 func CallerTrimmedPath(c zapcore.EntryCaller) string { return c.TrimmedPath() } // 日志记录的参数 type recordEntries struct { stringEntries []StringEntry floatEntries []FloatEntry intEntries []IntEntry boolEntries []BoolEntry } // 因为 json number 都是 double 型数字,最高有效位只有 53 位。所以为了避免精度丢失,需要对 int64 类型数据做以下处理: // - 能被 int32 表示的数据当作 int 数字处理。 // - 在 double 类型安全范围内的数字当作 float64 数字处理。 // - 无法用 double 表示的数字当作 string 处理。 func addInt64(r *recordEntries, key string, value int64) { switch { case int64(int32(value)) == value: r.intEntries = append(r.intEntries, IntEntry{Key: key, Value: int32(value)}) case int64(float64(value)) == value: r.floatEntries = append(r.floatEntries, FloatEntry{Key: key, Value: float64(value)}) default: r.stringEntries = append(r.stringEntries, StringEntry{Key: key, Value: strconv.FormatInt(value, 10)}) } } // uint 情况同上,转换规则为: // - 能被 int32 表示的数据当作 int 数字处理。 // - 在 double 类型安全范围内的数字当作 float64 数字处理。 // - 无法用 double 表示的数字当作 string 处理。 func addUint64(r *recordEntries, key string, value uint64) { switch { case uint64(int32(value)) == value: r.intEntries = append(r.intEntries, IntEntry{Key: key, Value: int32(value)}) case uint64(float64(value)) == value: r.floatEntries = append(r.floatEntries, FloatEntry{Key: key, Value: float64(value)}) default: r.stringEntries = append(r.stringEntries, StringEntry{Key: key, Value: strconv.FormatUint(value, 10)}) } } type encoder struct { key string category string formatCallerPath func(zapcore.EntryCaller) string entries *recordEntries } func (e *encoder) EncodeEntry(entry zapcore.Entry, fields []zapcore.Field) (*buffer.Buffer, error) { var caller string if entry.Caller != (zapcore.EntryCaller{}) { caller = e.formatCallerPath(entry.Caller) } r := LogRecord{ EventTime: entry.Time, Category: e.category, Level: entry.Level.String(), Caller: caller, Message: entry.Message, StringEntries: e.entries.stringEntries, FloatEntries: e.entries.floatEntries, IntEntries: e.entries.intEntries, BoolEntries: e.entries.boolEntries, } enc := &objectEncoder{ key: e.key, entries: &recordEntries{ stringEntries: []StringEntry{}, floatEntries: []FloatEntry{}, intEntries: []IntEntry{}, boolEntries: []BoolEntry{}, }, } if entry.LoggerName != "" { enc.AddString("loggerName", entry.LoggerName) } for _, field := range fields { field.AddTo(enc) } if entry.Stack != "" { enc.AddString("stack", entry.Stack) } r.StringEntries = append(r.StringEntries, enc.entries.stringEntries...) r.FloatEntries = append(r.FloatEntries, enc.entries.floatEntries...) r.IntEntries = append(r.IntEntries, enc.entries.intEntries...) r.BoolEntries = append(r.BoolEntries, enc.entries.boolEntries...) bs, err := json.Marshal(r) if err != nil { return nil, err } buf := pool.Get() _, err = buf.Write(bs) if err != nil { return nil, err } return buf, nil } func (e *encoder) AddArray(key string, marshaler zapcore.ArrayMarshaler) error { return marshaler.MarshalLogArray(&sliceEncoder{key: addKey(e.key, key)}) } func (e *encoder) AddObject(key string, marshaler zapcore.ObjectMarshaler) error { return marshaler.MarshalLogObject(&objectEncoder{key: addKey(e.key, key)}) } // 不支持纯二进制类型,用 Base64 编码一下。 func (e *encoder) AddBinary(key string, value []byte) { v := base64.StdEncoding.EncodeToString(value) e.entries.stringEntries = append(e.entries.stringEntries, StringEntry{Key: addKey(e.key, key), Value: v}) } func (e *encoder) AddByteString(key string, value []byte) { e.entries.stringEntries = append(e.entries.stringEntries, StringEntry{Key: addKey(e.key, key), Value: string(value)}) } func (e *encoder) AddBool(key string, value bool) { e.entries.boolEntries = append(e.entries.boolEntries, BoolEntry{Key: addKey(e.key, key), Value: value}) } func (e *encoder) AddComplex128(key string, value complex128) { v := strconv.FormatComplex(value, 'f', -1, 128) e.entries.stringEntries = append(e.entries.stringEntries, StringEntry{Key: addKey(e.key, key), Value: v}) } func (e *encoder) AddComplex64(key string, value complex64) { v := strconv.FormatComplex(complex128(value), 'f', -1, 64) e.entries.stringEntries = append(e.entries.stringEntries, StringEntry{Key: addKey(e.key, key), Value: v}) } func (e *encoder) AddDuration(key string, value time.Duration) { e.entries.stringEntries = append(e.entries.stringEntries, StringEntry{Key: addKey(e.key, key), Value: value.String()}) } func (e *encoder) AddFloat64(key string, value float64) { e.entries.floatEntries = append(e.entries.floatEntries, FloatEntry{Key: addKey(e.key, key), Value: value}) } func (e *encoder) AddFloat32(key string, value float32) { e.entries.floatEntries = append(e.entries.floatEntries, FloatEntry{Key: addKey(e.key, key), Value: float64(value)}) } func (e *encoder) AddInt(key string, value int) { addInt64(e.entries, addKey(e.key, key), int64(value)) } func (e *encoder) AddInt64(key string, value int64) { addInt64(e.entries, addKey(e.key, key), value) } func (e *encoder) AddInt32(key string, value int32) { e.entries.intEntries = append(e.entries.intEntries, IntEntry{Key: addKey(e.key, key), Value: value}) } func (e *encoder) AddInt16(key string, value int16) { e.entries.intEntries = append(e.entries.intEntries, IntEntry{Key: addKey(e.key, key), Value: int32(value)}) } func (e *encoder) AddInt8(key string, value int8) { e.entries.intEntries = append(e.entries.intEntries, IntEntry{Key: addKey(e.key, key), Value: int32(value)}) } func (e *encoder) AddString(key string, value string) { e.entries.stringEntries = append(e.entries.stringEntries, StringEntry{Key: addKey(e.key, key), Value: value}) } func (e *encoder) AddTime(key string, value time.Time) { e.entries.stringEntries = append(e.entries.stringEntries, StringEntry{Key: addKey(e.key, key), Value: value.Format(time.RFC3339Nano)}) } func (e *encoder) AddUint(key string, value uint) { addUint64(e.entries, addKey(e.key, key), uint64(value)) } func (e *encoder) AddUint64(key string, value uint64) { addUint64(e.entries, addKey(e.key, key), value) } func (e *encoder) AddUint32(key string, value uint32) { addUint64(e.entries, addKey(e.key, key), uint64(value)) } func (e *encoder) AddUint16(key string, value uint16) { e.entries.intEntries = append(e.entries.intEntries, IntEntry{Key: addKey(e.key, key), Value: int32(value)}) } func (e *encoder) AddUint8(key string, value uint8) { e.entries.intEntries = append(e.entries.intEntries, IntEntry{Key: addKey(e.key, key), Value: int32(value)}) } func (e *encoder) AddUintptr(key string, value uintptr) { addUint64(e.entries, addKey(e.key, key), uint64(value)) } func (e *encoder) AddReflected(key string, value any) error { v := fmt.Sprint(value) e.entries.stringEntries = append(e.entries.stringEntries, StringEntry{Key: addKey(e.key, key), Value: v}) return nil } func (e *encoder) OpenNamespace(key string) { e.key = addKey(e.key, key) } func (e *encoder) Clone() zapcore.Encoder { return &encoder{ key: e.key, category: e.category, formatCallerPath: e.formatCallerPath, entries: &recordEntries{ stringEntries: e.entries.stringEntries, floatEntries: e.entries.floatEntries, intEntries: e.entries.intEntries, boolEntries: e.entries.boolEntries, }, } } func addKey(parent, child string) string { if parent == "" { return child } return parent + "." + child } func addIndex(parent string, index int) string { return fmt.Sprintf("%s[%d]", parent, index) } type objectEncoder struct { key string entries *recordEntries } func (e *objectEncoder) AddArray(key string, marshaler zapcore.ArrayMarshaler) error { return marshaler.MarshalLogArray(&sliceEncoder{key: addKey(e.key, key), entries: e.entries}) } func (e *objectEncoder) AddObject(key string, marshaler zapcore.ObjectMarshaler) error { return marshaler.MarshalLogObject(&objectEncoder{key: addKey(e.key, key), entries: e.entries}) } // 不支持纯二进制类型,用 Base64 编码一下。 func (e *objectEncoder) AddBinary(key string, value []byte) { v := base64.StdEncoding.EncodeToString(value) e.entries.stringEntries = append(e.entries.stringEntries, StringEntry{Key: addKey(e.key, key), Value: v}) } func (e *objectEncoder) AddByteString(key string, value []byte) { e.entries.stringEntries = append(e.entries.stringEntries, StringEntry{Key: addKey(e.key, key), Value: string(value)}) } func (e *objectEncoder) AddBool(key string, value bool) { e.entries.boolEntries = append(e.entries.boolEntries, BoolEntry{Key: addKey(e.key, key), Value: value}) } func (e *objectEncoder) AddComplex128(key string, value complex128) { v := strconv.FormatComplex(value, 'f', -1, 128) e.entries.stringEntries = append(e.entries.stringEntries, StringEntry{Key: addKey(e.key, key), Value: v}) } func (e *objectEncoder) AddComplex64(key string, value complex64) { v := strconv.FormatComplex(complex128(value), 'f', -1, 64) e.entries.stringEntries = append(e.entries.stringEntries, StringEntry{Key: addKey(e.key, key), Value: v}) } func (e *objectEncoder) AddDuration(key string, value time.Duration) { e.entries.stringEntries = append(e.entries.stringEntries, StringEntry{Key: addKey(e.key, key), Value: value.String()}) } func (e *objectEncoder) AddFloat64(key string, value float64) { e.entries.floatEntries = append(e.entries.floatEntries, FloatEntry{Key: addKey(e.key, key), Value: value}) } func (e *objectEncoder) AddFloat32(key string, value float32) { e.entries.floatEntries = append(e.entries.floatEntries, FloatEntry{Key: addKey(e.key, key), Value: float64(value)}) } func (e *objectEncoder) AddInt(key string, value int) { addInt64(e.entries, addKey(e.key, key), int64(value)) } func (e *objectEncoder) AddInt64(key string, value int64) { addInt64(e.entries, addKey(e.key, key), value) } func (e *objectEncoder) AddInt32(key string, value int32) { e.entries.intEntries = append(e.entries.intEntries, IntEntry{Key: addKey(e.key, key), Value: value}) } func (e *objectEncoder) AddInt16(key string, value int16) { e.entries.intEntries = append(e.entries.intEntries, IntEntry{Key: addKey(e.key, key), Value: int32(value)}) } func (e *objectEncoder) AddInt8(key string, value int8) { e.entries.intEntries = append(e.entries.intEntries, IntEntry{Key: addKey(e.key, key), Value: int32(value)}) } func (e *objectEncoder) AddString(key string, value string) { e.entries.stringEntries = append(e.entries.stringEntries, StringEntry{Key: addKey(e.key, key), Value: value}) } func (e *objectEncoder) AddTime(key string, value time.Time) { e.entries.stringEntries = append(e.entries.stringEntries, StringEntry{Key: addKey(e.key, key), Value: value.Format(time.RFC3339Nano)}) } func (e *objectEncoder) AddUint(key string, value uint) { addUint64(e.entries, addKey(e.key, key), uint64(value)) } func (e *objectEncoder) AddUint64(key string, value uint64) { addUint64(e.entries, addKey(e.key, key), value) } func (e *objectEncoder) AddUint32(key string, value uint32) { addUint64(e.entries, addKey(e.key, key), uint64(value)) } func (e *objectEncoder) AddUint16(key string, value uint16) { e.entries.intEntries = append(e.entries.intEntries, IntEntry{Key: addKey(e.key, key), Value: int32(value)}) } func (e *objectEncoder) AddUint8(key string, value uint8) { e.entries.intEntries = append(e.entries.intEntries, IntEntry{Key: addKey(e.key, key), Value: int32(value)}) } func (e *objectEncoder) AddUintptr(key string, value uintptr) { addUint64(e.entries, addKey(e.key, key), uint64(value)) } func (e *objectEncoder) AddReflected(key string, value any) error { v := fmt.Sprint(value) e.entries.stringEntries = append(e.entries.stringEntries, StringEntry{Key: addKey(e.key, key), Value: v}) return nil } func (e *objectEncoder) OpenNamespace(key string) { e.key = addKey(e.key, key) } type sliceEncoder struct { key string index int entries *recordEntries } func (e *sliceEncoder) AppendBool(value bool) { e.entries.boolEntries = append(e.entries.boolEntries, BoolEntry{Key: addIndex(e.key, e.index), Value: value}) e.index++ } func (e *sliceEncoder) AppendByteString(value []byte) { e.entries.stringEntries = append(e.entries.stringEntries, StringEntry{Key: addIndex(e.key, e.index), Value: string(value)}) e.index++ } func (e *sliceEncoder) AppendComplex128(value complex128) { v := strconv.FormatComplex(value, 'f', -1, 128) e.entries.stringEntries = append(e.entries.stringEntries, StringEntry{Key: addIndex(e.key, e.index), Value: v}) e.index++ } func (e *sliceEncoder) AppendComplex64(value complex64) { v := strconv.FormatComplex(complex128(value), 'f', -1, 64) e.entries.stringEntries = append(e.entries.stringEntries, StringEntry{Key: addIndex(e.key, e.index), Value: v}) e.index++ } func (e *sliceEncoder) AppendFloat64(value float64) { e.entries.floatEntries = append(e.entries.floatEntries, FloatEntry{Key: addIndex(e.key, e.index), Value: value}) e.index++ } func (e *sliceEncoder) AppendFloat32(value float32) { e.entries.floatEntries = append(e.entries.floatEntries, FloatEntry{Key: addIndex(e.key, e.index), Value: float64(value)}) e.index++ } func (e *sliceEncoder) AppendInt(value int) { addInt64(e.entries, addIndex(e.key, e.index), int64(value)) e.index++ } func (e *sliceEncoder) AppendInt64(value int64) { addInt64(e.entries, addIndex(e.key, e.index), value) e.index++ } func (e *sliceEncoder) AppendInt32(value int32) { e.entries.intEntries = append(e.entries.intEntries, IntEntry{Key: addIndex(e.key, e.index), Value: value}) e.index++ } func (e *sliceEncoder) AppendInt16(value int16) { e.entries.intEntries = append(e.entries.intEntries, IntEntry{Key: addIndex(e.key, e.index), Value: int32(value)}) e.index++ } func (e *sliceEncoder) AppendInt8(value int8) { e.entries.intEntries = append(e.entries.intEntries, IntEntry{Key: addIndex(e.key, e.index), Value: int32(value)}) e.index++ } func (e *sliceEncoder) AppendString(value string) { e.entries.stringEntries = append(e.entries.stringEntries, StringEntry{Key: addIndex(e.key, e.index), Value: value}) e.index++ } func (e *sliceEncoder) AppendUint(value uint) { addUint64(e.entries, addIndex(e.key, e.index), uint64(value)) e.index++ } func (e *sliceEncoder) AppendUint64(value uint64) { addUint64(e.entries, addIndex(e.key, e.index), value) e.index++ } func (e *sliceEncoder) AppendUint32(value uint32) { addUint64(e.entries, addIndex(e.key, e.index), uint64(value)) e.index++ } func (e *sliceEncoder) AppendUint16(value uint16) { e.entries.intEntries = append(e.entries.intEntries, IntEntry{Key: addIndex(e.key, e.index), Value: int32(value)}) e.index++ } func (e *sliceEncoder) AppendUint8(value uint8) { e.entries.intEntries = append(e.entries.intEntries, IntEntry{Key: addIndex(e.key, e.index), Value: int32(value)}) e.index++ } func (e *sliceEncoder) AppendUintptr(value uintptr) { addUint64(e.entries, addIndex(e.key, e.index), uint64(value)) e.index++ } func (e *sliceEncoder) AppendDuration(value time.Duration) { e.entries.stringEntries = append(e.entries.stringEntries, StringEntry{Key: addIndex(e.key, e.index), Value: value.String()}) e.index++ } func (e *sliceEncoder) AppendTime(value time.Time) { e.entries.stringEntries = append(e.entries.stringEntries, StringEntry{Key: addIndex(e.key, e.index), Value: value.Format(time.RFC3339Nano)}) e.index++ } func (e *sliceEncoder) AppendArray(value zapcore.ArrayMarshaler) error { err := value.MarshalLogArray(&sliceEncoder{key: addIndex(e.key, e.index), entries: e.entries}) e.index++ return err } func (e *sliceEncoder) AppendObject(value zapcore.ObjectMarshaler) error { err := value.MarshalLogObject(&objectEncoder{key: addIndex(e.key, e.index), entries: e.entries}) e.index++ return err } func (e *sliceEncoder) AppendReflected(value any) error { v := fmt.Sprint(value) e.entries.stringEntries = append(e.entries.stringEntries, StringEntry{Key: addIndex(e.key, e.index), Value: v}) e.index++ return nil }