Perf: enable extra.go with generic GetEntry, update documentation and CHANGELOG
This commit is contained in:
parent
b219beef61
commit
700439e766
12
CHANGELOG.md
12
CHANGELOG.md
@ -1,5 +1,17 @@
|
|||||||
# Changelog
|
# 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
|
## [1.0.3] - 2026-05-05
|
||||||
- **接口规范化**: 重构 `Logger.Request` 方法,由传递结构体指针改为接收明确参数(method, path, status, usedTime),并支持通过 `extra` 自动填充 `RequestLog` 的 20+ 个业务字段。
|
- **接口规范化**: 重构 `Logger.Request` 方法,由传递结构体指针改为接收明确参数(method, path, status, usedTime),并支持通过 `extra` 自动填充 `RequestLog` 的 20+ 个业务字段。
|
||||||
- **架构解耦**: 将 `extra.go` 中的所有预定义日志结构及其快捷方法注释掉。仅作为示例供应用端参考实现,推动“应用自维护日志结构”的标准规范。
|
- **架构解耦**: 将 `extra.go` 中的所有预定义日志结构及其快捷方法注释掉。仅作为示例供应用端参考实现,推动“应用自维护日志结构”的标准规范。
|
||||||
|
|||||||
366
extra.go
366
extra.go
@ -1,201 +1,197 @@
|
|||||||
package log
|
package log
|
||||||
|
|
||||||
/*
|
// import (
|
||||||
import (
|
// "apigo.cc/go/cast"
|
||||||
"reflect"
|
// )
|
||||||
|
|
||||||
"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 {
|
// func (logger *Logger) Request(
|
||||||
BaseLog
|
// method, path, host, scheme, proto string,
|
||||||
ServerId string
|
// clientIp, serverId, app, node string,
|
||||||
App string
|
// fromApp, fromNode string,
|
||||||
Node string
|
// userId, deviceId, sessionId, requestId string,
|
||||||
ClientIp string
|
// clientAppName, clientAppVersion string,
|
||||||
FromApp string
|
// authLevel, priority int,
|
||||||
FromNode string
|
// reqHeaders map[string]string,
|
||||||
UserId string
|
// reqData map[string]any,
|
||||||
DeviceId string
|
// responseCode int,
|
||||||
ClientAppName string
|
// usedTime float32,
|
||||||
ClientAppVersion string
|
// respHeaders map[string]string,
|
||||||
SessionId string
|
// responseData string,
|
||||||
RequestId string
|
// responseDataLength uint,
|
||||||
Host string
|
// extra ...any,
|
||||||
Scheme string
|
// ) {
|
||||||
Proto string
|
// if !logger.CheckLevel(INFO) {
|
||||||
AuthLevel int
|
// return
|
||||||
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(
|
// entry := GetEntry[RequestLog]()
|
||||||
method, path, host, scheme, proto string,
|
// logger.fillBase(entry, LogTypeRequest)
|
||||||
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(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)
|
||||||
|
// }
|
||||||
|
|
||||||
// 暴力平铺赋值,性能极高,没有任何反射或额外开销
|
// logger.Log(entry)
|
||||||
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)
|
// type TaskLog struct {
|
||||||
}
|
// BaseLog
|
||||||
|
// Task string
|
||||||
|
// UsedTime float32
|
||||||
|
// Success bool
|
||||||
|
// Message string
|
||||||
|
// }
|
||||||
|
|
||||||
type TaskLog struct {
|
// type MonitorLog struct {
|
||||||
BaseLog
|
// BaseLog
|
||||||
Task string
|
// Target string
|
||||||
UsedTime float32
|
// Status int
|
||||||
Success bool
|
// Message string
|
||||||
Message string
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
type MonitorLog struct {
|
// type StatisticLog struct {
|
||||||
BaseLog
|
// BaseLog
|
||||||
Target string
|
// Category string
|
||||||
Status int
|
// Item string
|
||||||
Message string
|
// Value float64
|
||||||
}
|
// }
|
||||||
|
|
||||||
type StatisticLog struct {
|
// func (logger *Logger) Task(taskName string, usedTime float32, success bool, message string, extra ...any) {
|
||||||
BaseLog
|
// if logger.CheckLevel(INFO) {
|
||||||
Category string
|
// entry := GetEntry[TaskLog]()
|
||||||
Item string
|
// logger.fillBase(entry, LogTypeTask)
|
||||||
Value float64
|
// 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) {
|
// func (logger *Logger) Monitor(target string, status int, message string, extra ...any) {
|
||||||
if logger.CheckLevel(INFO) {
|
// if logger.CheckLevel(INFO) {
|
||||||
entry := GetEntry(reflect.TypeOf(&TaskLog{})).(*TaskLog)
|
// entry := GetEntry[MonitorLog]()
|
||||||
logger.fillBase(entry, LogTypeTask)
|
// logger.fillBase(entry, LogTypeMonitor)
|
||||||
entry.Task = taskName
|
// entry.Target = target
|
||||||
entry.UsedTime = usedTime
|
// entry.Status = status
|
||||||
entry.Success = success
|
// entry.Message = message
|
||||||
entry.Message = message
|
// if len(extra) > 0 {
|
||||||
if len(extra) > 0 {
|
// cast.FillMap(&entry.Extra, extra)
|
||||||
cast.FillMap(&entry.Extra, extra)
|
// }
|
||||||
}
|
// logger.Log(entry)
|
||||||
logger.Log(entry)
|
// }
|
||||||
}
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Monitor(target string, status int, message string, extra ...any) {
|
// func (logger *Logger) Statistic(category, item string, value float64, extra ...any) {
|
||||||
if logger.CheckLevel(INFO) {
|
// if logger.CheckLevel(INFO) {
|
||||||
entry := GetEntry(reflect.TypeOf(&MonitorLog{})).(*MonitorLog)
|
// entry := GetEntry[StatisticLog]()
|
||||||
logger.fillBase(entry, LogTypeMonitor)
|
// logger.fillBase(entry, LogTypeStatistic)
|
||||||
entry.Target = target
|
// entry.Category = category
|
||||||
entry.Status = status
|
// entry.Item = item
|
||||||
entry.Message = message
|
// entry.Value = value
|
||||||
if len(extra) > 0 {
|
// if len(extra) > 0 {
|
||||||
cast.FillMap(&entry.Extra, extra)
|
// cast.FillMap(&entry.Extra, extra)
|
||||||
}
|
// }
|
||||||
logger.Log(entry)
|
// logger.Log(entry)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
func (logger *Logger) Statistic(category, item string, value float64, extra ...any) {
|
// type DBLog struct {
|
||||||
if logger.CheckLevel(INFO) {
|
// BaseLog
|
||||||
entry := GetEntry(reflect.TypeOf(&StatisticLog{})).(*StatisticLog)
|
// DbType string
|
||||||
logger.fillBase(entry, LogTypeStatistic)
|
// Dsn string
|
||||||
entry.Category = category
|
// Query string
|
||||||
entry.Item = item
|
// QueryArgs string
|
||||||
entry.Value = value
|
// UsedTime float32
|
||||||
if len(extra) > 0 {
|
// Error string
|
||||||
cast.FillMap(&entry.Extra, extra)
|
// CallStacks []string
|
||||||
}
|
// }
|
||||||
logger.Log(entry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type DBLog struct {
|
// func (logger *Logger) DB(dbType, dsn, query string, args []any, usedTime float32, err error, extra ...any) {
|
||||||
BaseLog
|
// logType := LogTypeDb
|
||||||
DbType string
|
// level := INFO
|
||||||
Dsn string
|
// var e string
|
||||||
Query string
|
// if err != nil {
|
||||||
QueryArgs string
|
// logType = LogTypeDbError
|
||||||
UsedTime float32
|
// level = ERROR
|
||||||
Error string
|
// e = err.Error()
|
||||||
CallStacks []string
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) DB(dbType, dsn, query string, args []any, usedTime float32, err error, extra ...any) {
|
// if logger.CheckLevel(level) {
|
||||||
logType := LogTypeDb
|
// entry := GetEntry[DBLog]()
|
||||||
level := INFO
|
// logger.fillBase(entry, logType)
|
||||||
var e string
|
// entry.DbType = dbType
|
||||||
if err != nil {
|
// entry.Dsn = dsn
|
||||||
logType = LogTypeDbError
|
// entry.Query = query
|
||||||
level = ERROR
|
// entry.QueryArgs = cast.To[string](args)
|
||||||
e = err.Error()
|
// entry.UsedTime = usedTime
|
||||||
}
|
// if e != "" {
|
||||||
|
// entry.Error = e
|
||||||
if logger.CheckLevel(level) {
|
// entry.CallStacks = getCallStacks(logger.truncations)
|
||||||
entry := GetEntry(reflect.TypeOf(&DBLog{})).(*DBLog)
|
// }
|
||||||
logger.fillBase(entry, logType)
|
// if len(extra) > 0 {
|
||||||
entry.DbType = dbType
|
// cast.FillMap(&entry.Extra, extra)
|
||||||
entry.Dsn = dsn
|
// }
|
||||||
entry.Query = query
|
// logger.Log(entry)
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user