71 lines
1.4 KiB
Go
71 lines
1.4 KiB
Go
package fingerprint
|
|
|
|
// Frame represents a single stack frame parsed from a crash report.
|
|
type Frame struct {
|
|
Index int
|
|
Address string
|
|
Function string
|
|
File string
|
|
Line int
|
|
Module string
|
|
Inline bool
|
|
}
|
|
|
|
// NormalizedFrame is a frame after normalization for stable fingerprinting.
|
|
type NormalizedFrame struct {
|
|
Function string
|
|
File string
|
|
}
|
|
|
|
// Result contains the output of the fingerprinting pipeline.
|
|
type Result struct {
|
|
Fingerprint string
|
|
Frames []Frame
|
|
Normalized []NormalizedFrame
|
|
Parser string
|
|
}
|
|
|
|
// Compute runs the full fingerprinting pipeline on raw crash text:
|
|
// parse -> normalize -> hash.
|
|
func Compute(raw string) *Result {
|
|
frames, parser := Parse(raw)
|
|
if len(frames) == 0 {
|
|
return nil
|
|
}
|
|
|
|
normalized := Normalize(frames)
|
|
if len(normalized) == 0 {
|
|
return nil
|
|
}
|
|
|
|
fp := Hash(normalized)
|
|
|
|
return &Result{
|
|
Fingerprint: fp,
|
|
Frames: frames,
|
|
Normalized: normalized,
|
|
Parser: parser,
|
|
}
|
|
}
|
|
|
|
// Parse tries each parser in priority order and returns the first successful result.
|
|
func Parse(raw string) ([]Frame, string) {
|
|
parsers := []struct {
|
|
name string
|
|
fn func(string) []Frame
|
|
}{
|
|
{"asan", ParseASan},
|
|
{"gdb", ParseGDB},
|
|
{"zig", ParseZig},
|
|
{"generic", ParseGeneric},
|
|
}
|
|
|
|
for _, p := range parsers {
|
|
frames := p.fn(raw)
|
|
if len(frames) > 0 {
|
|
return frames, p.name
|
|
}
|
|
}
|
|
return nil, ""
|
|
}
|