From b4c39cd8c4dfcc40bdabc9db205bd347c2c0d826 Mon Sep 17 00:00:00 2001 From: mguetlein Date: Thu, 8 Aug 2013 16:40:54 +0200 Subject: error handling rewrite: making sure to pass backtrace --- lib/error.rb | 43 +++++++++++++++++++++++++++---------------- lib/overwrite.rb | 16 ++++++---------- lib/rest-client-wrapper.rb | 23 +++++++++++++++++------ lib/task.rb | 26 ++++---------------------- 4 files changed, 54 insertions(+), 54 deletions(-) (limited to 'lib') diff --git a/lib/error.rb b/lib/error.rb index 85ce35d..23e738d 100644 --- a/lib/error.rb +++ b/lib/error.rb @@ -2,8 +2,11 @@ require 'open4' # add additional fields to Exception class to format errors according to OT-API module OpenToxError - attr_accessor :http_code, :uri - def initialize message, uri=nil + attr_accessor :http_code, :uri, :error_cause + def initialize(message, uri=nil, cause=nil) + message.gsub!(/\A"|"\Z/, '') # remove quotes + @error_cause = cause ? OpenToxError::cut_backtrace(cause) : short_backtrace + super message #unless self.is_a? Errno::EAGAIN # avoid "Resource temporarily unavailable" errors @uri = uri.to_s.sub(%r{//.*:.*@},'//') # remove credentials from uri @@ -12,21 +15,29 @@ module OpenToxError subject = RDF::Node.new @rdf << [subject, RDF.type, RDF::OT.ErrorReport] @rdf << [subject, RDF::OT.actor, @uri] - @rdf << [subject, RDF::OT.message, message.sub(/^"/,'').sub(/"$/,'')] + @rdf << [subject, RDF::OT.message, message] @rdf << [subject, RDF::OT.statusCode, @http_code] @rdf << [subject, RDF::OT.errorCode, self.class.to_s] - @rdf << [subject, RDF::OT.errorCause, short_backtrace] + @rdf << [subject, RDF::OT.errorCause, @error_cause] $logger.error("\n"+self.to_turtle) #end end - + + def self.cut_backtrace(trace) + if trace.is_a?(Array) + cut_index = trace.find_index{|line| line.match(/sinatra|minitest/)} + cut_index ||= trace.size + cut_index -= 1 + cut_index = trace.size-1 if cut_index < 0 + trace[0..cut_index].join("\n") + else + trace + end + end + def short_backtrace backtrace = caller.collect{|line| line unless line =~ /#{File.dirname(__FILE__)}/}.compact - cut_index = backtrace.find_index{|line| line.match /sinatra|minitest/} - cut_index ||= backtrace.size - cut_index -= 1 - cut_index = backtrace.size-1 if cut_index < 0 - backtrace[0..cut_index].join("\n") + OpenToxError::cut_backtrace(backtrace) end RDF_FORMATS.each do |format| @@ -63,9 +74,9 @@ module OpenTox class Error < RuntimeError include OpenToxError - def initialize code, message, uri=nil + def initialize(code, message, uri=nil, cause=nil) @http_code = code - super message, uri + super message, uri, cause end end @@ -73,15 +84,15 @@ module OpenTox RestClientWrapper.known_errors.each do |error| # create error classes c = Class.new Error do - define_method :initialize do |message, uri=nil| - super error[:code], message, uri + define_method :initialize do |message, uri=nil, cause=nil| + super error[:code], message, uri, cause end end OpenTox.const_set error[:class],c # define global methods for raising errors, eg. bad_request_error - Object.send(:define_method, error[:method]) do |message,uri=nil| - raise c.new(message.inspect, uri) + Object.send(:define_method, error[:method]) do |message,uri=nil,cause=nil| + raise c.new(message.inspect, uri, cause) end end diff --git a/lib/overwrite.rb b/lib/overwrite.rb index ff43347..0830490 100644 --- a/lib/overwrite.rb +++ b/lib/overwrite.rb @@ -155,16 +155,12 @@ module Kernel t = OpenTox::Task.new uri t.wait unless t.completed? - begin # handle known (i.e. OpenTox) errors - error = OpenTox::RestClientWrapper.known_errors.select{|error| error[:code] == t.code}.first - error ? error_method = error[:method] : error_method = :internal_server_error - report = t.error_report - report ? error_message = report[RDF::OT.message] : error_message = $!.message - Object.send(error_method,error_message,t.uri) - rescue - internal_server_error "#{$!.message}", t.uri - #internal_server_error "#{$!.message}\n#{$!.backtrace}", t.uri - end + error = OpenTox::RestClientWrapper.known_errors.select{|error| error[:code] == t.code}.first + error_method = error ? error[:method] : :internal_server_error + report = t.error_report + error_message = report ? report[RDF::OT.message] : $!.message + error_cause = report ? report[RDF::OT.errorCause] : nil + Object.send(error_method,error_message,t.uri,error_cause) end uri = t.resultURI end diff --git a/lib/rest-client-wrapper.rb b/lib/rest-client-wrapper.rb index 134dd32..3ed41ad 100644 --- a/lib/rest-client-wrapper.rb +++ b/lib/rest-client-wrapper.rb @@ -53,13 +53,24 @@ module OpenTox if [301, 302, 307].include? response.code and request.method == :get response.follow_redirection(request, result) elsif response.code >= 400 and !URI.task?(uri) - message = response.to_s - parameters = request.args - parameters[:headers][:subjectid] = "REMOVED" if parameters[:headers] and parameters[:headers][:subjectid] - parameters[:url] = parameters[:url].gsub(/(http|https|)\:\/\/[a-zA-Z0-9\-]+\:[a-zA-Z0-9]+\@/, "REMOVED@") if parameters[:url] - message += "\nREST parameters:\n#{parameters.inspect}" + #TODO add parameters to error-report + #parameters = request.args + #parameters[:headers][:subjectid] = "REMOVED" if parameters[:headers] and parameters[:headers][:subjectid] + #parameters[:url] = parameters[:url].gsub(/(http|https|)\:\/\/[a-zA-Z0-9\-]+\:[a-zA-Z0-9]+\@/, "REMOVED@") if parameters[:url] + #message += "\nREST parameters:\n#{parameters.inspect}" error = known_errors.collect{|e| e if e[:code] == response.code}.compact.first - Object.method(error[:method]).call message, uri # call error method + begin # errors are returned as error reports in turtle, try to parse + content = {} + RDF::Reader.for(:turtle).new(response.to_s) do |reader| + reader.each_triple{|triple| content[triple[1]] = triple[2]} + end + msg = content[RDF::OT.message].to_s + cause = content[RDF::OT.errorCause].to_s + rescue # parsing error failed, use complete content as message + msg = response.to_s + cause = nil + end + Object.method(error[:method]).call msg, uri, cause # call error method else response end diff --git a/lib/task.rb b/lib/task.rb index 07efc0f..6d6a3a7 100644 --- a/lib/task.rb +++ b/lib/task.rb @@ -21,28 +21,10 @@ module OpenTox pid = fork do begin task.completed yield - rescue - if $!.respond_to? :to_ntriples - RestClientWrapper.put(File.join(task.uri,'Error'),{:errorReport => $!.to_ntriples},{:content_type => 'text/plain'}) - else - cut_index = $!.backtrace.find_index{|line| line.match /gems\/sinatra/} - cut_index = -1 unless cut_index - @rdf = RDF::Graph.new - subject = RDF::Node.new - @rdf << [subject, RDF.type, RDF::OT.ErrorReport] - @rdf << [subject, RDF::OT.message, $!.message] - @rdf << [subject, RDF::OT.errorCode, $!.class.to_s] - @rdf << [subject, RDF::OT.errorCause, $!.backtrace[0..cut_index].join("\n")] - prefixes = {:rdf => "http://www.w3.org/1999/02/22-rdf-syntax-ns#", :ot => RDF::OT.to_s} - turtle = RDF::Turtle::Writer.for(:turtle).buffer(:prefixes => prefixes) do |writer| - @rdf.each{|statement| writer << statement} - end - $logger.error turtle - nt = RDF::Writer.for(:ntriples).buffer do |writer| - @rdf.each{|statement| writer << statement} - end - RestClientWrapper.put(File.join(task.uri,'Error'),{:errorReport => nt},{:content_type => 'text/plain'}) - end + rescue => e + # wrap non-opentox-errors first + e = OpenTox::Error.new(500,e.message,nil,e.backtrace) unless e.is_a?(OpenTox::Error) + RestClientWrapper.put(File.join(task.uri,'Error'),{:errorReport => e.to_ntriples},{:content_type => 'text/plain'}) task.kill end end -- cgit v1.2.3