exceptional 2.0.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/bin/exceptional +6 -6
- data/exceptional.gemspec +3 -3
- data/init.rb +17 -2
- data/install.rb +3 -3
- data/lib/exceptional/catcher.rb +9 -2
- data/lib/exceptional/config.rb +9 -12
- data/lib/exceptional/controller_exception_data.rb +60 -0
- data/lib/exceptional/exception_data.rb +13 -50
- data/lib/exceptional/integration/rails.rb +3 -2
- data/lib/exceptional/integration/tester.rb +3 -3
- data/lib/exceptional/remote.rb +2 -1
- data/lib/exceptional.rb +30 -4
- data/spec/exceptional/catcher_spec.rb +2 -2
- data/spec/exceptional/config_spec.rb +7 -7
- data/spec/exceptional/exception_data_spec.rb +22 -12
- data/spec/exceptional_rescue_spec.rb +53 -6
- data/spec/rails_integration_spec.rb +24 -7
- data/spec/spec_helper.rb +2 -1
- data/tasks/exceptional_tasks.rake +1 -1
- metadata +7 -16
- data/lib/exceptional/integration/rack.rb +0 -14
data/bin/exceptional
CHANGED
@@ -7,9 +7,9 @@ command = args.shift.strip rescue 'help'
|
|
7
7
|
case command
|
8
8
|
when 'help'
|
9
9
|
puts <<USAGE
|
10
|
-
help #
|
11
|
-
test #
|
12
|
-
install <api_key> #
|
10
|
+
help # Show this usage.
|
11
|
+
test # Send a test exception to Exceptional.
|
12
|
+
install <api_key> # Create config/exceptional.yml with your api_key. Overrites existing one.
|
13
13
|
USAGE
|
14
14
|
when 'test'
|
15
15
|
puts "Loading Rails environment."
|
@@ -22,15 +22,15 @@ USAGE
|
|
22
22
|
when 'install'
|
23
23
|
api_key = args[0]
|
24
24
|
if (api_key.nil?)
|
25
|
-
puts '
|
25
|
+
puts 'Missing required paramater <api-key>. Check your app configuration at http://getexceptional.com.'
|
26
26
|
else
|
27
27
|
unless File.file?('config/environment.rb')
|
28
|
-
puts "Run this command from the root of your rails application"
|
28
|
+
puts "Run this command from the root of your rails application."
|
29
29
|
else
|
30
30
|
config_file = File.open('config/exceptional.yml', 'w')
|
31
31
|
config_file.puts("api-key: #{api_key}\n")
|
32
32
|
config_file.close
|
33
|
-
puts "Config file written as config/exceptional.yml"
|
33
|
+
puts "Config file written as config/exceptional.yml."
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|
data/exceptional.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
Gem::Specification.new do |s|
|
3
3
|
s.name = %q{exceptional}
|
4
|
-
s.version = "2.0.
|
4
|
+
s.version = "2.0.1"
|
5
5
|
s.authors = ["Contrast"]
|
6
6
|
s.summary = %q{Exceptional is the core Ruby library for communicating with http://getexceptional.com (hosted error tracking service)}
|
7
7
|
s.description = %q{Exceptional is the core Ruby library for communicating with http://getexceptional.com (hosted error tracking service). Use it to find out about errors that happen in your live app. It captures lots of helpful information to help you fix the errors.}
|
@@ -11,5 +11,5 @@ Gem::Specification.new do |s|
|
|
11
11
|
s.require_paths = ["lib"]
|
12
12
|
s.executables << 'exceptional'
|
13
13
|
s.rubyforge_project = %q{exceptional}
|
14
|
-
s.
|
15
|
-
end
|
14
|
+
s.requirements << "json_pure, json-jruby or json gem required"
|
15
|
+
end
|
data/init.rb
CHANGED
@@ -1,12 +1,27 @@
|
|
1
1
|
require 'exceptional'
|
2
2
|
|
3
|
+
unless Object.const_defined?(:JSON)
|
4
|
+
begin
|
5
|
+
require 'json'
|
6
|
+
rescue LoadError
|
7
|
+
begin
|
8
|
+
require 'json-ruby'
|
9
|
+
rescue LoadError
|
10
|
+
require 'json_pure'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
unless Object.const_defined?(:JSON)
|
15
|
+
raise "Could not load json gem; make sure you install one of json_pure, json-ruby, or the C-based json gem."
|
16
|
+
end
|
17
|
+
|
3
18
|
# If old plugin still installed then we don't want to install this one.
|
4
19
|
# In production environments we should continue to work as before, but in development/test we should
|
5
20
|
# advise how to correct the problem and exit
|
6
|
-
if defined?(Exceptional::VERSION::STRING) && %w(development test).include?(RAILS_ENV)
|
21
|
+
if (defined?(Exceptional::VERSION::STRING) rescue nil) && %w(development test).include?(RAILS_ENV)
|
7
22
|
message = %Q(
|
8
23
|
***********************************************************************
|
9
|
-
You seem to still have an old version of the
|
24
|
+
You seem to still have an old version of the Exceptional plugin installed.
|
10
25
|
Remove it from /vendor/plugins and try again.
|
11
26
|
***********************************************************************
|
12
27
|
)
|
data/install.rb
CHANGED
@@ -10,10 +10,10 @@ if File::exists? config_file
|
|
10
10
|
puts "Exceptional config file already exists. Please ensure it is up-to-date with the current format."
|
11
11
|
puts "See #{example_config_file}"
|
12
12
|
else
|
13
|
-
puts "Installing default Exceptional config"
|
13
|
+
puts "Installing default Exceptional config."
|
14
14
|
puts " From #{example_config_file}"
|
15
|
-
puts "For exceptional to work you need to configure your API
|
15
|
+
puts "For exceptional to work you need to configure your API key."
|
16
16
|
puts " See #{example_config_file}"
|
17
|
-
puts "If you don't have an API
|
17
|
+
puts "If you don't have an API key, get one at http://getexceptional.com/."
|
18
18
|
File.copy example_config_file, config_file
|
19
19
|
end
|
data/lib/exceptional/catcher.rb
CHANGED
@@ -1,9 +1,16 @@
|
|
1
1
|
module Exceptional
|
2
2
|
class Catcher
|
3
3
|
class << self
|
4
|
-
def
|
4
|
+
def handle_with_controller(exception, controller=nil, request=nil)
|
5
5
|
if Config.should_send_to_api?
|
6
|
-
data =
|
6
|
+
data = ControllerExceptionData.new(exception, controller, request)
|
7
|
+
Remote.error(data)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def handle(exception, name=nil)
|
12
|
+
if Config.should_send_to_api?
|
13
|
+
data = ExceptionData.new(exception, name)
|
7
14
|
Remote.error(data)
|
8
15
|
end
|
9
16
|
end
|
data/lib/exceptional/config.rb
CHANGED
@@ -2,11 +2,8 @@ module Exceptional
|
|
2
2
|
class Config
|
3
3
|
class << self
|
4
4
|
DEFAULTS = {
|
5
|
-
:
|
6
|
-
:remote_host_http => '
|
7
|
-
:remote_port_http => 80,
|
8
|
-
:remote_host_https => 'getexceptional.appspot.com',
|
9
|
-
:remote_port_https => 443,
|
5
|
+
:ssl => false,
|
6
|
+
:remote_host_http => 'plugin.getexceptional.com',
|
10
7
|
:http_open_timeout => 2,
|
11
8
|
:http_read_timeout => 4,
|
12
9
|
:disabled_by_default => %w(development test)
|
@@ -14,7 +11,7 @@ module Exceptional
|
|
14
11
|
|
15
12
|
attr_accessor :api_key
|
16
13
|
attr_accessor :http_proxy_host, :http_proxy_port, :http_proxy_username, :http_proxy_password
|
17
|
-
attr_writer :
|
14
|
+
attr_writer :ssl
|
18
15
|
|
19
16
|
def load(config_file=nil)
|
20
17
|
if (config_file && File.file?(config_file))
|
@@ -30,7 +27,7 @@ module Exceptional
|
|
30
27
|
@http_open_timeout = config['http-open-timeout']
|
31
28
|
@http_read_timeout = config['http-read-timeout']
|
32
29
|
|
33
|
-
@
|
30
|
+
@ssl = config['ssl'] || env_config['ssl']
|
34
31
|
@enabled = env_config['enabled']
|
35
32
|
@remote_port = config['remote-port'].to_i unless config['remote-port'].nil?
|
36
33
|
@remote_host = config['remote-host'] unless config['remote-host'].nil?
|
@@ -57,20 +54,20 @@ module Exceptional
|
|
57
54
|
defined?(RAILS_ROOT) ? RAILS_ROOT : Dir.pwd
|
58
55
|
end
|
59
56
|
|
60
|
-
def
|
61
|
-
@
|
57
|
+
def ssl?
|
58
|
+
@ssl ||= DEFAULTS[:ssl]
|
62
59
|
end
|
63
60
|
|
64
61
|
def remote_host
|
65
|
-
@remote_host ||=
|
62
|
+
@remote_host ||= DEFAULTS[:remote_host_http]
|
66
63
|
end
|
67
64
|
|
68
65
|
def remote_port
|
69
|
-
@remote_port ||=
|
66
|
+
@remote_port ||= ssl? ? 443 : 80
|
70
67
|
end
|
71
68
|
|
72
69
|
def reset
|
73
|
-
@enabled = @
|
70
|
+
@enabled = @ssl = @remote_host = @remote_port = @api_key = nil
|
74
71
|
end
|
75
72
|
|
76
73
|
def http_open_timeout
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'digest/md5'
|
2
|
+
|
3
|
+
module Exceptional
|
4
|
+
class ControllerExceptionData < ExceptionData
|
5
|
+
def initialize(exception, controller=nil, request=nil)
|
6
|
+
super(exception)
|
7
|
+
@request = request
|
8
|
+
@controller = controller
|
9
|
+
end
|
10
|
+
|
11
|
+
def extra_stuff
|
12
|
+
return {} if @request.nil?
|
13
|
+
{
|
14
|
+
'request' => {
|
15
|
+
'url' => "#{@request.protocol}#{@request.host}#{@request.request_uri}",
|
16
|
+
'controller' => @controller.class.to_s,
|
17
|
+
'action' => @request.parameters['action'],
|
18
|
+
'parameters' => filter_paramaters(@request.parameters),
|
19
|
+
'request_method' => @request.request_method.to_s,
|
20
|
+
'remote_ip' => @request.remote_ip,
|
21
|
+
'headers' => extract_http_headers(@request.env),
|
22
|
+
'session' => Exceptional::ControllerExceptionData.sanitize_session(@request)
|
23
|
+
}
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
def filter_paramaters(hash)
|
28
|
+
if @controller.respond_to?(:filter_parameters)
|
29
|
+
@controller.send(:filter_parameters, hash)
|
30
|
+
else
|
31
|
+
hash
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def extract_http_headers(env)
|
36
|
+
headers = {}
|
37
|
+
env.select{|k, v| k =~ /^HTTP_/}.each do |name, value|
|
38
|
+
proper_name = name.sub(/^HTTP_/, '').split('_').map{|upper_case| upper_case.capitalize}.join('-')
|
39
|
+
headers[proper_name] = value
|
40
|
+
end
|
41
|
+
unless headers['Cookie'].nil?
|
42
|
+
headers['Cookie'] = headers['Cookie'].sub(/_session=\S+/, '_session=[FILTERED]')
|
43
|
+
end
|
44
|
+
headers
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.sanitize_session(request)
|
48
|
+
session = request.session
|
49
|
+
session_hash = {}
|
50
|
+
session_hash['session_id'] = request.session_options ? request.session_options[:id] : nil
|
51
|
+
session_hash['session_id'] ||= session.respond_to?(:session_id) ? session.session_id : session.instance_variable_get("@session_id")
|
52
|
+
session_hash['data'] = session.respond_to?(:to_hash) ? session.to_hash : session.instance_variable_get("@data") || {}
|
53
|
+
session_hash['session_id'] ||= session_hash['data'][:session_id]
|
54
|
+
session_hash['data'].delete(:session_id)
|
55
|
+
ControllerExceptionData.sanitize_hash(session_hash)
|
56
|
+
rescue
|
57
|
+
{}
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -2,10 +2,9 @@ require 'digest/md5'
|
|
2
2
|
|
3
3
|
module Exceptional
|
4
4
|
class ExceptionData
|
5
|
-
def initialize(exception,
|
5
|
+
def initialize(exception, name=nil)
|
6
6
|
@exception = exception
|
7
|
-
@
|
8
|
-
@controller = controller
|
7
|
+
@name = name
|
9
8
|
end
|
10
9
|
|
11
10
|
def to_hash
|
@@ -18,23 +17,20 @@ module Exceptional
|
|
18
17
|
'occurred_at' => Time.now.strftime("%Y%m%d %H:%M:%S %Z")
|
19
18
|
}
|
20
19
|
})
|
21
|
-
|
22
|
-
|
23
|
-
'request' => {
|
24
|
-
'url' => "#{@request.protocol}#{@request.host}#{@request.request_uri}",
|
25
|
-
'controller' => @controller.class.to_s,
|
26
|
-
'action' => @request.parameters['action'],
|
27
|
-
'parameters' => filter_paramaters(@request.parameters),
|
28
|
-
'request_method' => @request.request_method.to_s,
|
29
|
-
'remote_ip' => @request.remote_ip,
|
30
|
-
'headers' => extract_http_headers(@request.env),
|
31
|
-
'session' => Exceptional::ExceptionData.sanitize_session(@request)
|
32
|
-
}
|
33
|
-
})
|
34
|
-
end
|
20
|
+
hash.merge!(extra_stuff)
|
21
|
+
hash.merge!(context_stuff)
|
35
22
|
hash
|
36
23
|
end
|
37
24
|
|
25
|
+
def extra_stuff
|
26
|
+
{ 'rescue_block' => { 'name' => @name} }
|
27
|
+
end
|
28
|
+
|
29
|
+
def context_stuff
|
30
|
+
context = Thread.current[:exceptional_context]
|
31
|
+
context.blank? ? {} : {'context' => context}
|
32
|
+
end
|
33
|
+
|
38
34
|
def to_json
|
39
35
|
to_hash.to_json
|
40
36
|
end
|
@@ -44,26 +40,6 @@ module Exceptional
|
|
44
40
|
Digest::MD5.hexdigest(@exception.backtrace.join)
|
45
41
|
end
|
46
42
|
|
47
|
-
def filter_paramaters(hash)
|
48
|
-
if @controller.respond_to?(:filter_parameters)
|
49
|
-
@controller.send(:filter_parameters, hash)
|
50
|
-
else
|
51
|
-
hash
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
def extract_http_headers(env)
|
56
|
-
headers = {}
|
57
|
-
env.select{|k, v| k =~ /^HTTP_/}.each do |name, value|
|
58
|
-
proper_name = name.sub(/^HTTP_/, '').split('_').map{|upper_case| upper_case.capitalize}.join('-')
|
59
|
-
headers[proper_name] = value
|
60
|
-
end
|
61
|
-
unless headers['Cookie'].nil?
|
62
|
-
headers['Cookie'] = headers['Cookie'].sub(/_session=\S+/, '_session=[FILTERED]')
|
63
|
-
end
|
64
|
-
headers
|
65
|
-
end
|
66
|
-
|
67
43
|
def self.sanitize_hash(hash)
|
68
44
|
case hash
|
69
45
|
when Hash
|
@@ -78,18 +54,5 @@ module Exceptional
|
|
78
54
|
rescue
|
79
55
|
{}
|
80
56
|
end
|
81
|
-
|
82
|
-
def self.sanitize_session(request)
|
83
|
-
session = request.session
|
84
|
-
session_hash = {}
|
85
|
-
session_hash['session_id'] = request.session_options ? request.session_options[:id] : nil
|
86
|
-
session_hash['session_id'] ||= session.respond_to?(:session_id) ? session.session_id : session.instance_variable_get("@session_id")
|
87
|
-
session_hash['data'] = session.respond_to?(:to_hash) ? session.to_hash : session.instance_variable_get("@data") || {}
|
88
|
-
session_hash['session_id'] ||= session_hash['data'][:session_id]
|
89
|
-
session_hash['data'].delete(:session_id)
|
90
|
-
ExceptionData.sanitize_hash(session_hash)
|
91
|
-
rescue
|
92
|
-
{}
|
93
|
-
end
|
94
57
|
end
|
95
58
|
end
|
@@ -8,7 +8,8 @@ if defined? ActionController
|
|
8
8
|
class Base
|
9
9
|
def rescue_action_with_exceptional(exception)
|
10
10
|
unless exception_handled_by_rescue_from?(exception)
|
11
|
-
Exceptional::Catcher.
|
11
|
+
Exceptional::Catcher.handle_with_controller(exception, self, request)
|
12
|
+
Exceptional.context.clear!
|
12
13
|
end
|
13
14
|
rescue_action_without_exceptional exception
|
14
15
|
end
|
@@ -23,4 +24,4 @@ if defined? ActionController
|
|
23
24
|
end
|
24
25
|
end
|
25
26
|
end
|
26
|
-
end
|
27
|
+
end
|
@@ -4,11 +4,11 @@ module Exceptional
|
|
4
4
|
end
|
5
5
|
|
6
6
|
def self.test
|
7
|
-
data = Exceptional::ExceptionData.new(ExceptionalTestException.new)
|
7
|
+
data = Exceptional::ExceptionData.new(ExceptionalTestException.new, 'Test exception')
|
8
8
|
unless Exceptional::Remote.error(data)
|
9
|
-
puts "Problem sending
|
9
|
+
puts "Problem sending exception to Exceptional. Check your API key."
|
10
10
|
else
|
11
|
-
puts "Exception sent successfully"
|
11
|
+
puts "Exception sent successfully."
|
12
12
|
end
|
13
13
|
end
|
14
14
|
end
|
data/lib/exceptional/remote.rb
CHANGED
@@ -30,7 +30,8 @@ module Exceptional
|
|
30
30
|
client = optional_proxy.new(config.remote_host, config.remote_port)
|
31
31
|
client.open_timeout = config.http_open_timeout
|
32
32
|
client.read_timeout = config.http_read_timeout
|
33
|
-
client.use_ssl = config.
|
33
|
+
client.use_ssl = config.ssl?
|
34
|
+
client.verify_mode = OpenSSL::SSL::VERIFY_NONE if config.ssl?
|
34
35
|
begin
|
35
36
|
response = client.post(url, data)
|
36
37
|
case response
|
data/lib/exceptional.rb
CHANGED
@@ -6,12 +6,12 @@ require 'exceptional/log_factory'
|
|
6
6
|
require 'exceptional/config'
|
7
7
|
require 'exceptional/application_environment'
|
8
8
|
require 'exceptional/exception_data'
|
9
|
+
require 'exceptional/controller_exception_data'
|
9
10
|
require 'exceptional/remote'
|
10
|
-
require 'exceptional/integration/rack'
|
11
11
|
|
12
12
|
module Exceptional
|
13
13
|
PROTOCOL_VERSION = 5
|
14
|
-
VERSION = '0.2.
|
14
|
+
VERSION = '0.2.1'
|
15
15
|
CLIENT_NAME = 'getexceptional-rails-plugin'
|
16
16
|
|
17
17
|
def self.logger
|
@@ -22,12 +22,38 @@ module Exceptional
|
|
22
22
|
Exceptional::Config.api_key = api_key
|
23
23
|
end
|
24
24
|
|
25
|
-
def self.
|
25
|
+
def self.handle(exception, name=nil)
|
26
|
+
Exceptional::Catcher.handle(exception, name)
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.rescue(name=nil, context=nil, &block)
|
26
30
|
begin
|
31
|
+
self.context(context) unless context.nil?
|
27
32
|
block.call
|
28
33
|
rescue Exception => e
|
29
|
-
Exceptional::Catcher.handle(e)
|
34
|
+
Exceptional::Catcher.handle(e,name)
|
35
|
+
self.clear!
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.rescue_and_reraise(name=nil, context=nil, &block)
|
40
|
+
begin
|
41
|
+
self.context(context) unless context.nil?
|
42
|
+
block.call
|
43
|
+
rescue Exception => e
|
44
|
+
Exceptional::Catcher.handle(e,name)
|
45
|
+
self.clear!
|
30
46
|
raise(e)
|
31
47
|
end
|
32
48
|
end
|
49
|
+
|
50
|
+
def self.clear!
|
51
|
+
Thread.current[:exceptional_context] = nil
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.context(hash = {})
|
55
|
+
Thread.current[:exceptional_context] ||= {}
|
56
|
+
Thread.current[:exceptional_context].merge!(hash)
|
57
|
+
self
|
58
|
+
end
|
33
59
|
end
|
@@ -6,8 +6,8 @@ describe Exceptional::Catcher do
|
|
6
6
|
exception = mock('exception')
|
7
7
|
controller = mock('controller')
|
8
8
|
request = mock('request')
|
9
|
-
Exceptional::
|
9
|
+
Exceptional::ControllerExceptionData.should_receive(:new).with(exception,controller,request).and_return(data = mock('exception_data'))
|
10
10
|
Exceptional::Remote.should_receive(:error).with(data)
|
11
|
-
Exceptional::Catcher.
|
11
|
+
Exceptional::Catcher.handle_with_controller(exception,controller,request)
|
12
12
|
end
|
13
13
|
end
|
@@ -5,8 +5,8 @@ describe Exceptional::Config, 'defaults' do
|
|
5
5
|
Exceptional::Config.reset
|
6
6
|
end
|
7
7
|
it "have sensible defaults" do
|
8
|
-
Exceptional::Config.
|
9
|
-
Exceptional::Config.remote_host.should == '
|
8
|
+
Exceptional::Config.ssl?.should == false
|
9
|
+
Exceptional::Config.remote_host.should == 'plugin.getexceptional.com'
|
10
10
|
Exceptional::Config.remote_port.should == 80
|
11
11
|
Exceptional::Config.application_root.should == Dir.pwd
|
12
12
|
Exceptional::Config.http_proxy_host.should be_nil
|
@@ -16,9 +16,9 @@ describe Exceptional::Config, 'defaults' do
|
|
16
16
|
Exceptional::Config.http_open_timeout.should == 2
|
17
17
|
Exceptional::Config.http_read_timeout.should == 4
|
18
18
|
end
|
19
|
-
it "have correct defaults when
|
20
|
-
Exceptional::Config.
|
21
|
-
Exceptional::Config.remote_host.should == 'getexceptional.
|
19
|
+
it "have correct defaults when ssl" do
|
20
|
+
Exceptional::Config.ssl = true
|
21
|
+
Exceptional::Config.remote_host.should == 'plugin.getexceptional.com'
|
22
22
|
Exceptional::Config.remote_port.should == 443
|
23
23
|
end
|
24
24
|
it "be enabled based on environment by default" do
|
@@ -38,7 +38,7 @@ describe Exceptional::Config, 'defaults' do
|
|
38
38
|
it "allow a new simpler format for exception.yml" do
|
39
39
|
Exceptional::Config.load('spec/fixtures/exceptional.yml')
|
40
40
|
Exceptional::Config.api_key.should == 'abc123'
|
41
|
-
Exceptional::Config.
|
41
|
+
Exceptional::Config.ssl?.should == true
|
42
42
|
Exceptional::Config.remote_host.should == 'example.com'
|
43
43
|
Exceptional::Config.remote_port.should == 123
|
44
44
|
Exceptional::Config.should_send_to_api?.should == true
|
@@ -52,7 +52,7 @@ describe Exceptional::Config, 'defaults' do
|
|
52
52
|
it "allow olded format for exception.yml" do
|
53
53
|
Exceptional::Config.load('spec/fixtures/exceptional_old.yml')
|
54
54
|
Exceptional::Config.api_key.should == 'abc123'
|
55
|
-
Exceptional::Config.
|
55
|
+
Exceptional::Config.ssl?.should == true
|
56
56
|
Exceptional::Config.should_send_to_api?.should == true
|
57
57
|
end
|
58
58
|
it "load api_key from environment variable" do
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/../spec_helper'
|
2
2
|
require 'digest/md5'
|
3
|
+
require 'json'
|
3
4
|
|
4
5
|
class Exceptional::FunkyError < StandardError
|
5
6
|
def backtrace
|
@@ -7,7 +8,7 @@ class Exceptional::FunkyError < StandardError
|
|
7
8
|
end
|
8
9
|
end
|
9
10
|
|
10
|
-
describe Exceptional::
|
11
|
+
describe Exceptional::ControllerExceptionData, 'when no request/controller/params' do
|
11
12
|
before :each do
|
12
13
|
ENV['LOGNAME'] = 'bob'
|
13
14
|
ENV['SOMEVAR'] = 'something'
|
@@ -15,8 +16,8 @@ describe Exceptional::ExceptionData, 'when no request/controller/params' do
|
|
15
16
|
RAILS_ENV = 'test' unless defined?(RAILS_ENV)
|
16
17
|
Time.stub!(:now).and_return(Time.mktime(1970,1,1))
|
17
18
|
error = Exceptional::FunkyError.new('some message')
|
18
|
-
data = Exceptional::
|
19
|
-
@hash = data.to_hash
|
19
|
+
@data = Exceptional::ControllerExceptionData.new(error)
|
20
|
+
@hash = @data.to_hash
|
20
21
|
end
|
21
22
|
|
22
23
|
it "capture exception details" do
|
@@ -31,6 +32,10 @@ describe Exceptional::ExceptionData, 'when no request/controller/params' do
|
|
31
32
|
client_hash['protocol_version'].should == Exceptional::PROTOCOL_VERSION
|
32
33
|
end
|
33
34
|
|
35
|
+
it "generates json" do
|
36
|
+
JSON.parse(@data.to_json)
|
37
|
+
end
|
38
|
+
|
34
39
|
it "capture application_environment" do
|
35
40
|
application_env_hash = @hash['application_environment']
|
36
41
|
application_env_hash['environment'].should == 'test'
|
@@ -46,7 +51,7 @@ describe Exceptional::ExceptionData, 'when no request/controller/params' do
|
|
46
51
|
end
|
47
52
|
end
|
48
53
|
|
49
|
-
describe Exceptional::
|
54
|
+
describe Exceptional::ControllerExceptionData, 'with request/controller/params' do
|
50
55
|
class Exceptional::SomeController < ActionController::Base
|
51
56
|
filter_parameter_logging :filter_me
|
52
57
|
end
|
@@ -60,7 +65,7 @@ describe Exceptional::ExceptionData, 'with request/controller/params' do
|
|
60
65
|
@request.stub!(:remote_ip).and_return('1.2.3.4')
|
61
66
|
@request.stub!(:env).and_return({'SOME_VAR' => 'abc', 'HTTP_CONTENT_TYPE' => 'text/html'})
|
62
67
|
error = Exceptional::FunkyError.new('some message')
|
63
|
-
data = Exceptional::
|
68
|
+
data = Exceptional::ControllerExceptionData.new(error, @controller, @request)
|
64
69
|
@hash = data.to_hash
|
65
70
|
end
|
66
71
|
|
@@ -83,7 +88,12 @@ describe Exceptional::ExceptionData, 'with request/controller/params' do
|
|
83
88
|
end
|
84
89
|
crazy = Crazy.new
|
85
90
|
input = {'crazy' => crazy, :simple => '123', :some_hash => {'1' => '2'}, :array => ['1','2']}
|
86
|
-
Exceptional::
|
91
|
+
Exceptional::ControllerExceptionData.sanitize_hash(input).should == {'crazy' => crazy.to_s, :simple => '123', :some_hash => {'1' => '2'}, :array => ['1','2']}
|
92
|
+
end
|
93
|
+
|
94
|
+
it "to_strings regex because JSON.parse(/aa/.to_json) doesn't work" do
|
95
|
+
input = {'crazy' => /abc.*/}
|
96
|
+
Exceptional::ExceptionData.sanitize_hash(input).should == {'crazy' => /abc.*/.to_s}
|
87
97
|
end
|
88
98
|
|
89
99
|
it "handles session objects with various interfaces" do
|
@@ -97,27 +107,27 @@ describe Exceptional::ExceptionData, 'with request/controller/params' do
|
|
97
107
|
session = SessionWithInstanceVariables.new
|
98
108
|
request.stub!(:session).and_return(session)
|
99
109
|
request.stub!(:session_options).and_return({})
|
100
|
-
Exceptional::
|
110
|
+
Exceptional::ControllerExceptionData.sanitize_session(request).should == {'session_id' => '123', 'data' => {'a' => '1'}}
|
101
111
|
session = mock('session', :session_id => '123', :instance_variable_get => {'a' => '1'})
|
102
112
|
request.stub!(:session).and_return(session)
|
103
|
-
Exceptional::
|
113
|
+
Exceptional::ControllerExceptionData.sanitize_session(request).should == {'session_id' => '123', 'data' => {'a' => '1'}}
|
104
114
|
session = mock('session', :session_id => nil, :to_hash => {:session_id => '123', 'a' => '1'})
|
105
115
|
request.stub!(:session).and_return(session)
|
106
|
-
Exceptional::
|
116
|
+
Exceptional::ControllerExceptionData.sanitize_session(request).should == {'session_id' => '123', 'data' => {'a' => '1'}}
|
107
117
|
request.stub!(:session_options).and_return({:id => 'xyz'})
|
108
|
-
Exceptional::
|
118
|
+
Exceptional::ControllerExceptionData.sanitize_session(request).should == {'session_id' => 'xyz', 'data' => {'a' => '1'}}
|
109
119
|
end
|
110
120
|
|
111
121
|
it "filter session cookies from headers" do
|
112
122
|
@request.stub!(:env).and_return({'SOME_VAR' => 'abc', 'HTTP_COOKIE' => '_something_else=faafsafafasfa; _myapp-lick-nation_session=BAh7DDoMbnVtYmVyc1sJaQZpB2kIaQk6FnNvbWVfY3Jhenlfb2JqZWN0bzobU3Bpa2VDb250cm9sbGVyOjpDcmF6eQY6CUBiYXJABzoTc29tZXRoaW5nX2Vsc2UiCGNjYzoKYXBwbGUiDUJyYWVidXJuOgloYXNoewdpBmkHaQhpCToPc2Vzc2lvbl9pZCIlMmJjZTM4MjVjMThkNzYxOWEyZDA4NTJhNWY1NGQzMmU6C3RvbWF0byIJQmVlZg%3D%3D--66fb4606851f06bf409b8bc4ba7aea47a0259bf7'})
|
113
|
-
@hash = Exceptional::
|
123
|
+
@hash = Exceptional::ControllerExceptionData.new(Exceptional::FunkyError.new('some message'), @controller, @request).to_hash
|
114
124
|
@hash['request']['headers'].should == {'Cookie' => '_something_else=faafsafafasfa; _myapp-lick-nation_session=[FILTERED]'}
|
115
125
|
end
|
116
126
|
|
117
127
|
it "creates a uniqueness_hash from backtrace" do
|
118
128
|
myException = Exception.new
|
119
129
|
myException.stub!(:backtrace).and_return(['123'])
|
120
|
-
data = Exceptional::
|
130
|
+
data = Exceptional::ControllerExceptionData.new(myException)
|
121
131
|
data.uniqueness_hash.should == Digest::MD5.hexdigest('123')
|
122
132
|
end
|
123
133
|
end
|
@@ -1,17 +1,64 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/spec_helper'
|
2
2
|
|
3
3
|
context 'resuce errors from within a block' do
|
4
|
-
class FunkyException < StandardError;
|
5
|
-
|
4
|
+
class FunkyException < StandardError;
|
5
|
+
end
|
6
|
+
it "Exceptional.rescue should send to exceptional and swallow error " do
|
7
|
+
to_raise = FunkyException.new
|
8
|
+
Exceptional::Catcher.should_receive(:handle).with(to_raise, 'my rescue name')
|
9
|
+
Exceptional.rescue('my rescue name') do
|
10
|
+
raise to_raise
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
it "reraises error with rescue_and_reraise" do
|
6
15
|
to_raise = FunkyException.new
|
7
|
-
Exceptional::Catcher.should_receive(:handle).with(to_raise)
|
16
|
+
Exceptional::Catcher.should_receive(:handle).with(to_raise, 'my rescue name')
|
8
17
|
begin
|
9
|
-
Exceptional.rescue do
|
18
|
+
Exceptional.rescue_and_reraise('my rescue name') do
|
10
19
|
raise to_raise
|
11
20
|
end
|
12
|
-
fail
|
21
|
+
fail 'expected a reraise'
|
13
22
|
rescue FunkyException => e
|
14
|
-
e.should == to_raise
|
15
23
|
end
|
16
24
|
end
|
25
|
+
|
26
|
+
it "Exceptional.handle calls Exceptional::Catcher.handle" do
|
27
|
+
to_raise = FunkyException.new
|
28
|
+
Exceptional::Catcher.should_receive(:handle).with(to_raise, 'optional name for where it has occurred')
|
29
|
+
begin
|
30
|
+
raise to_raise
|
31
|
+
rescue => e
|
32
|
+
Exceptional.handle(e, 'optional name for where it has occurred')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
it "collects context information but leaves thread local empty after block" do
|
37
|
+
to_raise = FunkyException.new
|
38
|
+
Exceptional::Config.should_receive(:should_send_to_api?).and_return(true)
|
39
|
+
Exceptional::Remote.should_receive(:error) {|exception_data|
|
40
|
+
exception_data.to_hash['context']['foo'] == 'bar'
|
41
|
+
exception_data.to_hash['context']['baz'] == 42
|
42
|
+
exception_data.to_hash['context']['cats'] == {'lol' => 'bot'}
|
43
|
+
}
|
44
|
+
Exceptional.rescue('my rescue name') do
|
45
|
+
Exceptional.context('foo' => 'bar')
|
46
|
+
Exceptional.context('baz' => 42)
|
47
|
+
Exceptional.context('cats' => {'lol' => 'bot'})
|
48
|
+
raise to_raise
|
49
|
+
end
|
50
|
+
Thread.current[:exceptional_context].should == nil
|
51
|
+
end
|
52
|
+
|
53
|
+
it "clearr context with Exceptional.context.clear!" do
|
54
|
+
Exceptional.context('foo' => 'bar')
|
55
|
+
Thread.current[:exceptional_context].should_not == nil
|
56
|
+
Exceptional.context.clear!
|
57
|
+
Thread.current[:exceptional_context].should == nil
|
58
|
+
end
|
59
|
+
|
60
|
+
it "allows optional second paramater hash to get added to context" do
|
61
|
+
Exceptional.should_receive(:context).with(context_hash = {'foo' => 'bar', 'baz' => 42})
|
62
|
+
Exceptional.rescue('my resccue', context_hash) {}
|
63
|
+
end
|
17
64
|
end
|
@@ -3,13 +3,13 @@ require File.join(File.dirname(__FILE__), '..', 'lib', 'exceptional', 'integrati
|
|
3
3
|
|
4
4
|
describe Exceptional, 'version number' do
|
5
5
|
it "be available proramatically" do
|
6
|
-
Exceptional::VERSION.should == '0.2.
|
6
|
+
Exceptional::VERSION.should == '0.2.1'
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
10
10
|
describe ActiveSupport::JSON, 'standards compliant json' do
|
11
11
|
it "quote keys" do
|
12
|
-
{:a => '123'}.to_json.gsub(/ /,'').should == '{"a":"123"}'
|
12
|
+
{:a => '123'}.to_json.gsub(/ /, '').should == '{"a":"123"}'
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
@@ -25,27 +25,36 @@ describe TestingController do
|
|
25
25
|
end
|
26
26
|
|
27
27
|
it 'handle exception with Exceptional::Catcher' do
|
28
|
-
Exceptional::Catcher.should_receive(:
|
28
|
+
Exceptional::Catcher.should_receive(:handle_with_controller).with(an_instance_of(StandardError), @controller, an_instance_of(ActionController::TestRequest))
|
29
29
|
send_request(:raises_something)
|
30
30
|
end
|
31
31
|
|
32
32
|
it "still return an error response to the user" do
|
33
|
-
Exceptional::Catcher.stub!(:
|
33
|
+
Exceptional::Catcher.stub!(:handle_with_controller)
|
34
34
|
send_request(:raises_something)
|
35
35
|
@response.code.should == '500'
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
39
|
if ActionController::Base.respond_to?(:rescue_from)
|
40
|
-
class CustomError < StandardError;
|
40
|
+
class CustomError < StandardError;
|
41
|
+
end
|
41
42
|
class TestingWithRescueFromController < ActionController::Base
|
42
43
|
rescue_from CustomError, :with => :custom_handler
|
44
|
+
|
43
45
|
def raises_custom_error
|
44
46
|
raise CustomError.new
|
45
47
|
end
|
48
|
+
|
46
49
|
def raises_other_error
|
47
50
|
raise StandardError.new
|
48
51
|
end
|
52
|
+
|
53
|
+
def raises_with_context
|
54
|
+
Exceptional.context('foo' => 'bar')
|
55
|
+
raise StandardError.new
|
56
|
+
end
|
57
|
+
|
49
58
|
def custom_handler
|
50
59
|
head :ok
|
51
60
|
end
|
@@ -57,12 +66,20 @@ if ActionController::Base.respond_to?(:rescue_from)
|
|
57
66
|
end
|
58
67
|
|
59
68
|
it 'not handle exception with Exceptional that is dealt with by rescue_from' do
|
60
|
-
Exceptional::Catcher.should_not_receive(:
|
69
|
+
Exceptional::Catcher.should_not_receive(:handle_with_controller)
|
61
70
|
send_request(:raises_custom_error)
|
62
71
|
end
|
63
72
|
it 'handle exception with Exceptional that is not dealt with by rescue_from' do
|
64
|
-
Exceptional::Catcher.should_receive(:
|
73
|
+
Exceptional::Catcher.should_receive(:handle_with_controller)
|
65
74
|
send_request(:raises_other_error)
|
66
75
|
end
|
76
|
+
it "has context and clears context after request" do
|
77
|
+
Exceptional::Config.should_receive(:should_send_to_api?).and_return(true)
|
78
|
+
Exceptional::Remote.should_receive(:error) {|exception_data|
|
79
|
+
exception_data.to_hash['context']['foo'] == 'bar'
|
80
|
+
}
|
81
|
+
send_request(:raises_with_context)
|
82
|
+
Thread.current[:exceptional_context].should == nil
|
83
|
+
end
|
67
84
|
end
|
68
85
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -4,6 +4,7 @@ begin
|
|
4
4
|
rescue LoadError
|
5
5
|
raise "cant load ginger"
|
6
6
|
end
|
7
|
+
|
7
8
|
gem 'rails'
|
8
9
|
require File.dirname(__FILE__) + '/../lib/exceptional' unless defined?(Exceptional)
|
9
10
|
|
@@ -17,4 +18,4 @@ def send_request(action = nil)
|
|
17
18
|
@request.action = action ? action.to_s : ""
|
18
19
|
@response = ActionController::TestResponse.new
|
19
20
|
@controller.process(@request, @response)
|
20
|
-
end
|
21
|
+
end
|
@@ -2,7 +2,7 @@ namespace :exceptional do
|
|
2
2
|
desc 'Send a test exception to Exceptional.'
|
3
3
|
task :test => :environment do
|
4
4
|
unless Exceptional::Config.api_key.blank?
|
5
|
-
puts "Sending test exception to Exceptional"
|
5
|
+
puts "Sending test exception to Exceptional."
|
6
6
|
require "exceptional/integration/tester"
|
7
7
|
Exceptional::Integration.test
|
8
8
|
puts "Done."
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: exceptional
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Contrast
|
@@ -9,19 +9,10 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-12-18 00:00:00 +00:00
|
13
13
|
default_executable:
|
14
|
-
dependencies:
|
15
|
-
|
16
|
-
name: json
|
17
|
-
type: :runtime
|
18
|
-
version_requirement:
|
19
|
-
version_requirements: !ruby/object:Gem::Requirement
|
20
|
-
requirements:
|
21
|
-
- - ">="
|
22
|
-
- !ruby/object:Gem::Version
|
23
|
-
version: 1.0.0
|
24
|
-
version:
|
14
|
+
dependencies: []
|
15
|
+
|
25
16
|
description: Exceptional is the core Ruby library for communicating with http://getexceptional.com (hosted error tracking service). Use it to find out about errors that happen in your live app. It captures lots of helpful information to help you fix the errors.
|
26
17
|
email: hello@contrast.ie
|
27
18
|
executables:
|
@@ -34,8 +25,8 @@ files:
|
|
34
25
|
- lib/exceptional/application_environment.rb
|
35
26
|
- lib/exceptional/catcher.rb
|
36
27
|
- lib/exceptional/config.rb
|
28
|
+
- lib/exceptional/controller_exception_data.rb
|
37
29
|
- lib/exceptional/exception_data.rb
|
38
|
-
- lib/exceptional/integration/rack.rb
|
39
30
|
- lib/exceptional/integration/rails.rb
|
40
31
|
- lib/exceptional/integration/tester.rb
|
41
32
|
- lib/exceptional/log_factory.rb
|
@@ -81,8 +72,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
81
72
|
- !ruby/object:Gem::Version
|
82
73
|
version: "0"
|
83
74
|
version:
|
84
|
-
requirements:
|
85
|
-
|
75
|
+
requirements:
|
76
|
+
- json_pure, json-jruby or json gem required
|
86
77
|
rubyforge_project: exceptional
|
87
78
|
rubygems_version: 1.3.5
|
88
79
|
signing_key:
|