feat: add log.As and logger.As for frictionless error handling
This commit is contained in:
parent
a2b1055f5d
commit
1f816dc8b3
@ -1,5 +1,11 @@
|
||||
# Changelog
|
||||
|
||||
## [1.3.2] - 2026-05-13
|
||||
- **功能增强: 引入摩擦消除工具 `As`**:
|
||||
- **泛型支持**: 新增全局泛型函数 `log.As[T](v T, err error) T`,仿照 `cast.As` 设计,自动记录错误并返回零值,极大简化了带 error 返回值的函数链式调用。
|
||||
- **Logger 扩展**: `Logger` 结构体新增 `As(v any, err error) any` 方法,支持实例级别的错误捕获与自动记录。
|
||||
- **调用栈优化**: 优化了 `GetCallStacks` 逻辑,自动跳过 `default_logger.go` 中的内部帧,确保 `log.As` 记录的错误位置精准指向业务代码。
|
||||
|
||||
## [1.3.1] - 2026-05-12
|
||||
- **架构升级: 引入 LoggerService**:
|
||||
- **解耦重构**: 重构全局变量管理,引入 `loggerService` 结构体,集中化管理异步写入协程、Writers 对象池、文件句柄与丢弃计数。
|
||||
|
||||
@ -89,10 +89,14 @@ export LOG_FILE=console
|
||||
1. **分级记录**
|
||||
* `Debug`, `Info`, `Warning`, `Error` —— 标准日志方法,支持 `message` + 变长 `extra` 参数。
|
||||
|
||||
2. **通用记录 (`Log`)**
|
||||
2. **摩擦消除 (`As`)**
|
||||
* `As(v, err)` —— 仿照 `cast.As`,忽略错误并返回零值,但会自动将错误记录到日志中。支持全局调用 (`log.As`) 或实例调用 (`logger.As`)。
|
||||
* **优势**: 在类型转换或快速赋值场景下,无需繁琐的 `if err != nil` 判断,同时确保异常被记录。
|
||||
|
||||
3. **通用记录 (`Log`)**
|
||||
* `Log(LogEntry)` —— 记录自定义结构的日志。
|
||||
|
||||
3. **独立可视化工具 (`logv`)**
|
||||
4. **独立可视化工具 (`logv`)**
|
||||
* **安装**: `go install apigo.cc/go/log/logv@latest`
|
||||
* **使用**: `tail -f app.log | logv` 或 `tail -f app.log | logv -json`。
|
||||
|
||||
|
||||
@ -30,3 +30,15 @@ func SetDefaultName(name string) {
|
||||
DefaultLogger.SetName(name)
|
||||
}
|
||||
}
|
||||
|
||||
// As 仿照 cast.As,使用 DefaultLogger 记录错误并返回零值 (消除摩擦)
|
||||
func As[T any](v T, err error) T {
|
||||
if err != nil {
|
||||
if DefaultLogger != nil {
|
||||
DefaultLogger.Error(err.Error())
|
||||
}
|
||||
var zero T
|
||||
return zero
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
26
log_test.go
26
log_test.go
@ -1,6 +1,7 @@
|
||||
package log_test
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"apigo.cc/go/log"
|
||||
@ -86,3 +87,28 @@ func TestExtraLogs(t *testing.T) {
|
||||
|
||||
logger.Info("Extra log test", "key", "value")
|
||||
}
|
||||
|
||||
func TestAs(t *testing.T) {
|
||||
// 1. 测试 log.As (使用 DefaultLogger)
|
||||
val1 := log.As(strconv.Atoi("123"))
|
||||
if val1 != 123 {
|
||||
t.Errorf("log.As expected 123, got %v", val1)
|
||||
}
|
||||
|
||||
val2 := log.As(strconv.Atoi("abc"))
|
||||
if val2 != 0 {
|
||||
t.Errorf("log.As expected 0, got %v", val2)
|
||||
}
|
||||
|
||||
// 2. 测试 logger.As (方法)
|
||||
logger := log.NewLogger(log.Config{Level: "debug"})
|
||||
val3 := logger.As(strconv.Atoi("456")).(int)
|
||||
if val3 != 456 {
|
||||
t.Errorf("logger.As expected 456, got %v", val3)
|
||||
}
|
||||
|
||||
val4 := logger.As(strconv.Atoi("def")).(int)
|
||||
if val4 != 0 {
|
||||
t.Errorf("logger.As expected 0, got %v", val4)
|
||||
}
|
||||
}
|
||||
|
||||
@ -254,6 +254,14 @@ func (logger *Logger) GetTraceId() string {
|
||||
return logger.traceId
|
||||
}
|
||||
|
||||
// As 仿照 cast.As,忽略错误并返回零值,但会将错误记录到日志中 (消除摩擦)
|
||||
func (logger *Logger) As(v any, err error) any {
|
||||
if err != nil {
|
||||
logger.Error(err.Error())
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func (logger *Logger) CheckLevel(logLevel LevelType) bool {
|
||||
settedLevel := logger.level
|
||||
if settedLevel == 0 {
|
||||
|
||||
@ -69,6 +69,7 @@ func getCallStacks(truncations []string) []string {
|
||||
isLogInternal := (strings.Contains(file, "/log/logger.go") ||
|
||||
strings.Contains(file, "/log/utility.go") ||
|
||||
strings.Contains(file, "/log/standard.go") ||
|
||||
strings.Contains(file, "/log/default_logger.go") ||
|
||||
strings.Contains(file, "/log/extra.go"))
|
||||
|
||||
if isLogInternal {
|
||||
|
||||
@ -181,12 +181,12 @@ func TestCallStacksViewable(t *testing.T) {
|
||||
wd, _ := os.Getwd()
|
||||
entry := &CallStackLog{
|
||||
BaseLog: log.BaseLog{
|
||||
LogType: "error",
|
||||
LogType: "test_error",
|
||||
LogTime: 1714896000000000000,
|
||||
},
|
||||
CallStacks: []string{wd + "/main.go:10", "/usr/local/go/src/runtime/panic.go:100"},
|
||||
}
|
||||
log.RegisterType("error", entry)
|
||||
log.RegisterType("test_error", entry)
|
||||
|
||||
line := string(log.Marshal(entry, nil))
|
||||
out := log.Viewable(line)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user