mirror of
https://github.com/rubyjs/therubyracer
synced 2023-03-27 23:21:42 -04:00
track causes of exceptions
This commit is contained in:
parent
f34cc5247a
commit
744baef3a3
2 changed files with 58 additions and 30 deletions
|
@ -1,23 +1,59 @@
|
||||||
module V8
|
module V8
|
||||||
class Error < StandardError
|
|
||||||
|
|
||||||
# capture 99 stack frames on exception with normal details.
|
# capture 99 stack frames on exception with normal details.
|
||||||
# You can adjust these values for performance or turn of stack capture entirely
|
# You can adjust these values for performance or turn of stack capture entirely
|
||||||
V8::C::V8::SetCaptureStackTraceForUncaughtExceptions(true, 99, V8::C::StackTrace::kOverview)
|
V8::C::V8::SetCaptureStackTraceForUncaughtExceptions(true, 99, V8::C::StackTrace::kOverview)
|
||||||
|
class Error < StandardError
|
||||||
|
include Enumerable
|
||||||
|
attr_reader :value, :cause, :javascript_backtrace
|
||||||
|
|
||||||
attr_reader :value
|
def initialize(message, value, javascript_backtrace, cause = nil)
|
||||||
def initialize(message, value)
|
|
||||||
super(message)
|
super(message)
|
||||||
@value = value
|
@value = value
|
||||||
|
@cause = cause
|
||||||
|
@javascript_backtrace = javascript_backtrace
|
||||||
|
end
|
||||||
|
|
||||||
|
def causes
|
||||||
|
[].tap do |causes|
|
||||||
|
current = self
|
||||||
|
until current.nil? do
|
||||||
|
causes.push current
|
||||||
|
current = current.respond_to?(:cause) ? current.cause : nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def root_cause
|
||||||
|
causes.last
|
||||||
|
end
|
||||||
|
|
||||||
|
def in_javascript?
|
||||||
|
causes.last.is_a? self.class
|
||||||
|
end
|
||||||
|
|
||||||
|
def in_ruby?
|
||||||
|
!in_javascript?
|
||||||
|
end
|
||||||
|
|
||||||
|
def multilingual_backtrace
|
||||||
|
causes.reduce(:backtrace => [], :ruby => -1, :javascript => -1) { |accumulator, cause|
|
||||||
|
ruby_frames = cause.backtrace[0..accumulator[:ruby]]
|
||||||
|
accumulator[:backtrace].unshift *ruby_frames
|
||||||
|
accumulator[:ruby] -= ruby_frames.length
|
||||||
|
if cause.respond_to?(:javascript_backtrace)
|
||||||
|
javascript_frames = cause.javascript_frames[0, accumulator[:javascript]].map(&:to_s)
|
||||||
|
accumulator[:backtrace].unshift *javascript_frames
|
||||||
|
accumulator[:javascript] -= javascript_frames.length
|
||||||
|
end
|
||||||
|
}[:backtrace]
|
||||||
end
|
end
|
||||||
|
|
||||||
module Try
|
module Try
|
||||||
def try
|
def try
|
||||||
context = V8::Context.current
|
|
||||||
V8::C::TryCatch() do |trycatch|
|
V8::C::TryCatch() do |trycatch|
|
||||||
result = yield
|
result = yield
|
||||||
if trycatch.HasCaught()
|
if trycatch.HasCaught()
|
||||||
V8::Error(trycatch.Exception())
|
raise V8::Error(trycatch)
|
||||||
else
|
else
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
@ -28,39 +64,33 @@ module V8
|
||||||
module Protect
|
module Protect
|
||||||
def protect
|
def protect
|
||||||
yield
|
yield
|
||||||
rescue Football => e
|
|
||||||
e.kickoff!
|
|
||||||
rescue Exception => e
|
rescue Exception => e
|
||||||
e.extend Football
|
error = V8::C::Exception::Error(e.message)
|
||||||
e.kickoff!
|
error.SetHiddenValue("rr::Cause", V8::C::External::New(e))
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
module Football
|
|
||||||
def kickoff!
|
|
||||||
error = V8::C::Exception::Error(message)
|
|
||||||
error.SetHiddenValue("rr::Football", V8::C::External::New(self))
|
|
||||||
V8::C::ThrowException(error)
|
V8::C::ThrowException(error)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.Error(exception)
|
def self.Error(trycatch)
|
||||||
|
exception = trycatch.Exception()
|
||||||
value = exception.to_ruby
|
value = exception.to_ruby
|
||||||
if !exception.kind_of?(V8::C::Value)
|
cause = nil
|
||||||
raise V8::Error.new(exception.to_s, value)
|
message = if !exception.kind_of?(V8::C::Value)
|
||||||
|
exception.to_s
|
||||||
elsif exception.IsNativeError()
|
elsif exception.IsNativeError()
|
||||||
if football = exception.GetHiddenValue("rr::Football")
|
if cause = exception.GetHiddenValue("rr::Cause")
|
||||||
raise football.Value()
|
cause = cause.Value()
|
||||||
else
|
|
||||||
raise V8::Error.new(exception.Get("message").to_ruby, value)
|
|
||||||
end
|
end
|
||||||
|
exception.Get("message").to_ruby
|
||||||
elsif exception.IsObject()
|
elsif exception.IsObject()
|
||||||
raise V8::Error.new(value['message'] || value.to_s, value)
|
value['message'] || value.to_s
|
||||||
else
|
else
|
||||||
raise V8::Error.new(exception.ToString().to_ruby, value)
|
value.to_s
|
||||||
end
|
end
|
||||||
|
javascript_backtrace = V8::StackTrace.new(trycatch.Message().GetStackTrace())
|
||||||
|
V8::Error.new(message, value, javascript_backtrace, cause)
|
||||||
end
|
end
|
||||||
const_set :JSError, Error
|
const_set :JSError, Error
|
||||||
end
|
end
|
|
@ -39,16 +39,14 @@ describe V8::Error do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "has a reference to the root javascript cause" do
|
it "has a reference to the root javascript cause" do
|
||||||
pending
|
|
||||||
throw!('"I am a String"') do |e|
|
throw!('"I am a String"') do |e|
|
||||||
e.should_not be_in_ruby
|
e.should_not be_in_ruby
|
||||||
e.should be_in_javascript
|
e.should be_in_javascript
|
||||||
e.value.should == "I am a String"
|
e.value['message'].should == "I am a String"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it "has a reference to the root ruby cause if one exists" do
|
it "has a reference to the root ruby cause if one exists" do
|
||||||
pending
|
|
||||||
StandardError.new("BOOM!").tap do |bomb|
|
StandardError.new("BOOM!").tap do |bomb|
|
||||||
@cxt['boom'] = lambda do
|
@cxt['boom'] = lambda do
|
||||||
raise bomb
|
raise bomb
|
||||||
|
@ -58,7 +56,7 @@ describe V8::Error do
|
||||||
}.should(raise_error do |raised|
|
}.should(raise_error do |raised|
|
||||||
raised.should be_in_ruby
|
raised.should be_in_ruby
|
||||||
raised.should_not be_in_javascript
|
raised.should_not be_in_javascript
|
||||||
raised.value.should be(bomb)
|
raised.root_cause.should be(bomb)
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Reference in a new issue