Skip to content
This repository has been archived by the owner on Jan 12, 2024. It is now read-only.

Bug: JRuby stacktraces with Java content can fail the reporting #47

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
15 changes: 14 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
language: ruby
cache: bundler
env:
- CI=true
global:
- CI=true
- JRUBY_OPTS=--debug
before_install:
- gem install bundler
rvm:
Expand All @@ -11,6 +13,7 @@ rvm:
- 2.2.3
- 2.3.3
- 2.4.0
- jruby-9.1.11.0
gemfile:
- gemfiles/Gemfile.rails-3.2.x
- gemfiles/Gemfile.rails-4.0.x
Expand All @@ -21,6 +24,8 @@ matrix:
include:
- rvm: 2.3.3
gemfile: gemfiles/Gemfile.rails-HEAD
- rvm: jruby-9.1.11.0
gemfile: gemfiles/Gemfile.rails-HEAD

exclude:
- rvm: 2.0.0
Expand All @@ -35,6 +40,14 @@ matrix:
gemfile: gemfiles/Gemfile.rails-4.1.x
- rvm: 2.4.0
gemfile: gemfiles/Gemfile.rails-4.2.x
- rvm: jruby-9.1.11.0
gemfile: gemfiles/Gemfile.rails-3.2.x
- rvm: jruby-9.1.11.0
gemfile: gemfiles/Gemfile.rails-4.0.x
- rvm: jruby-9.1.11.0
gemfile: gemfiles/Gemfile.rails-4.1.x
- rvm: jruby-9.1.11.0
gemfile: gemfiles/Gemfile.rails-4.2.x

notifications:
email: false
Expand Down
26 changes: 25 additions & 1 deletion lib/opbeat/error_message/stacktrace.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,19 @@ class Frame < Struct.new(:filename, :lineno, :abs_path, :function, :vars,

BACKTRACE_REGEX = /^(.+?):(\d+)(?::in `(.+?)')?$/.freeze

# regexp (optional leading X: on windows, or JRuby9000 class-prefix)
RUBY_INPUT_FORMAT = /
^ \s* (?: [a-zA-Z]: | uri:classloader: )? ([^:]+ | <.*>):
(\d+)
(?: :in \s `([^']+)')?$
/x

# org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:170)
JAVA_INPUT_FORMAT = /^(.+)\.([^\.]+)\(([^\:]+)\:(\d+)\)$/

class << self
def from_line config, line
_, abs_path, lineno, function = line.match(BACKTRACE_REGEX).to_a
abs_path, lineno, function, _module_name = parse_line(line)
lineno = lineno.to_i
filename = strip_load_path(abs_path)

Expand All @@ -44,7 +54,21 @@ def from_line config, line

private

def parse_line(unparsed_line)
ruby_match = unparsed_line.match(RUBY_INPUT_FORMAT)
if ruby_match
_, file, number, method = ruby_match.to_a
file.sub!(/\.class$/, '.rb')
module_name = nil
else
java_match = unparsed_line.match(JAVA_INPUT_FORMAT)
_, module_name, method, file, number = java_match.to_a
end
[file, number, method, module_name]
end

def strip_load_path path
return '' unless path
prefix = $:
.map(&:to_s)
.select { |s| path.start_with?(s) }
Expand Down
1 change: 1 addition & 0 deletions opbeat.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Gem::Specification.new do |gem|
gem.summary = "The official Opbeat Ruby client library"
gem.homepage = "https://github.com/opbeat/opbeat-ruby"
gem.license = "BSD-3-Clause"
gem.required_ruby_version = ">= 2.0.0"

gem.files = `git ls-files -z`.split("\x0")
gem.require_paths = ["lib"]
Expand Down
64 changes: 42 additions & 22 deletions spec/opbeat/error_message/stacktrace_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,58 @@

module Opbeat
RSpec.describe ErrorMessage::Stacktrace do

def real_exception
1 / 0
rescue => e
e
end

def java_exception
require 'java'
java_import 'java.lang.ClassNotFoundException'
java.lang::Class.forName('foo.Bar')
rescue ClassNotFoundException => e
e
end

let(:config) { Configuration.new }
let(:exception) { real_exception }

describe ".from" do
it "initializes from an exception" do
stacktrace = ErrorMessage::Stacktrace.from config, exception
expect(stacktrace.frames).to_not be_empty

# so meta
last_frame = stacktrace.frames.last
expect(last_frame.filename).to eq "opbeat/error_message/stacktrace_spec.rb"
expect(last_frame.lineno).to be 7
expect(last_frame.abs_path).to_not be_nil
expect(last_frame.function).to eq "/"
expect(last_frame.vars).to be_nil

expect(last_frame.pre_context.last).to match(/def real_exception/)
expect(last_frame.context_line).to match(/1 \/ 0/)
expect(last_frame.post_context.first).to match(/rescue/)
describe '.from' do
context 'when on JRuby', if: RSpec::Support::Ruby.jruby? do
it 'initializes from a Java exception' do
stacktrace = ErrorMessage::Stacktrace.from config, java_exception
expect(stacktrace.frames).to_not be_empty
end

it 'initializes from an exception' do
stacktrace = ErrorMessage::Stacktrace.from config, exception
expect(stacktrace.frames).to_not be_empty
end
end

context "when context lines are off" do
context 'when on MRI', unless: RSpec::Support::Ruby.jruby? do
it 'initializes from an exception' do
stacktrace = ErrorMessage::Stacktrace.from config, exception
expect(stacktrace.frames).to_not be_empty

# so meta
last_frame = stacktrace.frames.last
expect(last_frame.filename).to eq 'opbeat/error_message/stacktrace_spec.rb'
expect(last_frame.lineno).to be 6
expect(last_frame.abs_path).to_not be_nil
expect(last_frame.function).to eq '/'
expect(last_frame.vars).to be_nil

expect(last_frame.pre_context.last).to match(/def real_exception/)
expect(last_frame.context_line).to match(/1 \/ 0/)
expect(last_frame.post_context.first).to match(/rescue/)
end
end

context 'when context lines are off' do
let(:config) { Configuration.new context_lines: nil }
it "initializes too" do
it 'initializes too' do
stacktrace = ErrorMessage::Stacktrace.from config, exception
expect(stacktrace.frames).to_not be_empty

Expand All @@ -44,13 +65,12 @@ def real_exception
end
end

describe "#to_h" do
it "is a hash" do
describe '#to_h' do
it 'is a hash' do
hsh = ErrorMessage::Stacktrace.from(config, exception).to_h
expect(hsh).to be_a Hash
expect(hsh.keys).to eq [:frames]
end
end

end
end
2 changes: 1 addition & 1 deletion spec/opbeat/injections/sequel_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
require 'sequel'

module Opbeat
RSpec.describe Injections::Sequel do
RSpec.describe Injections::Sequel, unless: RSpec::Support::Ruby.jruby? do

it "is installed" do
reg = Opbeat::Injections.installed['Sequel']
Expand Down