Module: Sentiero::Fingerprint
- Defined in:
- lib/sentiero/fingerprint.rb
Overview
Computes the grouping fingerprint for an exception occurrence. The normalization regexes are deliberately linear-time (simple character classes with a single quantifier, no nesting) so untrusted backtraces cannot trigger catastrophic backtracking (ReDoS).
Constant Summary collapse
- MAX_FRAMES =
Only the top frames drive grouping (deeper frames vary by call site).
5- MAX_FRAME_LENGTH =
1000
Class Method Summary collapse
- .compute(exception_class:, backtrace:, project:) ⇒ Object
-
.normalize_frame(frame) ⇒ Object
Strips per-occurrence noise (memory addresses, line numbers).
Class Method Details
.compute(exception_class:, backtrace:, project:) ⇒ Object
17 18 19 20 21 |
# File 'lib/sentiero/fingerprint.rb', line 17 def compute(exception_class:, backtrace:, project:) frames = Array(backtrace).first(MAX_FRAMES).map { |frame| normalize_frame(frame.to_s) } input = "#{project}\n#{exception_class}\n#{frames.join("\n")}" Digest::SHA256.hexdigest(input)[0, 40] end |
.normalize_frame(frame) ⇒ Object
Strips per-occurrence noise (memory addresses, line numbers). Digits inside
identifiers (e.g. step_1, V2::Api) are preserved so distinct methods do
not collapse into one group.
26 27 28 29 30 31 32 |
# File 'lib/sentiero/fingerprint.rb', line 26 def normalize_frame(frame) frame = frame[0, MAX_FRAME_LENGTH].strip frame .gsub(/0x[0-9a-fA-F]+/, "0xHEX") # memory addresses .gsub(/:[0-9]+(?=:in )/, ":N") # `path:LINE:in 'method'` .gsub(/:[0-9]+\z/, ":N") # `path:LINE` (top-level frame, no method) end |