diff --git a/CHANGELOG.md b/CHANGELOG.md index 5593a23..109f81f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## [1.5.7] - 2026-06-20 +- **调用栈容错增强**: + - `Error` 方法现在支持通过 `extra` 参数传入 `callStacks` 字段,自动合并到结构化的 `CallStacks` 字段中,避免外部调用栈信息丢失。 +- **模块路径兼容**: + - 新增 `isLogPkgFile` 辅助函数,统一处理本地路径 (`.../log/file.go`) 和 Go module 版本路径 (`.../log@v1.5.6/file.go`) 的文件匹配,确保在 module proxy 场景下调用栈过滤同样精准。 + +## [1.5.6] - 2026-06-20 +- **基础设施对齐**: 内部依赖统一升级至 v1.5.x 语义版本。 + ## [1.5.5] - 2026-06-05 - **规范化: Warning 日志行为对齐**: - ** Convention 对齐**: 移除了 `Warning` 级别日志自动附带堆栈信息(`CallStacks`)的逻辑。 diff --git a/logger.go b/logger.go index 92a0df8..9c9804c 100644 --- a/logger.go +++ b/logger.go @@ -282,6 +282,13 @@ func (logger *Logger) Error(message string, extra ...any) { logger.FillError(entry, message) if len(extra) > 0 { cast.FillMap(&entry.Extra, extra) + // Merge extra callStacks into the structured CallStacks field + if stacks, ok := entry.Extra["callStacks"]; ok { + if s, ok := stacks.([]string); ok && len(s) > 0 { + entry.CallStacks = append(s, entry.CallStacks...) + } + delete(entry.Extra, "callStacks") + } } logger.Log(entry) } diff --git a/utility.go b/utility.go index 4aaee9e..52fed7a 100644 --- a/utility.go +++ b/utility.go @@ -52,6 +52,15 @@ func fixField(s string) string { return strings.ToLower(s) } +// isLogPkgFile checks whether a runtime.Caller file path belongs to the log +// package's internal implementation files. It handles both local paths +// (.../log/file.go) and Go module paths with version suffixes +// (.../log@v1.5.6/file.go). +func isLogPkgFile(file, name string) bool { + return strings.HasSuffix(file, "/log/"+name) || + (strings.Contains(file, "/log@") && strings.HasSuffix(file, "/"+name)) +} + // getCallStacks 获取调用栈 func getCallStacks(truncations []string) []string { callStacks := make([]string, 0) @@ -65,12 +74,12 @@ func getCallStacks(truncations []string) []string { continue } // 只有在 logger.go, extra.go 等核心实现文件中的帧才被认为是 "inLogger" - // 这样可以保留测试文件 (xxx_test.go) 的调用栈 - 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")) + // 兼容本地路径 (.../log/file.go) 和 module 路径 (.../log@v1.5.6/file.go) + isLogInternal := isLogPkgFile(file, "logger.go") || + isLogPkgFile(file, "utility.go") || + isLogPkgFile(file, "standard.go") || + isLogPkgFile(file, "default_logger.go") || + isLogPkgFile(file, "extra.go") if isLogInternal { if inLogger {