fckeuspy-go/vendor/github.com/hack-pad/safejs/internal/stackerr/stackerr.go

80 lines
1.4 KiB
Go

//go:build js && wasm
// Package stackerr adds stack traces to verbose error messages.
package stackerr
import (
"fmt"
"runtime"
"strings"
)
type stackError struct {
err error
stack *stacktrace
}
// WithStack returns 'err' with a stack trace in its verbose formatter output.
// Returns nil if err is nil.
func WithStack(err error) error {
if err == nil {
return nil
}
return &stackError{
err: err,
stack: collectStacktrace(3),
}
}
func (s *stackError) Error() string {
return s.err.Error()
}
func (s *stackError) Unwrap() error {
return s.err
}
func (s *stackError) Format(f fmt.State, verb rune) {
switch verb {
case 'v':
if f.Flag('+') {
fmt.Fprintf(f, "%+v\n%s", s.err, s.stack)
return
}
fmt.Fprint(f, s.Error())
case 's':
fmt.Fprint(f, s.Error())
case 'q':
fmt.Fprintf(f, "%q", s.Error())
}
}
type stacktrace struct {
callers []uintptr
}
func collectStacktrace(skip int) *stacktrace {
const (
maxFrames = 32
)
pc := make([]uintptr, maxFrames)
n := runtime.Callers(1+skip, pc)
return &stacktrace{
callers: pc[:n],
}
}
func (s *stacktrace) String() string {
var sb strings.Builder
frames := runtime.CallersFrames(s.callers)
for frame, next := frames.Next(); next; frame, next = frames.Next() {
funcName := "unknown"
if frame.Func != nil {
funcName = frame.Func.Name()
}
sb.WriteString(fmt.Sprintf("%s\n\t%s:%d\n", funcName, frame.File, frame.Line))
}
return sb.String()
}