64 lines
1.2 KiB
Go
64 lines
1.2 KiB
Go
package log
|
|
|
|
import (
|
|
"runtime"
|
|
"runtime/debug"
|
|
"strings"
|
|
"sync"
|
|
)
|
|
|
|
func getSingleCallerPc(skip int) uintptr {
|
|
var pc [1]uintptr
|
|
runtime.Callers(skip+2, pc[:])
|
|
return pc[0]
|
|
}
|
|
|
|
type Loc struct {
|
|
Package string
|
|
Function string
|
|
File string
|
|
Line int
|
|
}
|
|
|
|
// This is the package returned for a caller frame that is in the main package for a binary.
|
|
const mainPackageFrameImport = "main"
|
|
|
|
// Reads the build info to get the true full import path for the main package.
|
|
var mainPackagePath = sync.OnceValue(func() string {
|
|
info, ok := debug.ReadBuildInfo()
|
|
if ok {
|
|
return info.Path
|
|
}
|
|
return mainPackageFrameImport
|
|
})
|
|
|
|
func locFromPc(pc uintptr) Loc {
|
|
f, _ := runtime.CallersFrames([]uintptr{pc}).Next()
|
|
lastSlash := strings.LastIndexByte(f.Function, '/')
|
|
firstDot := strings.IndexByte(f.Function[lastSlash+1:], '.')
|
|
pkg := f.Function[:lastSlash+1+firstDot]
|
|
if pkg == mainPackageFrameImport {
|
|
pkg = mainPackagePath()
|
|
}
|
|
return Loc{
|
|
Package: pkg,
|
|
Function: f.Function,
|
|
File: f.File,
|
|
Line: f.Line,
|
|
}
|
|
}
|
|
|
|
var pcToLoc sync.Map
|
|
|
|
func getMsgLogLoc(msg Msg) Loc {
|
|
var pc [1]uintptr
|
|
msg.Callers(1, pc[:])
|
|
locIf, ok := pcToLoc.Load(pc[0])
|
|
if ok {
|
|
return locIf.(Loc)
|
|
}
|
|
loc := locFromPc(pc[0])
|
|
pcToLoc.Store(pc[0], loc)
|
|
return loc
|
|
}
|