class Sentry::Backtrace
@api private
def self.line_cache
def self.line_cache @line_cache ||= Concurrent::Map.new end
def self.parse(backtrace, project_root, app_dirs_pattern, &backtrace_cleanup_callback)
def self.parse(backtrace, project_root, app_dirs_pattern, &backtrace_cleanup_callback) ruby_lines = backtrace.is_a?(Array) ? backtrace : backtrace.split(/\n\s*/) ruby_lines = backtrace_cleanup_callback.call(ruby_lines) if backtrace_cleanup_callback in_app_pattern ||= begin Regexp.new("^(#{project_root}/)?#{app_dirs_pattern}") end lines = ruby_lines.to_a.map do |unparsed_line| Line.parse(unparsed_line, in_app_pattern) end new(lines) end
def self.source_location(&backtrace_cleaner)
def self.source_location(&backtrace_cleaner) Thread.each_caller_location do |location| frame_key = [location.absolute_path, location.lineno] cached_value = line_cache[frame_key] next if cached_value == :skip if cached_value return cached_value else if cleaned_frame = backtrace_cleaner.(location) line = Line.from_source_location(location) line_cache[frame_key] = line return line else line_cache[frame_key] = :skip next end end end end
def self.source_location(*)
to the slower implementation and adds potentially big overhead to the
Since Sentry is mostly used in production, we don't want to fallback
def self.source_location(*) nil end
def ==(other)
def ==(other) if other.respond_to?(:lines) lines == other.lines else false end end
def initialize(lines)
def initialize(lines) @lines = lines end
def inspect
def inspect "<Backtrace: " + lines.map(&:inspect).join(", ") + ">" end
def to_s
def to_s content = [] lines.each do |line| content << line end content.join("\n") end