|
|
@@ -59,52 +59,7 @@ import (
|
|
|
type stack []uintptr
|
|
|
|
|
|
func (s stack) Location() (string, int) {
|
|
|
- pc := s[0] - 1
|
|
|
- fn := runtime.FuncForPC(pc)
|
|
|
- if fn == nil {
|
|
|
- return "unknown", 0
|
|
|
- }
|
|
|
-
|
|
|
- file, line := fn.FileLine(pc)
|
|
|
-
|
|
|
- // Here we want to get the source file path relative to the compile time
|
|
|
- // GOPATH. As of Go 1.6.x there is no direct way to know the compiled
|
|
|
- // GOPATH at runtime, but we can infer the number of path segments in the
|
|
|
- // GOPATH. We note that fn.Name() returns the function name qualified by
|
|
|
- // the import path, which does not include the GOPATH. Thus we can trim
|
|
|
- // segments from the beginning of the file path until the number of path
|
|
|
- // separators remaining is one more than the number of path separators in
|
|
|
- // the function name. For example, given:
|
|
|
- //
|
|
|
- // GOPATH /home/user
|
|
|
- // file /home/user/src/pkg/sub/file.go
|
|
|
- // fn.Name() pkg/sub.Type.Method
|
|
|
- //
|
|
|
- // We want to produce:
|
|
|
- //
|
|
|
- // pkg/sub/file.go
|
|
|
- //
|
|
|
- // From this we can easily see that fn.Name() has one less path separator
|
|
|
- // than our desired output. We count separators from the end of the file
|
|
|
- // path until it finds two more than in the function name and then move
|
|
|
- // one character forward to preserve the initial path segment without a
|
|
|
- // leading separator.
|
|
|
- const sep = "/"
|
|
|
- goal := strings.Count(fn.Name(), sep) + 2
|
|
|
- i := len(file)
|
|
|
- for n := 0; n < goal; n++ {
|
|
|
- i = strings.LastIndex(file[:i], sep)
|
|
|
- if i == -1 {
|
|
|
- // not enough separators found, set i so that the slice expression
|
|
|
- // below leaves file unmodified
|
|
|
- i = -len(sep)
|
|
|
- break
|
|
|
- }
|
|
|
- }
|
|
|
- // get back to 0 or trim the leading separator
|
|
|
- file = file[i+len(sep):]
|
|
|
-
|
|
|
- return file, line
|
|
|
+ return location(s[0] - 1)
|
|
|
}
|
|
|
|
|
|
// New returns an error that formats as the given text.
|
|
|
@@ -241,3 +196,52 @@ func callers() stack {
|
|
|
n := runtime.Callers(3, pcs[:])
|
|
|
return pcs[0:n]
|
|
|
}
|
|
|
+
|
|
|
+// location returns the source file and line matching pc.
|
|
|
+func location(pc uintptr) (string, int) {
|
|
|
+ fn := runtime.FuncForPC(pc)
|
|
|
+ if fn == nil {
|
|
|
+ return "unknown", 0
|
|
|
+ }
|
|
|
+
|
|
|
+ file, line := fn.FileLine(pc)
|
|
|
+
|
|
|
+ // Here we want to get the source file path relative to the compile time
|
|
|
+ // GOPATH. As of Go 1.6.x there is no direct way to know the compiled
|
|
|
+ // GOPATH at runtime, but we can infer the number of path segments in the
|
|
|
+ // GOPATH. We note that fn.Name() returns the function name qualified by
|
|
|
+ // the import path, which does not include the GOPATH. Thus we can trim
|
|
|
+ // segments from the beginning of the file path until the number of path
|
|
|
+ // separators remaining is one more than the number of path separators in
|
|
|
+ // the function name. For example, given:
|
|
|
+ //
|
|
|
+ // GOPATH /home/user
|
|
|
+ // file /home/user/src/pkg/sub/file.go
|
|
|
+ // fn.Name() pkg/sub.Type.Method
|
|
|
+ //
|
|
|
+ // We want to produce:
|
|
|
+ //
|
|
|
+ // pkg/sub/file.go
|
|
|
+ //
|
|
|
+ // From this we can easily see that fn.Name() has one less path separator
|
|
|
+ // than our desired output. We count separators from the end of the file
|
|
|
+ // path until it finds two more than in the function name and then move
|
|
|
+ // one character forward to preserve the initial path segment without a
|
|
|
+ // leading separator.
|
|
|
+ const sep = "/"
|
|
|
+ goal := strings.Count(fn.Name(), sep) + 2
|
|
|
+ i := len(file)
|
|
|
+ for n := 0; n < goal; n++ {
|
|
|
+ i = strings.LastIndex(file[:i], sep)
|
|
|
+ if i == -1 {
|
|
|
+ // not enough separators found, set i so that the slice expression
|
|
|
+ // below leaves file unmodified
|
|
|
+ i = -len(sep)
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // get back to 0 or trim the leading separator
|
|
|
+ file = file[i+len(sep):]
|
|
|
+
|
|
|
+ return file, line
|
|
|
+}
|