require 'rollbar/item/frame' module Rollbar class Item class Backtrace attr_reader :exception attr_reader :message attr_reader :extra attr_reader :configuration attr_reader :files private :files def initialize(exception, options = {}) @exception = exception @message = options[:message] @extra = options[:extra] @configuration = options[:configuration] @files = {} end def to_h traces = trace_chain traces[0][:exception][:description] = message if message traces[0][:extra] = extra if extra if traces.size > 1 { :trace_chain => traces } elsif traces.size == 1 { :trace => traces[0] } end end alias_method :build, :to_h def get_file_lines(filename) files[filename] ||= read_file(filename) end private def read_file(filename) return unless File.exist?(filename) File.read(filename).split("\n") rescue nil end def trace_chain traces = [trace_data(exception)] visited = [exception] current_exception = exception while current_exception.respond_to?(:cause) && (cause = current_exception.cause) && cause.is_a?(Exception) && !visited.include?(cause) traces << trace_data(cause) visited << cause current_exception = cause end traces end def trace_data(current_exception) { :frames => map_frames(current_exception), :exception => { :class => current_exception.class.name, :message => current_exception.message } } end def map_frames(current_exception) exception_backtrace(current_exception).reverse.map do |frame| Rollbar::Item::Frame.new(self, frame, :configuration => configuration).to_h end end # Returns the backtrace to be sent to our API. There are 3 options: # # 1. The exception received has a backtrace, then that backtrace is returned. # 2. configuration.populate_empty_backtraces is disabled, we return [] here # 3. The user has configuration.populate_empty_backtraces is enabled, then: # # We want to send the caller as backtrace, but the first lines of that array # are those from the user's Rollbar.error line until this method. We want # to remove those lines. def exception_backtrace(current_exception) return current_exception.backtrace if current_exception.backtrace.respond_to?(:map) return [] unless configuration.populate_empty_backtraces caller_backtrace = caller caller_backtrace.shift while caller_backtrace[0].include?(rollbar_lib_gem_dir) caller_backtrace end def rollbar_lib_gem_dir Gem::Specification.find_by_name('rollbar').gem_dir + '/lib' end end end end