-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstack.go
More file actions
105 lines (85 loc) · 2.4 KB
/
stack.go
File metadata and controls
105 lines (85 loc) · 2.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package ewrap
import (
"runtime"
"strings"
)
// StackFrame represents a single frame in a stack trace.
type StackFrame struct {
// Function is the fully qualified function name
Function string `json:"function" yaml:"function"`
// File is the source file path
File string `json:"file" yaml:"file"`
// Line is the line number in the source file
Line int `json:"line" yaml:"line"`
// PC is the program counter for this frame
PC uintptr `json:"pc" yaml:"pc"`
}
// StackTrace represents a collection of stack frames.
type StackTrace []StackFrame
// StackIterator provides a way to iterate through stack frames.
type StackIterator struct {
frames []StackFrame
index int
}
// NewStackIterator creates a new stack iterator from program counters.
func NewStackIterator(pcs []uintptr) *StackIterator {
frames := make([]StackFrame, 0, len(pcs))
callersFrames := runtime.CallersFrames(pcs)
for {
frame, more := callersFrames.Next()
// Skip runtime frames and error package frames
if !strings.Contains(frame.File, "runtime/") &&
!strings.Contains(frame.File, "ewrap/errors.go") {
frames = append(frames, StackFrame{
Function: frame.Function,
File: frame.File,
Line: frame.Line,
PC: frame.PC,
})
}
if !more {
break
}
}
return &StackIterator{
frames: frames,
index: 0,
}
}
// Next returns the next stack frame, or nil if no more frames.
func (si *StackIterator) Next() *StackFrame {
if si.index >= len(si.frames) {
return nil
}
frame := &si.frames[si.index]
si.index++
return frame
}
// HasNext returns true if there are more frames to iterate.
func (si *StackIterator) HasNext() bool {
return si.index < len(si.frames)
}
// Reset resets the iterator to the beginning.
func (si *StackIterator) Reset() {
si.index = 0
}
// Frames returns all remaining frames as a slice.
func (si *StackIterator) Frames() []StackFrame {
if si.index >= len(si.frames) {
return nil
}
return si.frames[si.index:]
}
// AllFrames returns all frames regardless of current position.
func (si *StackIterator) AllFrames() []StackFrame {
return si.frames
}
// GetStackIterator returns a stack iterator for the error's stack trace.
func (e *Error) GetStackIterator() *StackIterator {
return NewStackIterator(e.stack)
}
// GetStackFrames returns all stack frames as a slice.
func (e *Error) GetStackFrames() []StackFrame {
iterator := e.GetStackIterator()
return iterator.AllFrames()
}