exceptional 2.0.0 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
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 # 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.
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 'missing required paramater <api-key>. Check your app configuration at http://getexceptional.com'
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.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.add_dependency('json', ">= 1.0.0")
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 exceptional plugin installed.
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 Key"
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 Key, get one at http://getexceptional.com/"
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
@@ -1,9 +1,16 @@
1
1
  module Exceptional
2
2
  class Catcher
3
3
  class << self
4
- def handle(exception, controller=nil, request=nil)
4
+ def handle_with_controller(exception, controller=nil, request=nil)
5
5
  if Config.should_send_to_api?
6
- data = ExceptionData.new(exception, controller, request)
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
@@ -2,11 +2,8 @@ module Exceptional
2
2
  class Config
3
3
  class << self
4
4
  DEFAULTS = {
5
- :ssl_enabled => false,
6
- :remote_host_http => 'api.getexceptional.com',
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 :ssl_enabled
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
- @ssl_enabled = config['ssl'] || env_config['ssl']
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 ssl_enabled?
61
- @ssl_enabled ||= DEFAULTS[:ssl_enabled]
57
+ def ssl?
58
+ @ssl ||= DEFAULTS[:ssl]
62
59
  end
63
60
 
64
61
  def remote_host
65
- @remote_host ||= ssl_enabled? ? DEFAULTS[:remote_host_https] : DEFAULTS[:remote_host_http]
62
+ @remote_host ||= DEFAULTS[:remote_host_http]
66
63
  end
67
64
 
68
65
  def remote_port
69
- @remote_port ||= ssl_enabled? ? DEFAULTS[:remote_port_https] : DEFAULTS[:remote_port_http]
66
+ @remote_port ||= ssl? ? 443 : 80
70
67
  end
71
68
 
72
69
  def reset
73
- @enabled = @ssl_enabled = @remote_host = @remote_port = @api_key = nil
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, controller=nil, request=nil)
5
+ def initialize(exception, name=nil)
6
6
  @exception = exception
7
- @request = request
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
- unless @request.nil?
22
- hash.merge!({
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.handle(exception, self, request)
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 error to Exceptional. Check your api key"
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
@@ -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.ssl_enabled?
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.0'
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.rescue(&block)
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::ExceptionData.should_receive(:new).with(exception,controller,request).and_return(data = mock('exception_data'))
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.handle(exception,controller,request)
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.ssl_enabled?.should == false
9
- Exceptional::Config.remote_host.should == 'api.getexceptional.com'
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 ssl_enabled" do
20
- Exceptional::Config.ssl_enabled = true
21
- Exceptional::Config.remote_host.should == 'getexceptional.appspot.com'
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.ssl_enabled?.should == true
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.ssl_enabled?.should == true
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::ExceptionData, 'when no request/controller/params' do
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::ExceptionData.new(error)
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::ExceptionData, 'with request/controller/params' do
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::ExceptionData.new(error, @controller, @request)
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::ExceptionData.sanitize_hash(input).should == {'crazy' => crazy.to_s, :simple => '123', :some_hash => {'1' => '2'}, :array => ['1','2']}
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::ExceptionData.sanitize_session(request).should == {'session_id' => '123', 'data' => {'a' => '1'}}
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::ExceptionData.sanitize_session(request).should == {'session_id' => '123', 'data' => {'a' => '1'}}
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::ExceptionData.sanitize_session(request).should == {'session_id' => '123', 'data' => {'a' => '1'}}
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::ExceptionData.sanitize_session(request).should == {'session_id' => 'xyz', 'data' => {'a' => '1'}}
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::ExceptionData.new(Exceptional::FunkyError.new('some message'), @controller, @request).to_hash
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::ExceptionData.new(myException)
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; end
5
- it "send them to catcher and reraise" do
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 "expected to raise"
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.0'
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(:handle).with(an_instance_of(StandardError), @controller, an_instance_of(ActionController::TestRequest))
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!(:handle)
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; end
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(:handle)
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(:handle)
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.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-11-13 00:00:00 +00:00
12
+ date: 2009-12-18 00:00:00 +00:00
13
13
  default_executable:
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
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:
@@ -1,14 +0,0 @@
1
- module Exceptional
2
- class Rack
3
- def initialize(app, api_key)
4
- @app = app
5
- @api_key= api_key
6
- end
7
-
8
- def call(env)
9
- @app.call(env)
10
- rescue Exception => e
11
- raise e
12
- end
13
- end
14
- end