mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-02-19 15:36:04 -05:00
Bumps [github.com/gookit/config/v2](https://github.com/gookit/config) from 2.2.6 to 2.2.7. - [Release notes](https://github.com/gookit/config/releases) - [Commits](https://github.com/gookit/config/compare/v2.2.6...v2.2.7) --- updated-dependencies: - dependency-name: github.com/gookit/config/v2 dependency-version: 2.2.7 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
167 lines
3.5 KiB
Go
167 lines
3.5 KiB
Go
package goinfo
|
|
|
|
import (
|
|
"path/filepath"
|
|
"runtime"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/gookit/goutil/x/basefn"
|
|
)
|
|
|
|
// some commonly consts
|
|
var (
|
|
DefStackLen = 10000
|
|
MaxStackLen = 100000
|
|
)
|
|
|
|
// GetCallStacks stacks is a wrapper for runtime.
|
|
// If all is true, Stack that attempts to recover the data for all goroutines.
|
|
//
|
|
// from glog package
|
|
func GetCallStacks(all bool) []byte {
|
|
// We don't know how big the traces are, so grow a few times if they don't fit.
|
|
// Start large, though.
|
|
n := DefStackLen
|
|
if all {
|
|
n = MaxStackLen
|
|
}
|
|
|
|
// 4<<10 // 4 KB should be enough
|
|
var trace []byte
|
|
for i := 0; i < 10; i++ {
|
|
trace = make([]byte, n)
|
|
bts := runtime.Stack(trace, all)
|
|
if bts < len(trace) {
|
|
return trace[:bts]
|
|
}
|
|
n *= 2
|
|
}
|
|
return trace
|
|
}
|
|
|
|
// GetCallerInfo get caller func name and with base filename and line.
|
|
//
|
|
// returns:
|
|
//
|
|
// github.com/gookit/goutil/x/goinfo_test.someFunc2(),stack_test.go:26
|
|
func GetCallerInfo(skip int) string {
|
|
skip++ // ignore current func
|
|
cs := GetCallersInfo(skip, skip+1)
|
|
return basefn.FirstOr(cs, "")
|
|
}
|
|
|
|
// SimpleCallersInfo returns an array of strings containing
|
|
// the func name, file and line number of each stack frame leading.
|
|
func SimpleCallersInfo(skip, num int) []string {
|
|
skip++ // ignore current func
|
|
return GetCallersInfo(skip, skip+num)
|
|
}
|
|
|
|
// GetCallersInfo returns an array of strings containing
|
|
// the func name, file and line number of each stack frame leading.
|
|
//
|
|
// NOTICE: max should > skip
|
|
func GetCallersInfo(skip, max int) []string {
|
|
var (
|
|
pc uintptr
|
|
ok bool
|
|
line int
|
|
file, name string
|
|
)
|
|
|
|
callers := make([]string, 0, max-skip)
|
|
for i := skip; i < max; i++ {
|
|
pc, file, line, ok = runtime.Caller(i)
|
|
if !ok {
|
|
// The breaks below failed to terminate the loop, and we ran off the
|
|
// end of the call stack.
|
|
break
|
|
}
|
|
|
|
// This is a huge edge case, but it will panic if this is the case
|
|
if file == "<autogenerated>" {
|
|
break
|
|
}
|
|
|
|
fc := runtime.FuncForPC(pc)
|
|
if fc == nil {
|
|
break
|
|
}
|
|
|
|
if strings.ContainsRune(file, '/') {
|
|
name = fc.Name()
|
|
file = filepath.Base(file)
|
|
// eg: github.com/gookit/goutil/x/goinfo_test.someFunc2(),stack_test.go:26
|
|
callers = append(callers, name+"(),"+file+":"+strconv.Itoa(line))
|
|
}
|
|
|
|
// Drop the package
|
|
// segments := strings.Split(name, ".")
|
|
// name = segments[len(segments)-1]
|
|
}
|
|
|
|
return callers
|
|
}
|
|
|
|
// CallerInfo struct
|
|
type CallerInfo struct {
|
|
PC uintptr
|
|
Fc *runtime.Func
|
|
File string
|
|
Line int
|
|
}
|
|
|
|
// String convert
|
|
func (ci *CallerInfo) String() string {
|
|
return ci.File + ":" + strconv.Itoa(ci.Line)
|
|
}
|
|
|
|
// CallerFilterFunc type
|
|
type CallerFilterFunc func(file string, fc *runtime.Func) bool
|
|
|
|
// CallersInfos returns an array of the CallerInfo, can with filters
|
|
//
|
|
// Usage:
|
|
//
|
|
// cs := sysutil.CallersInfos(3, 2)
|
|
// for _, ci := range cs {
|
|
// fc := runtime.FuncForPC(pc)
|
|
// // maybe need check fc = nil
|
|
// fnName = fc.Name()
|
|
// }
|
|
func CallersInfos(skip, num int, filters ...CallerFilterFunc) []*CallerInfo {
|
|
filterLn := len(filters)
|
|
callers := make([]*CallerInfo, 0, num)
|
|
for i := skip; i < skip+num; i++ {
|
|
pc, file, line, ok := runtime.Caller(i)
|
|
if !ok {
|
|
// The breaks below failed to terminate the loop, and we ran off the
|
|
// end of the call stack.
|
|
break
|
|
}
|
|
|
|
fc := runtime.FuncForPC(pc)
|
|
if fc == nil {
|
|
continue
|
|
}
|
|
|
|
if filterLn > 0 && filters[0] != nil {
|
|
// filter - return false for skip
|
|
if !filters[0](file, fc) {
|
|
continue
|
|
}
|
|
}
|
|
|
|
// collecting
|
|
callers = append(callers, &CallerInfo{
|
|
PC: pc,
|
|
Fc: fc,
|
|
File: file,
|
|
Line: line,
|
|
})
|
|
}
|
|
|
|
return callers
|
|
}
|