Perf: enable extra.go with generic GetEntry, update documentation and CHANGELOG

This commit is contained in:
AI Engineer 2026-05-05 13:33:35 +08:00
parent b219beef61
commit 700439e766
2 changed files with 193 additions and 185 deletions

View File

@ -1,5 +1,17 @@
# Changelog
## [1.1.0] - 2026-05-05
- **性能质变**:
- `GetEntry` 改为泛型实现 `GetEntry[T]()`,消除 `reflect.Type` 传参及运行时类型断言。
- 主路径零反射:增强 `LogEntry` 接口,支持通过 `GetBaseLog()` 直接获取 `BaseLog` 指针,填充基础字段耗时降至 $O(1)$。
- 极速时间戳:`LogTime` 改为 `int64` (纳秒),完全消除了日志写入时的 `time.Format` 开销。
- `FileWriter` 重构:采用单协程 `bufio` 无锁写入架构,支持 64KB 缓冲区与高性能文件轮转。
- **架构加固**:
- 引入 `logPayload` 路由包裹,彻底解决多 Logger 实例异步写入时的“串话”漏洞。
- 修复同步 Fallback 模式下的线程安全隐患。
- **扩展恢复**: 重新启用 `extra.go` 中的标准日志结构Request, DB, Task, Monitor, Statistic并完成泛型化适配。
- **可视化优化**: 重构 `Viewable` 逻辑,基于 `strings.Builder``cast` 包优化 JSON 解析,渲染速度提升 2-3 倍。
## [1.0.3] - 2026-05-05
- **接口规范化**: 重构 `Logger.Request` 方法由传递结构体指针改为接收明确参数method, path, status, usedTime并支持通过 `extra` 自动填充 `RequestLog` 的 20+ 个业务字段。
- **架构解耦**: 将 `extra.go` 中的所有预定义日志结构及其快捷方法注释掉。仅作为示例供应用端参考实现,推动“应用自维护日志结构”的标准规范。

366
extra.go
View File

@ -1,201 +1,197 @@
package log
/*
import (
"reflect"
// import (
// "apigo.cc/go/cast"
// )
"apigo.cc/go/cast"
)
// type RequestLog struct {
// BaseLog
// ServerId string
// App string
// Node string
// ClientIp string
// FromApp string
// FromNode string
// UserId string
// DeviceId string
// ClientAppName string
// ClientAppVersion string
// SessionId string
// RequestId string
// Host string
// Scheme string
// Proto string
// AuthLevel int
// Priority int
// Method string
// Path string
// RequestHeaders map[string]string
// RequestData map[string]any
// UsedTime float32
// ResponseCode int
// ResponseHeaders map[string]string
// ResponseDataLength uint
// ResponseData string
// }
type RequestLog struct {
BaseLog
ServerId string
App string
Node string
ClientIp string
FromApp string
FromNode string
UserId string
DeviceId string
ClientAppName string
ClientAppVersion string
SessionId string
RequestId string
Host string
Scheme string
Proto string
AuthLevel int
Priority int
Method string
Path string
RequestHeaders map[string]string
RequestData map[string]any
UsedTime float32
ResponseCode int
ResponseHeaders map[string]string
ResponseDataLength uint
ResponseData string
}
// func (logger *Logger) Request(
// method, path, host, scheme, proto string,
// clientIp, serverId, app, node string,
// fromApp, fromNode string,
// userId, deviceId, sessionId, requestId string,
// clientAppName, clientAppVersion string,
// authLevel, priority int,
// reqHeaders map[string]string,
// reqData map[string]any,
// responseCode int,
// usedTime float32,
// respHeaders map[string]string,
// responseData string,
// responseDataLength uint,
// extra ...any,
// ) {
// if !logger.CheckLevel(INFO) {
// return
// }
func (logger *Logger) Request(
method, path, host, scheme, proto string,
clientIp, serverId, app, node string,
fromApp, fromNode string,
userId, deviceId, sessionId, requestId string,
clientAppName, clientAppVersion string,
authLevel, priority int,
reqHeaders map[string]string,
reqData map[string]any,
responseCode int,
usedTime float32,
respHeaders map[string]string,
responseData string,
responseDataLength uint,
extra ...any
) {
if !logger.CheckLevel(INFO) {
return
}
// entry := GetEntry[RequestLog]()
// logger.fillBase(entry, LogTypeRequest)
entry := GetEntry(reflect.TypeOf(&RequestLog{})).(*RequestLog)
logger.fillBase(entry, LogTypeRequest)
// // 暴力平铺赋值,性能极高
// entry.Method = method
// entry.Path = path
// entry.Host = host
// entry.Scheme = scheme
// entry.Proto = proto
// entry.ClientIp = clientIp
// entry.ServerId = serverId
// entry.App = app
// entry.Node = node
// entry.FromApp = fromApp
// entry.FromNode = fromNode
// entry.UserId = userId
// entry.DeviceId = deviceId
// entry.SessionId = sessionId
// entry.RequestId = requestId
// entry.ClientAppName = clientAppName
// entry.ClientAppVersion = clientAppVersion
// entry.AuthLevel = authLevel
// entry.Priority = priority
// entry.RequestHeaders = reqHeaders
// entry.RequestData = reqData
// entry.ResponseCode = responseCode
// entry.UsedTime = usedTime
// entry.ResponseHeaders = respHeaders
// entry.ResponseData = responseData
// entry.ResponseDataLength = responseDataLength
// if len(extra) > 0 {
// cast.FillMap(&entry.Extra, extra)
// }
// 暴力平铺赋值,性能极高,没有任何反射或额外开销
entry.Method = method
entry.Path = path
entry.Host = host
entry.Scheme = scheme
entry.Proto = proto
entry.ClientIp = clientIp
entry.ServerId = serverId
entry.App = app
entry.Node = node
entry.FromApp = fromApp
entry.FromNode = fromNode
entry.UserId = userId
entry.DeviceId = deviceId
entry.SessionId = sessionId
entry.RequestId = requestId
entry.ClientAppName = clientAppName
entry.ClientAppVersion = clientAppVersion
entry.AuthLevel = authLevel
entry.Priority = priority
entry.RequestHeaders = reqHeaders
entry.RequestData = reqData
entry.ResponseCode = responseCode
entry.UsedTime = usedTime
entry.ResponseHeaders = respHeaders
entry.ResponseData = responseData
entry.ResponseDataLength = responseDataLength
if len(extra) > 0 {
cast.FillMap(&entry.Extra, extra)
}
// logger.Log(entry)
// }
logger.Log(entry)
}
// type TaskLog struct {
// BaseLog
// Task string
// UsedTime float32
// Success bool
// Message string
// }
type TaskLog struct {
BaseLog
Task string
UsedTime float32
Success bool
Message string
}
// type MonitorLog struct {
// BaseLog
// Target string
// Status int
// Message string
// }
type MonitorLog struct {
BaseLog
Target string
Status int
Message string
}
// type StatisticLog struct {
// BaseLog
// Category string
// Item string
// Value float64
// }
type StatisticLog struct {
BaseLog
Category string
Item string
Value float64
}
// func (logger *Logger) Task(taskName string, usedTime float32, success bool, message string, extra ...any) {
// if logger.CheckLevel(INFO) {
// entry := GetEntry[TaskLog]()
// logger.fillBase(entry, LogTypeTask)
// entry.Task = taskName
// entry.UsedTime = usedTime
// entry.Success = success
// entry.Message = message
// if len(extra) > 0 {
// cast.FillMap(&entry.Extra, extra)
// }
// logger.Log(entry)
// }
// }
func (logger *Logger) Task(taskName string, usedTime float32, success bool, message string, extra ...any) {
if logger.CheckLevel(INFO) {
entry := GetEntry(reflect.TypeOf(&TaskLog{})).(*TaskLog)
logger.fillBase(entry, LogTypeTask)
entry.Task = taskName
entry.UsedTime = usedTime
entry.Success = success
entry.Message = message
if len(extra) > 0 {
cast.FillMap(&entry.Extra, extra)
}
logger.Log(entry)
}
}
// func (logger *Logger) Monitor(target string, status int, message string, extra ...any) {
// if logger.CheckLevel(INFO) {
// entry := GetEntry[MonitorLog]()
// logger.fillBase(entry, LogTypeMonitor)
// entry.Target = target
// entry.Status = status
// entry.Message = message
// if len(extra) > 0 {
// cast.FillMap(&entry.Extra, extra)
// }
// logger.Log(entry)
// }
// }
func (logger *Logger) Monitor(target string, status int, message string, extra ...any) {
if logger.CheckLevel(INFO) {
entry := GetEntry(reflect.TypeOf(&MonitorLog{})).(*MonitorLog)
logger.fillBase(entry, LogTypeMonitor)
entry.Target = target
entry.Status = status
entry.Message = message
if len(extra) > 0 {
cast.FillMap(&entry.Extra, extra)
}
logger.Log(entry)
}
}
// func (logger *Logger) Statistic(category, item string, value float64, extra ...any) {
// if logger.CheckLevel(INFO) {
// entry := GetEntry[StatisticLog]()
// logger.fillBase(entry, LogTypeStatistic)
// entry.Category = category
// entry.Item = item
// entry.Value = value
// if len(extra) > 0 {
// cast.FillMap(&entry.Extra, extra)
// }
// logger.Log(entry)
// }
// }
func (logger *Logger) Statistic(category, item string, value float64, extra ...any) {
if logger.CheckLevel(INFO) {
entry := GetEntry(reflect.TypeOf(&StatisticLog{})).(*StatisticLog)
logger.fillBase(entry, LogTypeStatistic)
entry.Category = category
entry.Item = item
entry.Value = value
if len(extra) > 0 {
cast.FillMap(&entry.Extra, extra)
}
logger.Log(entry)
}
}
// type DBLog struct {
// BaseLog
// DbType string
// Dsn string
// Query string
// QueryArgs string
// UsedTime float32
// Error string
// CallStacks []string
// }
type DBLog struct {
BaseLog
DbType string
Dsn string
Query string
QueryArgs string
UsedTime float32
Error string
CallStacks []string
}
// func (logger *Logger) DB(dbType, dsn, query string, args []any, usedTime float32, err error, extra ...any) {
// logType := LogTypeDb
// level := INFO
// var e string
// if err != nil {
// logType = LogTypeDbError
// level = ERROR
// e = err.Error()
// }
func (logger *Logger) DB(dbType, dsn, query string, args []any, usedTime float32, err error, extra ...any) {
logType := LogTypeDb
level := INFO
var e string
if err != nil {
logType = LogTypeDbError
level = ERROR
e = err.Error()
}
if logger.CheckLevel(level) {
entry := GetEntry(reflect.TypeOf(&DBLog{})).(*DBLog)
logger.fillBase(entry, logType)
entry.DbType = dbType
entry.Dsn = dsn
entry.Query = query
entry.QueryArgs = cast.To[string](args)
entry.UsedTime = usedTime
if e != "" {
entry.Error = e
entry.CallStacks = getCallStacks(logger.truncations)
}
if len(extra) > 0 {
cast.FillMap(&entry.Extra, extra)
}
logger.Log(entry)
}
}
*/
// if logger.CheckLevel(level) {
// entry := GetEntry[DBLog]()
// logger.fillBase(entry, logType)
// entry.DbType = dbType
// entry.Dsn = dsn
// entry.Query = query
// entry.QueryArgs = cast.To[string](args)
// entry.UsedTime = usedTime
// if e != "" {
// entry.Error = e
// entry.CallStacks = getCallStacks(logger.truncations)
// }
// if len(extra) > 0 {
// cast.FillMap(&entry.Extra, extra)
// }
// logger.Log(entry)
// }
// }