kra-new/pkg/logging/source.go

99 lines
2.5 KiB
Go

package logging
import (
"fmt"
"go/ast"
"go/parser"
"go/token"
"os"
"regexp"
"strconv"
"strings"
)
type stackFrame struct {
File string
Line int
Func string
}
var stackFileLinePattern = regexp.MustCompile(`\s*(.+\.go):(\d+)\s*$`)
func finalApplicationCaller(stack string) (stackFrame, bool) {
if stack == "" {
return stackFrame{}, false
}
functionName := ""
for _, raw := range strings.Split(stack, "\n") {
line := strings.TrimSpace(raw)
if line == "" {
continue
}
matches := stackFileLinePattern.FindStringSubmatch(line)
if matches == nil {
functionName = line
continue
}
lineNumber, _ := strconv.Atoi(matches[2])
if skipStackFile(matches[1]) {
functionName = ""
continue
}
return stackFrame{File: matches[1], Line: lineNumber, Func: functionName}, true
}
return stackFrame{}, false
}
func skipStackFile(filename string) bool {
normalized := strings.ReplaceAll(filename, "\\", "/")
for _, marker := range []string{
"/go/pkg/mod/",
"/go.uber.org/",
"/gorm.io/",
"/pkg/logging/",
"/internal/server/middleware/",
"/internal/server/router/",
} {
if strings.Contains(normalized, marker) {
return true
}
}
return strings.Contains(normalized, "/src/") &&
(strings.Contains(normalized, "/go/go") || strings.Contains(normalized, "/go/src/"))
}
func functionSourceAt(filename string, line int) (name, source string, startLine, endLine int, err error) {
content, err := os.ReadFile(filename)
if err != nil {
return "", "", 0, 0, fmt.Errorf("read file failed: %w", err)
}
files := token.NewFileSet()
parsed, err := parser.ParseFile(files, filename, content, parser.ParseComments)
if err != nil {
return "", "", 0, 0, fmt.Errorf("parse file failed: %w", err)
}
var target *ast.FuncDecl
ast.Inspect(parsed, func(node ast.Node) bool {
declaration, ok := node.(*ast.FuncDecl)
if !ok {
return true
}
start := files.Position(declaration.Pos()).Line
end := files.Position(declaration.End()).Line
if line >= start && line <= end {
target, startLine, endLine = declaration, start, end
return false
}
return true
})
if target == nil {
return "", "", 0, 0, fmt.Errorf("no function encloses line %d in %s", line, filename)
}
start := files.Position(target.Pos()).Offset
end := files.Position(target.End()).Offset
if start < 0 || end > len(content) || start >= end {
return "", "", 0, 0, fmt.Errorf("invalid offsets for function: start=%d end=%d len=%d", start, end, len(content))
}
return target.Name.Name, string(content[start:end]), startLine, endLine, nil
}