package logs import ( "go.uber.org/zap/buffer" "go.uber.org/zap/zapcore" ) // traceKey 是日志中用于调用链的字段名,必须与 GetLogger 中使用的保持一致。 const traceKey = "Trace" // coloredConsoleEncoder 是一个自定义的 zapcore.Encoder,它实现了两个核心功能: // 1. 为控制台输出的日志行根据级别添加 ANSI 颜色。 // 2. 确保代表“调用链”的结构化字段总是出现在日志行的末尾。 type coloredConsoleEncoder struct { zapcore.Encoder // 嵌入一个标准的 ConsoleEncoder,复用其大部分能力。 } // NewColoredConsoleEncoder 创建一个新的 coloredConsoleEncoder 实例。 func NewColoredConsoleEncoder(cfg zapcore.EncoderConfig) zapcore.Encoder { return &coloredConsoleEncoder{ Encoder: zapcore.NewConsoleEncoder(cfg), } } // EncodeEntry 重写了核心的编码方法。 // EncodeEntry 重写了核心的编码方法。 func (c *coloredConsoleEncoder) EncodeEntry(entry zapcore.Entry, fields []zapcore.Field) (*buffer.Buffer, error) { // 1. 直接使用内嵌的 Encoder 编码日志条目和所有字段。 line, err := c.Encoder.EncodeEntry(entry, fields) if err != nil { return nil, err } // 2. 为最终的日志行添加颜色。 var color string switch entry.Level { case zapcore.DebugLevel: color = blue case zapcore.InfoLevel: color = green case zapcore.WarnLevel: color = yellow case zapcore.ErrorLevel: color = red case zapcore.DPanicLevel, zapcore.PanicLevel, zapcore.FatalLevel: color = bold + red default: color = reset } // 3. 创建一个新的 buffer,将颜色、日志内容和重置代码包裹起来。 finalBuf := buffer.NewPool().Get() finalBuf.AppendString(color) finalBuf.Write(line.Bytes()) finalBuf.AppendString(reset) // 4. 如果原始日志行末尾没有换行符,则添加一个。 if line.Len() > 0 && line.Bytes()[line.Len()-1] != '\n' { finalBuf.AppendByte('\n') } line.Free() // 释放由 c.Encoder.EncodeEntry 创建的 buffer return finalBuf, nil } // Clone 必须被重写,以确保克隆时返回的是我们自定义的 encoder 类型。 func (c *coloredConsoleEncoder) Clone() zapcore.Encoder { // 克隆内嵌的 Encoder,并用它来创建一个新的 coloredConsoleEncoder return &coloredConsoleEncoder{ Encoder: c.Encoder.Clone(), } }