Initial QSfera import
This commit is contained in:
+187
@@ -0,0 +1,187 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user