mirror of
https://github.com/alexgo-io/gaze-indexer.git
synced 2026-04-01 22:35:22 +08:00
93 lines
2.3 KiB
Go
93 lines
2.3 KiB
Go
package stacktrace
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"runtime"
|
|
"strings"
|
|
)
|
|
|
|
// StackTrace is the type of the data for a call stack.
|
|
// This mirrors the type of the same name in [github.com/cockroachdb/errors/errbase.StackTrace].
|
|
type StackTrace struct {
|
|
PCS []uintptr
|
|
Frames []Frame
|
|
}
|
|
|
|
// Caller captures a stack trace of the specified depth, skipping
|
|
// the provided number of frames. skip=0 identifies the caller of Caller.
|
|
//
|
|
// Alias of [Capture]
|
|
func Caller(skip int) *StackTrace {
|
|
return Capture(1 + skip)
|
|
}
|
|
|
|
// Capture captures a stack trace of the specified depth, skipping
|
|
// the provided number of frames. skip=0 identifies the caller of Capture.
|
|
func Capture(skip int) *StackTrace {
|
|
pcs := make([]uintptr, 64)
|
|
n := runtime.Callers(2+skip, pcs[:])
|
|
|
|
// Expand the pcs slice if there wasn't enough room.
|
|
for n == len(pcs) {
|
|
pcs = make([]uintptr, 2*len(pcs))
|
|
n = runtime.Callers(2+skip, pcs[:])
|
|
}
|
|
|
|
// Deallocate the unused space in the slice.
|
|
pcs = pcs[:n:n]
|
|
|
|
return ParsePCS(pcs)
|
|
}
|
|
|
|
func ParsePCS(pcs []uintptr) *StackTrace {
|
|
frames := make([]Frame, 0, len(pcs))
|
|
callerFrames := runtime.CallersFrames(pcs)
|
|
for frame, more := callerFrames.Next(); more; frame, more = callerFrames.Next() {
|
|
if !strings.HasPrefix(frame.Function, "runtime.") {
|
|
frames = append(frames, Frame{frame})
|
|
}
|
|
}
|
|
return &StackTrace{
|
|
PCS: pcs,
|
|
Frames: frames[:len(frames):len(frames)],
|
|
}
|
|
}
|
|
|
|
// FramesStrings returns the frames of this stacktrace as slice of strings.
|
|
func (s *StackTrace) FramesStrings() []string {
|
|
str := make([]string, len(s.Frames))
|
|
for i, frame := range s.Frames {
|
|
str[i] = frame.String()
|
|
}
|
|
return str
|
|
}
|
|
|
|
// Count reports the total number of frames in this stacktrace.
|
|
func (s *StackTrace) Count() int {
|
|
return len(s.Frames)
|
|
}
|
|
|
|
// Format formats the stack of Frames according to the fmt.Formatter interface.
|
|
func (s *StackTrace) Format(fs fmt.State, verb rune) {
|
|
for i, frame := range s.Frames {
|
|
if i > 0 {
|
|
_, _ = io.WriteString(fs, "\n")
|
|
}
|
|
frame.Format(fs, verb)
|
|
}
|
|
}
|
|
|
|
// String returns a string representation of the stack trace.
|
|
func (s *StackTrace) String() string {
|
|
var sb strings.Builder
|
|
for i, frame := range s.Frames {
|
|
if i > 0 {
|
|
sb.WriteString(", ")
|
|
}
|
|
sb.WriteString(fmt.Sprintf("[%d] ", len(s.Frames)-i))
|
|
sb.WriteString(frame.String())
|
|
}
|
|
return sb.String()
|
|
}
|