diff --git a/CHANGELOG.md b/CHANGELOG.md index b6709ca..a217a0b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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` 中的所有预定义日志结构及其快捷方法注释掉。仅作为示例供应用端参考实现,推动“应用自维护日志结构”的标准规范。 diff --git a/extra.go b/extra.go index 0661344..70033dc 100644 --- a/extra.go +++ b/extra.go @@ -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) +// } +// }