@@ -18,6 +18,7 @@ type Patterns struct {
18
18
Function * regexp.Regexp
19
19
Location * regexp.Regexp
20
20
CreatedBy * regexp.Regexp
21
+ LongFunc * regexp.Regexp
21
22
}
22
23
23
24
// NewParser creates a new Parser instance with the given options
@@ -30,22 +31,25 @@ func NewParser(options ...Option) *Parser {
30
31
return & Parser {
31
32
config : config ,
32
33
patterns : & Patterns {
33
- Goroutine : regexp .MustCompile (`goroutine (\d+) \[([\w\.]+)\]:` ),
34
- Function : regexp .MustCompile (`^(\S+)\((.*)\)$` ),
35
- Location : regexp .MustCompile (`^\s*(.+\.go):(\d+)(.*)$` ),
34
+ // universal all function regex ^(\S+)\((.*)\)$
35
+ Goroutine : regexp .MustCompile (`goroutine (\d+) \[(.*?)\]:` ),
36
+ Function : regexp .MustCompile (`^([^\s/]+)\((.*)\)$` ),
37
+ Location : regexp .MustCompile (`^\s*(.+\.go):(\d+)(?:\s+\+([0-9a-fA-Fx]+))?$` ),
36
38
CreatedBy : regexp .MustCompile (`created by (.+) in goroutine (\d+)` ),
39
+ LongFunc : regexp .MustCompile (`^(\S*/\S+)\((.*)\)$` ),
37
40
},
38
41
}
39
42
}
40
43
41
44
// Parse converts a byte slice containing a stack trace into a StackTrace
42
- func (p * Parser ) Parse (stack []byte ) * StackTrace {
45
+ func (p * Parser ) Parse (stack []byte ) [] * StackTrace {
43
46
lines := strings .Split (string (stack ), "\n " )
44
47
return p .parseLines (lines )
45
48
}
46
49
47
- func (p * Parser ) parseLines (lines []string ) * StackTrace {
48
- trace := & StackTrace {}
50
+ func (p * Parser ) parseLines (lines []string ) []* StackTrace {
51
+ var traces []* StackTrace
52
+ var currentTrace * StackTrace
49
53
var currentEntry * StackEntry
50
54
51
55
for i := 0 ; i < len (lines ); i ++ {
@@ -54,25 +58,50 @@ func (p *Parser) parseLines(lines []string) *StackTrace {
54
58
continue
55
59
}
56
60
57
- // Handle goroutine header
61
+ // Handle goroutine header - starts a new trace
58
62
if match := p .patterns .Goroutine .FindStringSubmatch (line ); match != nil {
59
- if currentEntry != nil {
60
- trace .Entries = append (trace .Entries , * currentEntry )
63
+ // Save current entry if exists
64
+ if currentEntry != nil && currentTrace != nil {
65
+ currentTrace .Entries = append (currentTrace .Entries , * currentEntry )
61
66
currentEntry = nil
62
67
}
63
- trace .GoroutineID = match [1 ]
64
- trace .GoroutineState = match [2 ]
68
+
69
+ // Create new trace
70
+ currentTrace = & StackTrace {
71
+ GoroutineID : match [1 ],
72
+ GoroutineState : match [2 ],
73
+ }
74
+ traces = append (traces , currentTrace )
75
+ continue
76
+ }
77
+
78
+ // Skip if no current trace
79
+ if currentTrace == nil {
65
80
continue
66
81
}
67
82
68
83
// Handle function calls
69
84
if match := p .patterns .Function .FindStringSubmatch (line ); match != nil {
70
85
if currentEntry != nil {
71
- trace .Entries = append (trace .Entries , * currentEntry )
86
+ currentTrace .Entries = append (currentTrace .Entries , * currentEntry )
87
+ }
88
+
89
+ funcName := match [1 ]
90
+ args := match [2 ]
91
+
92
+ // Handle long function names
93
+ if len (funcName ) > 60 { // Configurable threshold
94
+ parts := strings .Split (funcName , "/" )
95
+ if len (parts ) > 3 {
96
+ // Keep the last three parts
97
+ funcName = ".../" + strings .Join (parts [len (parts )- 3 :], "/" )
98
+ }
72
99
}
100
+
73
101
currentEntry = & StackEntry {
74
- FunctionName : match [1 ],
75
- Args : match [2 ],
102
+ FunctionName : funcName ,
103
+ Args : args ,
104
+ FullName : match [1 ], // Store full name for reference
76
105
}
77
106
continue
78
107
}
@@ -85,18 +114,25 @@ func (p *Parser) parseLines(lines []string) *StackTrace {
85
114
}
86
115
currentEntry .File = filePath
87
116
currentEntry .Line = match [2 ]
117
+ if len (match ) > 3 && match [3 ] != "" {
118
+ currentEntry .Offset = match [3 ]
119
+ }
88
120
continue
89
121
}
90
122
91
123
// Handle "created by" lines
92
124
if match := p .patterns .CreatedBy .FindStringSubmatch (line ); match != nil {
93
125
if currentEntry != nil {
94
- trace .Entries = append (trace .Entries , * currentEntry )
126
+ currentTrace .Entries = append (currentTrace .Entries , * currentEntry )
95
127
}
128
+
96
129
currentEntry = & StackEntry {
97
- FunctionName : match [1 ],
98
- IsCreatedBy : true ,
130
+ FunctionName : match [1 ],
131
+ IsCreatedBy : true ,
132
+ CreatedByGoroutine : match [2 ],
99
133
}
134
+
135
+ // Look ahead for location
100
136
if i + 1 < len (lines ) && p .patterns .Location .MatchString (lines [i + 1 ]) {
101
137
locMatch := p .patterns .Location .FindStringSubmatch (lines [i + 1 ])
102
138
filePath := locMatch [1 ]
@@ -105,19 +141,26 @@ func (p *Parser) parseLines(lines []string) *StackTrace {
105
141
}
106
142
currentEntry .File = filePath
107
143
currentEntry .Line = locMatch [2 ]
144
+ if len (locMatch ) > 3 && locMatch [3 ] != "" {
145
+ currentEntry .Offset = locMatch [3 ]
146
+ }
108
147
i ++
109
148
}
110
149
continue
111
150
}
112
151
}
113
152
114
- if currentEntry != nil {
115
- trace .Entries = append (trace .Entries , * currentEntry )
153
+ // Add final entry if exists
154
+ if currentEntry != nil && currentTrace != nil {
155
+ currentTrace .Entries = append (currentTrace .Entries , * currentEntry )
116
156
}
117
157
118
- return trace
158
+ return traces
119
159
}
120
160
121
161
func (p * Parser ) simplifyPath (path string ) string {
122
- return filepath .Base (path )
162
+ if p .config .Simple {
163
+ return filepath .Base (path )
164
+ }
165
+ return path
123
166
}
0 commit comments