Skip to content

Commit

Permalink
Merge pull request #117 from MindscapeHQ/background-sending
Browse files Browse the repository at this point in the history
Background sending of exceptions so web request thread is not blocked
  • Loading branch information
UberMouse authored May 4, 2017
2 parents 797ef7e + 1ea285f commit d6967fd
Show file tree
Hide file tree
Showing 9 changed files with 67 additions and 28 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## 2.2.0

Features
- Opt in support for sending exceptions in a background thread to not block web request thread during IO ([#117](https://github.com/MindscapeHQ/raygun4ruby/pull/117))

Bugfixes
- Don't attempt to read raw data during GET requests or if rack.input buffer is empty

## 2.1.0

Features
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ You can then test your Raygun integration by running:

You should see an "ItWorksException" appear in your Raygun dashboard. You're ready to zap those errors!

NB: Raygun4Ruby currently requires Ruby >= 1.9
NB: Raygun4Ruby currently requires Ruby >= 2.0

Note that the generator will create a file in `config/initializers` called "raygun.rb". If you need to do any further configuration or customization of Raygun, that's the place to do it!

Expand Down
55 changes: 37 additions & 18 deletions lib/raygun.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
require "concurrent"
require "httparty"
require "logger"
require "json"
Expand Down Expand Up @@ -54,25 +55,10 @@ def configured?
end

def track_exception(exception_instance, env = {}, user = nil, retry_count = 1)
if should_report?(exception_instance)
log("[Raygun] Tracking Exception...")
Client.new.track_exception(exception_instance, env, user)
end
rescue Exception => e
if configuration.failsafe_logger
failsafe_log("Problem reporting exception to Raygun: #{e.class}: #{e.message}\n\n#{e.backtrace.join("\n")}")
end

if retry_count > 0
new_exception = e.exception("raygun4ruby encountered an exception processing your exception")
new_exception.set_backtrace(e.backtrace)

env[:custom_data] ||= {}
env[:custom_data].merge!(original_stacktrace: exception_instance.backtrace)

track_exception(new_exception, env, user, retry_count - 1)
if configuration.send_in_background
track_exception_async(exception_instance, env, user, retry_count)
else
raise e
track_exception_sync(exception_instance, env, user, retry_count)
end
end

Expand Down Expand Up @@ -122,6 +108,39 @@ def deprecation_warning(message)

private

def track_exception_async(*args)
future = Concurrent::Future.execute { track_exception_sync(*args) }
future.add_observer(lambda do |_, value, reason|
if value == nil || value.response.code != "202"
log("[Raygun] unexpected response from Raygun, could indicate error: #{value.inspect}")
end
end, :call)
end

def track_exception_sync(exception_instance, env, user, retry_count)
if should_report?(exception_instance)
log("[Raygun] Tracking Exception...")
Client.new.track_exception(exception_instance, env, user)
end
rescue Exception => e
if configuration.failsafe_logger
failsafe_log("Problem reporting exception to Raygun: #{e.class}: #{e.message}\n\n#{e.backtrace.join("\n")}")
end

if retry_count > 0
new_exception = e.exception("raygun4ruby encountered an exception processing your exception")
new_exception.set_backtrace(e.backtrace)

env[:custom_data] ||= {}
env[:custom_data].merge!(original_stacktrace: exception_instance.backtrace)

track_exception(new_exception, env, user, retry_count - 1)
else
raise e
end
end


def print_api_key_warning
$stderr.puts(NO_API_KEY_MESSAGE)
end
Expand Down
5 changes: 4 additions & 1 deletion lib/raygun/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,11 @@ def raw_data(rack_env)

request = Rack::Request.new(rack_env)
input = rack_env['rack.input']
return if request.get?

if input && !request.form_data?
# If size is 0 the buffer is at best empty and at worst
# something like the Puma::NullIO buffer which is missing methods
if input && input.size && !request.form_data?
current_position = input.pos
input.rewind

Expand Down
10 changes: 7 additions & 3 deletions lib/raygun/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ def self.proc_config_option(name)
# form submissions and will not be filtered by the blacklist
config_option :record_raw_data

# Should the exceptions to Raygun be sent asynchronously?
config_option :send_in_background

# Exception classes to ignore by default
IGNORE_DEFAULT = ['ActiveRecord::RecordNotFound',
'ActionController::RoutingError',
Expand Down Expand Up @@ -111,7 +114,7 @@ def initialize
@config_values = {}

# set default attribute values
@defaults = OpenStruct.new({
@defaults = OpenStruct.new(
ignore: IGNORE_DEFAULT,
custom_data: {},
tags: [],
Expand All @@ -125,8 +128,9 @@ def initialize
debug: false,
api_url: 'https://api.raygun.io/',
breadcrumb_level: :info,
record_raw_data: false
})
record_raw_data: false,
send_in_background: false
)
end

def [](key)
Expand Down
2 changes: 1 addition & 1 deletion lib/raygun/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module Raygun
VERSION = "2.1.0"
VERSION = "2.2.0"
end
1 change: 1 addition & 0 deletions raygun4ruby.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Gem::Specification.new do |spec|
spec.add_runtime_dependency "httparty", "> 0.13.7"
spec.add_runtime_dependency "json"
spec.add_runtime_dependency "rack"
spec.add_runtime_dependency "concurrent-ruby"

spec.add_development_dependency "bundler", ">= 1.1"
spec.add_development_dependency "rake", "0.9.6"
Expand Down
8 changes: 4 additions & 4 deletions test/unit/client_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ def test_getting_request_information
queryString: { "a" => "b", "c" => "4945438" },
headers: { "Version"=>"HTTP/1.1", "Host"=>"localhost:3000", "Cookie"=>"cookieval" },
form: {},
rawData: {}
rawData: nil
}

assert_equal expected_hash, @client.send(:request_information, env_hash)
Expand Down Expand Up @@ -550,7 +550,7 @@ def test_filter_payload_with_whitelist_default_request_get
queryString: { "a" => "b", "c" => "4945438" },
headers: { "Version"=>"HTTP/1.1", "Host"=>"localhost:3000", "Cookie"=>"cookieval" },
form: {},
rawData: {}
rawData: nil
}

details = @client.send(:build_payload_hash, test_exception, env_hash)[:details]
Expand All @@ -574,7 +574,7 @@ def test_filter_payload_with_whitelist_default_request_get_except_querystring
queryString: "[FILTERED]",
headers: { "Version"=>"HTTP/1.1", "Host"=>"localhost:3000", "Cookie"=>"cookieval" },
form: {},
rawData: {}
rawData: nil
}

details = @client.send(:build_payload_hash, test_exception, sample_env_hash)[:details]
Expand All @@ -597,7 +597,7 @@ def test_filter_payload_with_whitelist_being_false_does_not_filter_query_string
queryString: { "a" => "b", "c" => "4945438" },
headers: { "Version"=>"HTTP/1.1", "Host"=>"localhost:3000", "Cookie"=>"cookieval" },
form: {},
rawData: {}
rawData: nil
}

details = @client.send(:build_payload_hash, test_exception, env_hash)[:details]
Expand Down
4 changes: 4 additions & 0 deletions test/unit/configuration_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -159,4 +159,8 @@ def test_breadcrumb_level_default
def test_record_raw_data_default
assert_equal false, Raygun.configuration.record_raw_data
end

def test_send_in_background_default
assert_equal false, Raygun.configuration.send_in_background
end
end

0 comments on commit d6967fd

Please sign in to comment.