Module: Errsight::SourceContext
- Defined in:
- lib/errsight/source_context.rb
Overview
Reads source files to attach ‘pre_context`, `context_line`, and `post_context` to in_app backtrace frames — the snippet of code around the failing line that turns “stack trace at user.rb:42” into “here’s what user.rb:42 looked like when it crashed.”
Reference: sentry-ruby’s ‘Sentry::LineCache`. Their cache is per-process bounded LRU; ours is the same idea, smaller, no dependencies.
Constant Summary collapse
- PRE_CONTEXT_LINES =
5 lines before, 5 lines after — sentry’s default and a comfortable debugging window. Larger values bloat events without adding value.
5- POST_CONTEXT_LINES =
5- MAX_LINE_BYTES =
Cap each emitted line to keep events bounded. A 1MB minified JS line accidentally landing in a Ruby backtrace (it happens via Sprockets asset pipeline errors) shouldn’t blow our 512KB ingestion limit.
256- CACHE_SIZE =
LRU bound. 100 files × ~100 lines avg × ~80 bytes per line = ~800KB cache footprint per process. Cheap. A request typically reads <10 unique files for context; the cache absorbs cross-request sharing.
100
Class Method Summary collapse
-
.fetch(filename, lineno) ⇒ Object
Returns { pre_context:, context_line:, post_context: } or nil if the file can’t be read (missing, eval’d, internal, permission denied, malformed encoding, …).
-
.reset_cache! ⇒ Object
Test-only: drop the cache so a test that mutates a fixture file gets the fresh contents on the next fetch.
Class Method Details
.fetch(filename, lineno) ⇒ Object
Returns { pre_context:, context_line:, post_context: } or nil if the file can’t be read (missing, eval’d, internal, permission denied, malformed encoding, …). Never raises — source-context failure must not cascade into a failed event capture.
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/errsight/source_context.rb', line 30 def fetch(filename, lineno) return nil unless filename.is_a?(String) && !filename.empty? return nil unless lineno.is_a?(Integer) && lineno > 0 # Synthetic frames have no readable source. return nil if filename.start_with?("<", "(") lines = read_lines(filename) return nil unless lines idx = lineno - 1 return nil if idx < 0 || idx >= lines.size { pre_context: slice_with_truncation(lines, [ idx - PRE_CONTEXT_LINES, 0 ].max, idx - 1), context_line: truncate(lines[idx]), post_context: slice_with_truncation(lines, idx + 1, [ idx + POST_CONTEXT_LINES, lines.size - 1 ].min) } rescue StandardError nil end |
.reset_cache! ⇒ Object
Test-only: drop the cache so a test that mutates a fixture file gets the fresh contents on the next fetch.
53 54 55 56 |
# File 'lib/errsight/source_context.rb', line 53 def reset_cache! @cache = nil @order = nil end |