diff --git a/lib/raven/backtrace.rb b/lib/raven/backtrace.rb index f0aad7231..c741926e1 100644 --- a/lib/raven/backtrace.rb +++ b/lib/raven/backtrace.rb @@ -9,7 +9,10 @@ class Backtrace class Line # regexp (optionnally allowing leading X: for windows support) - INPUT_FORMAT = %r{^((?:[a-zA-Z]:)?[^:]+|<.*>):(\d+)(?::in `([^']+)')?$}.freeze + RUBY_INPUT_FORMAT = %r{^((?:[a-zA-Z]:)?[^:]+|<.*>):(\d+)(?::in `([^']+)')?$}.freeze + + # org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:170) + JAVA_INPUT_FORMAT = %r{^(.+)\.([^\.]+)\(([^\:]+)\:(\d+)\)$}.freeze APP_DIRS_PATTERN = /(bin|app|config|lib|test)/ @@ -22,16 +25,27 @@ class Line # The method of the line (such as index) attr_reader :method + # The module name (JRuby) + attr_reader :module_name + # Parses a single line of a given backtrace # @param [String] unparsed_line The raw line from +caller+ or some backtrace # @return [Line] The parsed backtrace line def self.parse(unparsed_line) - _, file, number, method = unparsed_line.match(INPUT_FORMAT).to_a - new(file, number, method) + ruby_match = unparsed_line.match(RUBY_INPUT_FORMAT) + if ruby_match + _, file, number, method = ruby_match.to_a + module_name = nil + else + java_match = unparsed_line.match(JAVA_INPUT_FORMAT) + _, module_name, method, file, number = java_match.to_a + end + new(file, number, method, module_name) end - def initialize(file, number, method) + def initialize(file, number, method, module_name) self.file = file + self.module_name = module_name self.number = number.to_i self.method = method end @@ -66,7 +80,7 @@ def inspect private - attr_writer :file, :number, :method + attr_writer :file, :number, :method, :module_name end # holder for an Array of Backtrace::Line instances diff --git a/lib/raven/event.rb b/lib/raven/event.rb index 20b17f7b6..ed27850fa 100644 --- a/lib/raven/event.rb +++ b/lib/raven/event.rb @@ -186,10 +186,11 @@ def self.stacktrace_interface_from(int, evt, backtrace) backtrace = Backtrace.parse(backtrace) int.frames = backtrace.lines.reverse.map do |line| StacktraceInterface::Frame.new.tap do |frame| - frame.abs_path = line.file - frame.function = line.method + frame.abs_path = line.file if line.file + frame.function = line.method if line.method frame.lineno = line.number frame.in_app = line.in_app + frame.module = line.module_name if line.module_name if evt.configuration[:context_lines] && frame.abs_path frame.pre_context, frame.context_line, frame.post_context = \ diff --git a/lib/raven/interfaces/stack_trace.rb b/lib/raven/interfaces/stack_trace.rb index 084661c43..e0c37fab8 100644 --- a/lib/raven/interfaces/stack_trace.rb +++ b/lib/raven/interfaces/stack_trace.rb @@ -25,6 +25,7 @@ class Frame < Interface attr_accessor :pre_context attr_accessor :post_context attr_accessor :context_line + attr_accessor :module attr_accessor :lineno attr_accessor :in_app diff --git a/spec/raven/event_spec.rb b/spec/raven/event_spec.rb index 5e9bd4e15..7bedfb660 100644 --- a/spec/raven/event_spec.rb +++ b/spec/raven/event_spec.rb @@ -467,6 +467,23 @@ class SubExc < BaseExc; end end end + if RUBY_PLATFORM == "java" + context 'when running under jRuby' do + let(:exception) do + begin + raise java.lang.OutOfMemoryError.new("A Java error") + rescue Exception => e + return e + end + end + + it 'should have a backtrace' do + frames = hash[:exception][:values][0][:stacktrace][:frames] + expect(frames.length).not_to eq(0) + end + end + end + context 'when the exception has a backtrace' do let(:exception) do e = Exception.new(message)