Module: LaunchDarklyObservability::SourceContext
- Defined in:
- lib/launchdarkly_observability/source_context.rb
Constant Summary collapse
- CONTEXT_LINES =
4- MAX_FRAMES =
20- MAX_LINE_LENGTH =
1000- BACKTRACE_LINE_PATTERN =
/^(.+):(\d+)(?::in [`'](.+?)')?$/
Class Method Summary collapse
- .build_structured_stacktrace(exception) ⇒ Object
-
.exception_attributes(exception) ⇒ Hash
Build a Hash of span attributes for an exception’s structured stacktrace.
- .read_source_context(file_name, line_number) ⇒ Object
Class Method Details
.build_structured_stacktrace(exception) ⇒ Object
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# File 'lib/launchdarkly_observability/source_context.rb', line 16 def build_structured_stacktrace(exception) return nil unless exception backtrace = exception.backtrace return nil unless backtrace&.any? = begin exception.(highlight: false, order: :top).to_s.lines.first&.chomp rescue StandardError exception. end frames = backtrace.first(MAX_FRAMES).filter_map do |backtrace_line| build_frame(backtrace_line, ) end frames.empty? ? nil : frames rescue StandardError nil end |
.exception_attributes(exception) ⇒ Hash
Build a Hash of span attributes for an exception’s structured stacktrace. Returns an empty hash when no stacktrace can be built, so the result is safe to merge directly into an attributes hash.
42 43 44 45 46 47 |
# File 'lib/launchdarkly_observability/source_context.rb', line 42 def exception_attributes(exception) stacktrace = build_structured_stacktrace(exception) return {} unless stacktrace { 'exception.structured_stacktrace' => stacktrace.to_json } end |
.read_source_context(file_name, line_number) ⇒ Object
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/launchdarkly_observability/source_context.rb', line 49 def read_source_context(file_name, line_number) return nil unless file_name && line_number return nil unless File.exist?(file_name) && File.readable?(file_name) source_lines = cached_source_lines(file_name) return nil unless source_lines return nil if line_number <= 0 || line_number > source_lines.length target_index = line_number - 1 before_start = [target_index - CONTEXT_LINES, 0].max before_lines = source_lines[before_start...target_index] || [] after_end = [target_index + CONTEXT_LINES, source_lines.length - 1].min after_lines = source_lines[(target_index + 1)..after_end] || [] { lineContent: source_lines[target_index], linesBefore: before_lines.empty? ? nil : before_lines.join("\n"), linesAfter: after_lines.empty? ? nil : after_lines.join("\n") } rescue StandardError nil end |