2022-06-15 11:09:20 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
module ErrorTracking
|
|
|
|
class StacktraceBuilder
|
|
|
|
attr_reader :stacktrace
|
|
|
|
|
|
|
|
def initialize(payload)
|
|
|
|
@stacktrace = build_stacktrace(payload)
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
def build_stacktrace(payload)
|
|
|
|
raw_stacktrace = raw_stacktrace_from_payload(payload)
|
|
|
|
return [] unless raw_stacktrace
|
|
|
|
|
|
|
|
raw_stacktrace.map do |entry|
|
|
|
|
{
|
|
|
|
'lineNo' => entry['lineno'],
|
|
|
|
'context' => build_stacktrace_context(entry),
|
|
|
|
'filename' => entry['filename'],
|
|
|
|
'function' => entry['function'],
|
|
|
|
'colNo' => 0 # we don't support colNo yet.
|
|
|
|
}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def raw_stacktrace_from_payload(payload)
|
|
|
|
exception_entry = payload['exception']
|
|
|
|
return unless exception_entry
|
|
|
|
|
2022-06-23 05:08:58 -04:00
|
|
|
# Some SDK send exception payload as Array. For exmple Go lang SDK.
|
|
|
|
# We need to convert it to hash format we expect.
|
|
|
|
exception_entry = { 'values' => exception_entry } if exception_entry.is_a?(Array)
|
|
|
|
|
2022-06-15 11:09:20 -04:00
|
|
|
exception_values = exception_entry['values']
|
|
|
|
stack_trace_entry = exception_values&.detect { |h| h['stacktrace'].present? }
|
|
|
|
stack_trace_entry&.dig('stacktrace', 'frames')
|
|
|
|
end
|
|
|
|
|
|
|
|
def build_stacktrace_context(entry)
|
|
|
|
error_line = entry['context_line']
|
|
|
|
error_line_no = entry['lineno']
|
|
|
|
pre_context = entry['pre_context']
|
|
|
|
post_context = entry['post_context']
|
|
|
|
|
|
|
|
context = []
|
|
|
|
context.concat lines_with_position(pre_context, error_line_no - pre_context.size) if pre_context
|
|
|
|
context.concat lines_with_position([error_line], error_line_no)
|
|
|
|
context.concat lines_with_position(post_context, error_line_no + 1) if post_context
|
|
|
|
|
|
|
|
context.reject(&:blank?)
|
|
|
|
end
|
|
|
|
|
|
|
|
def lines_with_position(lines, position)
|
|
|
|
return [] if lines.blank?
|
|
|
|
|
|
|
|
lines.map.with_index do |line, index|
|
|
|
|
next unless line
|
|
|
|
|
|
|
|
[position + index, line]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|