diff --git a/.cursor/debug.log b/.cursor/debug.log deleted file mode 100644 index e69de29..0000000 diff --git a/log/logrus.go b/log/logrus.go index bd401a2..dda13e7 100644 --- a/log/logrus.go +++ b/log/logrus.go @@ -2,12 +2,13 @@ package log import ( "fmt" - log "github.com/sirupsen/logrus" "os" "path/filepath" "runtime" "strings" "time" + + log "github.com/sirupsen/logrus" ) func GetLog(path string, showCodeLine bool) *log.Logger { @@ -73,41 +74,98 @@ func (that *MyHook) Fire(entry *log.Entry) error { return nil } -// 对caller进行递归查询, 直到找到非logrus包产生的第一个调用. -// 因为filename我获取到了上层目录名, 因此所有logrus包的调用的文件名都是 logrus/... -// 因此通过排除logrus开头的文件名, 就可以排除所有logrus包的自己的函数调用 -func findCaller(skip int) string { - file := "" - line := 0 - for i := 0; i < 10; i++ { - file, line = getCaller(skip + i) - if !strings.HasPrefix(file, "logrus") { - j := 0 - for true { - j++ - if file == "common/error.go" { - file, line = getCaller(skip + i + j) - } - if file == "db/hotimedb.go" { - file, line = getCaller(skip + i + j) - } - if file == "code/makecode.go" { - file, line = getCaller(skip + i + j) - } - if strings.Index(file, "common/") == 0 { - file, line = getCaller(skip + i + j) - } - if strings.Contains(file, "application.go") { - file, line = getCaller(skip + i + j) - } - if j == 5 { - break - } - } +// 最大框架层数限制 - 超过这个层数后不再跳过,防止误过滤应用层 +const maxFrameworkDepth = 10 - break +// isHoTimeFrameworkFile 判断是否是 HoTime 框架文件 +// 更精确的匹配:只有明确属于框架的文件才会被跳过 +func isHoTimeFrameworkFile(file string) bool { + // 1. logrus 日志库内部文件 + if strings.HasPrefix(file, "logrus/") { + return true + } + + // 2. Go 运行时文件 + if strings.HasPrefix(file, "runtime/") { + return true + } + + // 3. HoTime 框架核心文件 - 通过包含 "hotime" 或框架特有文件名来识别 + // 检查路径中是否包含 hotime 框架标识 + lowerFile := strings.ToLower(file) + if strings.Contains(lowerFile, "hotime") { + // 是 hotime 框架的一部分,检查是否是核心模块 + frameworkDirs := []string{"/db/", "/common/", "/code/", "/cache/", "/log/", "/dri/"} + for _, dir := range frameworkDirs { + if strings.Contains(file, dir) { + return true + } + } + // 框架核心文件(在 hotime 根目录下的 .go 文件) + if strings.HasSuffix(file, "application.go") || + strings.HasSuffix(file, "context.go") || + strings.HasSuffix(file, "session.go") || + strings.HasSuffix(file, "const.go") || + strings.HasSuffix(file, "type.go") || + strings.HasSuffix(file, "var.go") || + strings.HasSuffix(file, "mime.go") { + return true } } + + // 4. 直接匹配框架核心目录(用于没有完整路径的情况) + // 只匹配 "db/xxx.go" 这种在框架核心目录下的文件 + frameworkCoreDirs := []string{"db/", "common/", "code/", "cache/"} + for _, dir := range frameworkCoreDirs { + if strings.HasPrefix(file, dir) { + // 额外检查:确保不是用户项目中同名目录 + // 框架文件通常有特定的文件名 + frameworkFiles := []string{ + "query.go", "crud.go", "where.go", "builder.go", "db.go", + "dialect.go", "aggregate.go", "transaction.go", "identifier.go", + "error.go", "func.go", "map.go", "obj.go", "slice.go", + "makecode.go", "template.go", "config.go", + "cache.go", "cache_db.go", "cache_memory.go", "cache_redis.go", + } + for _, f := range frameworkFiles { + if strings.HasSuffix(file, f) { + return true + } + } + } + } + + return false +} + +// 对caller进行递归查询, 直到找到非框架层产生的第一个调用. +// 遍历调用栈,跳过框架层文件,找到应用层代码 +// 使用层数限制确保不会误过滤应用层同名目录 +func findCaller(skip int) string { + frameworkCount := 0 // 连续框架层计数 + + // 遍历调用栈,找到第一个非框架文件 + for i := 0; i < 20; i++ { + file, line := getCaller(skip + i) + if file == "" { + break + } + + if isHoTimeFrameworkFile(file) { + frameworkCount++ + // 层数限制:如果已经跳过太多层,停止跳过 + if frameworkCount >= maxFrameworkDepth { + return fmt.Sprintf("%s:%d", file, line) + } + continue + } + + // 找到非框架文件,返回应用层代码位置 + return fmt.Sprintf("%s:%d", file, line) + } + + // 如果找不到应用层,返回最初的调用者 + file, line := getCaller(skip) return fmt.Sprintf("%s:%d", file, line) }