-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathutil.go
101 lines (90 loc) · 2.59 KB
/
util.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package log
import (
"runtime"
"strconv"
"strings"
)
// find outside caller
func getCaller() string {
// fast lookup
_, currentFile, currentLine, _ := runtime.Caller(3)
return currentFile + ":" + strconv.Itoa(currentLine)
}
// trimOutPrefix removes all the characters before AND the prefix
// its return the original string if not found prefix in str
func trimOutPrefix(str, prefix string) string {
i := strings.Index(str, prefix)
if i < 0 {
return str
}
return str[i+len(prefix):]
}
// trimToPrefix removes all the characters before the prefix
// its return the original string if not found prefix in str
func trimToPrefix(str, prefix string) string {
i := strings.Index(str, prefix)
if i < 0 {
return str
}
return str[i:]
}
// getStack returns 10 closest stacktrace, included file paths and line numbers
// it will ignore all system path, path which is vendor is striped to /vendor/
// skip: number of stack ignored
// returns stack and function name
func GetStack(skip int) (string, string) {
stack := make([]uintptr, 10)
var sb strings.Builder
// skip one system stack, the this current stack line
length := runtime.Callers(4+skip, stack[:])
funcname := ""
first := -1
for i := 0; i < length; i++ {
pc := stack[i]
// pc - 1 because the program counters we use are usually return addresses,
// and we want to show the line that corresponds to the function call
function := runtime.FuncForPC(pc - 1)
if i == 0 {
funcname = function.Name()
}
file, line := function.FileLine(pc - 1)
file = trimToPrefix(file, "/vendor/")
// dont report system path
if isIgnorePath(file) {
continue
}
// trim out common provider since most of go projects are hosted
// in single host, there is no need to include them in the call stack
// remove them help keeping the call stack smaller, navigatiing easier
if !strings.HasPrefix(file, "/vendor") {
file = trimOutPrefix(file, "/github.com/")
file = trimOutPrefix(file, "/gitlab.com/")
file = trimOutPrefix(file, "/gopkg.in/")
}
if first == -1 {
first = i
} else {
sb.WriteString(" | ")
}
sb.WriteString(file + ":" + strconv.Itoa(line))
}
return sb.String(), funcname
}
func Stack() string {
stack, _ := GetStack(0)
return stack
}
// isIgnorePath indicates whether a path is just noise, that excluding the path does not
// affect error context
func isIgnorePath(path string) bool {
if strings.HasPrefix(path, "/usr/local/go/src") {
return true
}
if strings.HasPrefix(path, "/vendor/google.golang.org/") {
return true
}
if strings.HasPrefix(path, "/vendor/github.com/gin-gonic") {
return true
}
return false
}