github.com/artisanhe/tools@v1.0.1-0.20210607022958-19a8fef2eb04/catgo/cat-go/cat/stacktrace.go (about) 1 package cat 2 3 import ( 4 "bytes" 5 "fmt" 6 "go/build" 7 "path/filepath" 8 "runtime" 9 "strings" 10 ) 11 12 var trimPaths []string 13 14 func init() { 15 for _, prefix := range build.Default.SrcDirs() { 16 if prefix[len(prefix)-1] != filepath.Separator { 17 prefix += string(filepath.Separator) 18 } 19 trimPaths = append(trimPaths, prefix) 20 } 21 } 22 23 func trimPath(filename string) string { 24 for _, prefix := range trimPaths { 25 if trimmed := strings.TrimPrefix(filename, prefix); len(trimmed) < len(filename) { 26 return trimmed 27 } 28 } 29 return filename 30 } 31 32 func functionName(pc uintptr) string { 33 fn := runtime.FuncForPC(pc) 34 if fn == nil { 35 return "unknown" 36 } 37 return fn.Name() 38 } 39 40 func newStacktrace(skip int, err error) (buf *bytes.Buffer) { 41 buf = bytes.NewBuffer([]byte{}) 42 buf.WriteString(err.Error()) 43 buf.WriteRune('\n') 44 for i := skip; ; i++ { 45 pc, file, line, ok := runtime.Caller(i) 46 if !ok { 47 break 48 } 49 file = trimPath(file) 50 name := functionName(pc) 51 // `runtime.goexit` is bootstrap loader and is meaningless in tracing. 52 if name == "runtime.goexit" { 53 continue 54 } 55 buf.WriteString(fmt.Sprintf("at %s(%s:%d)\n", name, file, line)) 56 } 57 return buf 58 }