Files
Ant-Browser/backend/internal/logger/formatter.go
T
Ant Browser Release Bot 6f58a6c19a publish: 1.0.0 snapshot (bad2ec1)
channel: master
version: 1.0.0
source-ref: master
published-at-utc: 2026-03-13T15:19:28Z
2026-03-13 23:19:29 +08:00

193 lines
4.7 KiB
Go

package logger
import (
"encoding/json"
"fmt"
"sort"
"strings"
)
// TextFormatter 文本格式化器
// 将日志条目格式化为结构化文本格式
type TextFormatter struct {
// TimestampFormat 时间戳格式,默认为 "2006-01-02 15:04:05.000"
TimestampFormat string
}
// NewTextFormatter 创建新的文本格式化器
func NewTextFormatter() *TextFormatter {
return &TextFormatter{
TimestampFormat: "2006-01-02 15:04:05.000",
}
}
// Format 格式化日志条目为文本格式
// 输出格式: [timestamp] [level] [component] message | field1=value1 field2=value2
func (f *TextFormatter) Format(entry *LogEntry) ([]byte, error) {
if entry == nil {
return nil, fmt.Errorf("log entry is nil")
}
var sb strings.Builder
// 时间戳
timestampFormat := f.TimestampFormat
if timestampFormat == "" {
timestampFormat = "2006-01-02 15:04:05.000"
}
sb.WriteString("[")
sb.WriteString(entry.Timestamp.Format(timestampFormat))
sb.WriteString("] ")
// 级别
sb.WriteString("[")
sb.WriteString(entry.Level.String())
sb.WriteString("] ")
// 组件
sb.WriteString("[")
if entry.Component != "" {
sb.WriteString(entry.Component)
} else {
sb.WriteString("-")
}
sb.WriteString("] ")
// 消息
sb.WriteString(entry.Message)
// 收集所有额外字段
extraFields := make([]string, 0)
// 请求ID
if entry.RequestID != "" {
extraFields = append(extraFields, fmt.Sprintf("request_id=%s", entry.RequestID))
}
// 方法名
if entry.Method != "" {
extraFields = append(extraFields, fmt.Sprintf("method=%s", entry.Method))
}
// 执行耗时
if entry.Duration > 0 {
extraFields = append(extraFields, fmt.Sprintf("duration_ms=%d", entry.Duration))
}
// 调用位置
if entry.CallerFile != "" {
caller := entry.CallerFile
if entry.CallerLine > 0 {
caller = fmt.Sprintf("%s:%d", entry.CallerFile, entry.CallerLine)
}
extraFields = append(extraFields, fmt.Sprintf("caller=%s", caller))
}
// 错误信息
if entry.Error != "" {
extraFields = append(extraFields, fmt.Sprintf("error=%s", entry.Error))
}
// 扩展字段(按key排序以保证输出稳定)
if len(entry.Fields) > 0 {
keys := make([]string, 0, len(entry.Fields))
for k := range entry.Fields {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
extraFields = append(extraFields, fmt.Sprintf("%s=%v", k, entry.Fields[k]))
}
}
// 如果有额外字段,添加分隔符和字段
if len(extraFields) > 0 {
sb.WriteString(" | ")
sb.WriteString(strings.Join(extraFields, " "))
}
// 添加换行符
sb.WriteString("\n")
return []byte(sb.String()), nil
}
// JSONFormatter JSON格式化器
// 将日志条目格式化为JSON格式
type JSONFormatter struct {
// PrettyPrint 是否美化输出(带缩进)
PrettyPrint bool
}
// NewJSONFormatter 创建新的JSON格式化器
func NewJSONFormatter() *JSONFormatter {
return &JSONFormatter{
PrettyPrint: false,
}
}
// jsonLogEntry 用于JSON序列化的内部结构
// 确保字段顺序和格式符合要求
type jsonLogEntry struct {
Timestamp string `json:"timestamp"`
Level string `json:"level"`
Component string `json:"component"`
Message string `json:"message"`
RequestID string `json:"request_id,omitempty"`
Method string `json:"method,omitempty"`
DurationMs int64 `json:"duration_ms,omitempty"`
Caller string `json:"caller,omitempty"`
Error string `json:"error,omitempty"`
Fields map[string]interface{} `json:"fields,omitempty"`
}
// Format 格式化日志条目为JSON格式
func (f *JSONFormatter) Format(entry *LogEntry) ([]byte, error) {
if entry == nil {
return nil, fmt.Errorf("log entry is nil")
}
// 构建调用位置字符串
var caller string
if entry.CallerFile != "" {
if entry.CallerLine > 0 {
caller = fmt.Sprintf("%s:%d", entry.CallerFile, entry.CallerLine)
} else {
caller = entry.CallerFile
}
}
// 创建JSON结构
jsonEntry := jsonLogEntry{
Timestamp: entry.Timestamp.Format("2006-01-02T15:04:05.000Z07:00"),
Level: entry.Level.String(),
Component: entry.Component,
Message: entry.Message,
RequestID: entry.RequestID,
Method: entry.Method,
DurationMs: entry.Duration,
Caller: caller,
Error: entry.Error,
Fields: entry.Fields,
}
var data []byte
var err error
if f.PrettyPrint {
data, err = json.MarshalIndent(jsonEntry, "", " ")
} else {
data, err = json.Marshal(jsonEntry)
}
if err != nil {
return nil, fmt.Errorf("failed to marshal log entry to JSON: %w", err)
}
// 添加换行符
data = append(data, '\n')
return data, nil
}