Files
opencloud/vendor/github.com/gookit/goutil/errorx/stack.go
dependabot[bot] 452d40dad7 build(deps): bump github.com/gookit/config/v2 from 2.2.5 to 2.2.6
Bumps [github.com/gookit/config/v2](https://github.com/gookit/config) from 2.2.5 to 2.2.6.
- [Release notes](https://github.com/gookit/config/releases)
- [Commits](https://github.com/gookit/config/compare/v2.2.5...v2.2.6)

---
updated-dependencies:
- dependency-name: github.com/gookit/config/v2
  dependency-version: 2.2.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-29 14:15:29 +00:00

188 lines
3.7 KiB
Go

package errorx
import (
"bytes"
"fmt"
"io"
"path/filepath"
"runtime"
"strconv"
)
// stack represents a stack of program counters.
type stack []uintptr
// Format stack trace
func (s *stack) Format(fs fmt.State, verb rune) {
switch verb {
// case 'v', 's':
case 'v':
_, _ = s.WriteTo(fs)
}
}
// StackLen for error
func (s *stack) StackLen() int {
return len(*s)
}
// WriteTo for error
func (s *stack) WriteTo(w io.Writer) (int64, error) {
if len(*s) == 0 {
return 0, nil
}
nn, _ := w.Write([]byte("\nSTACK:\n"))
for _, pc := range *s {
// For historical reasons if pc is interpreted as a uintptr
// its value represents the program counter + 1.
fc := runtime.FuncForPC(pc - 1)
if fc == nil {
continue
}
// file eg: workspace/godev/gookit/goutil/errorx/errorx_test.go
file, line := fc.FileLine(pc - 1)
// f.Name() eg: github.com/gookit/goutil/errorx_test.TestWithPrev()
location := fc.Name() + "()\n " + file + ":" + strconv.Itoa(line) + "\n"
n, _ := w.Write([]byte(location))
nn += n
}
return int64(nn), nil
}
// String format to string
func (s *stack) String() string {
var buf bytes.Buffer
_, _ = s.WriteTo(&buf)
return buf.String()
}
// StackFrames stack frame list
func (s *stack) StackFrames() *runtime.Frames {
return runtime.CallersFrames(*s)
}
// CallerPC the caller PC value in the stack. it is first frame.
func (s *stack) CallerPC() uintptr {
if len(*s) == 0 {
return 0
}
// For historical reasons if pc is interpreted as a uintptr
// its value represents the program counter + 1.
return (*s)[0] - 1
}
/*************************************************************
* For error caller func
*************************************************************/
// Func struct
type Func struct {
*runtime.Func
pc uintptr
}
// FuncForPC create.
func FuncForPC(pc uintptr) *Func {
fc := runtime.FuncForPC(pc)
if fc == nil {
return nil
}
return &Func{
pc: pc,
Func: fc,
}
}
// FileLine returns the file name and line number of the source code
func (f *Func) FileLine() (file string, line int) {
return f.Func.FileLine(f.pc)
}
// Location simple location info for the func
//
// Returns eg:
//
// "github.com/gookit/goutil/errorx_test.TestWithPrev(), errorx_test.go:34"
func (f *Func) Location() string {
file, line := f.FileLine()
return f.Name() + "(), " + filepath.Base(file) + ":" + strconv.Itoa(line)
}
// String of the func
//
// Returns eg:
//
// github.com/gookit/goutil/errorx_test.TestWithPrev()
// At /path/to/github.com/gookit/goutil/errorx_test.go:34
func (f *Func) String() string {
file, line := f.FileLine()
return f.Name() + "()\n At " + file + ":" + strconv.Itoa(line)
}
// MarshalText handle
func (f *Func) MarshalText() ([]byte, error) {
return []byte(f.String()), nil
}
/*************************************************************
* helper func for callers stacks
*************************************************************/
// ErrStackOpt struct
type ErrStackOpt struct {
SkipDepth int
TraceDepth int
}
// default option
var stdOpt = newErrOpt()
// ResetStdOpt config
func ResetStdOpt() {
stdOpt = newErrOpt()
}
func newErrOpt() *ErrStackOpt {
return &ErrStackOpt{
SkipDepth: 3,
TraceDepth: 8,
}
}
// Config the stdOpt setting
func Config(fns ...func(opt *ErrStackOpt)) {
for _, fn := range fns {
fn(stdOpt)
}
}
// SkipDepth setting
func SkipDepth(skipDepth int) func(opt *ErrStackOpt) {
return func(opt *ErrStackOpt) {
opt.SkipDepth = skipDepth
}
}
// TraceDepth setting
func TraceDepth(traceDepth int) func(opt *ErrStackOpt) {
return func(opt *ErrStackOpt) {
opt.TraceDepth = traceDepth
}
}
func callersStack(skip, depth int) *stack {
pcs := make([]uintptr, depth)
num := runtime.Callers(skip, pcs[:])
var st stack = pcs[0:num]
return &st
}