func (e *oopsError) writeStackTrace(w io.Writer) {
	var base error
	for err := error(e); err != nil; err = Unwrap(err) {
		base = err
	}
	fmt.Fprintf(w, "%s\n\n", base.Error())
	for i, stack := range Frames(e) {
		if i > 0 {
			fmt.Fprintf(w, "\n")
		}
		writeSingleFrameTrace(w, stack)
	}
}
writeStackTrace unwinds a chain of oopsErrors and prints the stacktrace
annotated with explanatory messages.
package oops
import (
	"bytes"
	"fmt"
	"io"
	"runtime"
	"strings"
)
type stack struct {
	frames []uintptr
}
type oopsError struct {
	inner error
	previous *oopsError
	stack *stack
	reason string
	index int
}
func (e *oopsError) Error() string {
	var buffer bytes.Buffer
	e.writeStackTrace(&buffer)
	return buffer.String()
}
func MainStackToString(err error) string {
	var e *oopsError
	if ok := As(err, &e); !ok {
		return ""
	}
	var base error
	for err := error(e); err != nil; err = Unwrap(err) {
		base = err
	}
	var buffer bytes.Buffer
	fmt.Fprintf(&buffer, "%s", base.Error())
	frames := Frames(err)
	if frames == nil || len(frames) == 0 {
		return ""
	}
	fmt.Fprintf(&buffer, "\n\n")
	writeSingleFrameTrace(&buffer, frames[0])
	return buffer.String()
}
func writeSingleFrameTrace(w io.Writer, frames []Frame) {
	for _, frame := range frames {
		if frame.Reason != "" {
			fmt.Fprintf(w, "%s: %s\n", frame.Function, frame.Reason)
		} else {
			fmt.Fprintf(w, "%s\n", frame.Function)
		}
		fmt.Fprintf(w, "\t%s:%d\n", frame.File, frame.Line)
	}
}
func (err *oopsError) Unwrap() error {
	if err.inner != nil {
		return err.inner
	}
	return nil
}
type stackWithReasons struct {
	stack   *stack
	reasons []string
}
func Frames(err error) [][]Frame {
	var e *oopsError
	if ok := As(err, &e); !ok {
		return nil
	}
	stacks := make([]stackWithReasons, 0, 8)
	for ; e != nil; e = e.previous {
		if len(stacks) == 0 || stacks[len(stacks)-1].stack != e.stack {
			stacks = append(stacks, stackWithReasons{
				stack:   e.stack,
				reasons: make([]string, len(e.stack.frames)),
			})
		}
		stacks[len(stacks)-1].reasons[e.index] = e.reason
	}
	parsedStacks := make([][]Frame, 0, len(stacks))
	for i := len(stacks) - 1; i >= 0; i-- {
		frames := stacks[i].stack.frames
		reasons := stacks[i].reasons
		parsedFrames := make([]Frame, 0, 8)
		iter := runtime.CallersFrames(frames)
		j := 0
		for {
			frame, ok := iter.Next()
			if !ok {
				break
			}
			var reason string
			if j < len(frames) && (frame.PC == frames[j] || frame.PC+1 == frames[j]) {
				reason = reasons[j]
				j++
			}
			file := frame.File
			i := strings.LastIndex(file, "/src/")
			if i >= 0 {
				file = file[i+len("/src/"):]
			}
			parsedFrames = append(parsedFrames, Frame{
				File:     file,
				Function: frame.Function,
				Line:     frame.Line,
				Reason:   reason,
			})
		}
		parsedStacks = append(parsedStacks, parsedFrames)
	}
	return parsedStacks
}
func SkipFrames(err error, numFrames int) error {
	var e *oopsError
	if ok := As(err, &e); !ok || numFrames <= 0 {
		return err
	}
	st := e.stack
	if st == nil {
		return err
	}
	numLeftoverFrames := len(st.frames) - int(numFrames)
	if numLeftoverFrames < 0 {
		return err
	}
	frames := make([]uintptr, numLeftoverFrames)
	copy(frames, st.frames[numFrames:])
	return &oopsError{
		inner:    e.inner,
		previous: e.previous,
		stack:    &stack{frames: frames},
		reason:   e.reason,
		index:    e.index,
	}
}