exceptional 2.0.5 → 2.0.6
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 +23 -13
- data/exceptional.gemspec +3 -3
- data/lib/exceptional.rb +5 -2
- data/lib/exceptional/application_environment.rb +2 -7
- data/lib/exceptional/catcher.rb +8 -1
- data/lib/exceptional/controller_exception_data.rb +4 -0
- data/lib/exceptional/exception_data.rb +5 -1
- data/lib/exceptional/integration/rack.rb +21 -0
- data/lib/exceptional/rack_exception_data.rb +29 -0
- data/lib/exceptional/remote.rb +2 -2
- data/lib/exceptional/startup.rb +1 -1
- data/spec/exceptional/exception_data_spec.rb +3 -0
- data/spec/exceptional/rack_exception_data_spec.rb +87 -0
- data/spec/rack_integration_spec.rb +21 -0
- data/spec/rails_integration_spec.rb +1 -1
- metadata +8 -4
data/bin/exceptional
CHANGED
@@ -12,25 +12,35 @@ test # Send a test exception to Exceptional.
|
|
12
12
|
install <api_key> # Create config/exceptional.yml with your api_key. Overrites existing one.
|
13
13
|
USAGE
|
14
14
|
when 'test'
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
if defined?(RAILS_ROOT)
|
16
|
+
puts "Loading Rails environment."
|
17
|
+
require(File.join('config', 'boot'))
|
18
|
+
require(File.join(RAILS_ROOT, 'config', 'environment')) if defined?(RAILS_ROOT)
|
19
|
+
require "exceptional/integration/tester"
|
20
|
+
else
|
21
|
+
require 'json'
|
22
|
+
require 'exceptional'
|
23
|
+
require "exceptional/integration/tester"
|
24
|
+
Exceptional::Config.load('config/exceptional.yml')
|
25
|
+
end
|
26
|
+
unless Exceptional::Config.api_key.empty?
|
20
27
|
Exceptional::Integration.test
|
21
|
-
|
28
|
+
else
|
29
|
+
puts 'API key not configured'
|
30
|
+
end
|
22
31
|
when 'install'
|
23
32
|
api_key = args[0]
|
24
33
|
if (api_key.nil?)
|
25
34
|
puts 'Missing required paramater <api-key>. Check your app configuration at http://getexceptional.com.'
|
26
35
|
else
|
27
|
-
|
28
|
-
puts "Run this command from the root of your rails application."
|
36
|
+
if (defined?(RAILS_ROOT) && !File.file?('config/environment.rb'))
|
37
|
+
puts "Run this command from the root of your rails application." and return
|
29
38
|
else
|
30
|
-
|
31
|
-
config_file.puts("api-key: #{api_key}\n")
|
32
|
-
config_file.close
|
33
|
-
puts "Config file written as config/exceptional.yml."
|
39
|
+
Dir.mkdir('config') unless File.exists?('config')
|
34
40
|
end
|
35
|
-
end
|
41
|
+
end
|
42
|
+
config_file = File.open('config/exceptional.yml', 'w')
|
43
|
+
config_file.puts("api-key: #{api_key}\n")
|
44
|
+
config_file.close
|
45
|
+
puts "Config file written as config/exceptional.yml."
|
36
46
|
end
|
data/exceptional.gemspec
CHANGED
@@ -1,10 +1,10 @@
|
|
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.6"
|
5
5
|
s.authors = ["Contrast"]
|
6
|
-
s.summary = %q{
|
7
|
-
s.description = %q{Exceptional is the
|
6
|
+
s.summary = %q{ getexceptional.com is a hosted service for tracking errors in your Ruby/Rails/Rack apps }
|
7
|
+
s.description = %q{Exceptional is the Ruby gem 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.}
|
8
8
|
s.email = %q{hello@contrast.ie}
|
9
9
|
s.files = Dir['lib/**/*'] + Dir['spec/**/*'] + Dir['spec/**/*'] + Dir['rails/**/*'] + Dir['tasks/**/*'] + Dir['*.rb'] + ["exceptional.gemspec"]
|
10
10
|
s.homepage = %q{http://getexceptional.com/}
|
data/lib/exceptional.rb
CHANGED
@@ -7,12 +7,15 @@ require 'exceptional/config'
|
|
7
7
|
require 'exceptional/application_environment'
|
8
8
|
require 'exceptional/exception_data'
|
9
9
|
require 'exceptional/controller_exception_data'
|
10
|
+
require 'exceptional/rack_exception_data'
|
10
11
|
require 'exceptional/remote'
|
12
|
+
require 'exceptional/integration/rack'
|
11
13
|
|
12
14
|
module Exceptional
|
15
|
+
|
13
16
|
PROTOCOL_VERSION = 5
|
14
|
-
VERSION = '2.0.
|
15
|
-
CLIENT_NAME = 'getexceptional-
|
17
|
+
VERSION = '2.0.6'
|
18
|
+
CLIENT_NAME = 'getexceptional-gem'
|
16
19
|
|
17
20
|
def self.logger
|
18
21
|
::Exceptional::LogFactory.logger
|
@@ -2,8 +2,8 @@ require 'digest/md5'
|
|
2
2
|
|
3
3
|
module Exceptional
|
4
4
|
class ApplicationEnvironment
|
5
|
-
def self.to_hash
|
6
|
-
|
5
|
+
def self.to_hash(framework)
|
6
|
+
{
|
7
7
|
'client' => {
|
8
8
|
'name' => Exceptional::CLIENT_NAME,
|
9
9
|
'version' => Exceptional::VERSION,
|
@@ -21,11 +21,6 @@ module Exceptional
|
|
21
21
|
'libraries_loaded' => libraries_loaded
|
22
22
|
}
|
23
23
|
}
|
24
|
-
hash
|
25
|
-
end
|
26
|
-
|
27
|
-
def self.framework
|
28
|
-
defined?(RAILS_ENV) ? "rails" : nil
|
29
24
|
end
|
30
25
|
|
31
26
|
def self.environment
|
data/lib/exceptional/catcher.rb
CHANGED
@@ -7,6 +7,13 @@ module Exceptional
|
|
7
7
|
Remote.error(data)
|
8
8
|
end
|
9
9
|
end
|
10
|
+
|
11
|
+
def handle_with_rack(exception, environment, request)
|
12
|
+
if Config.should_send_to_api?
|
13
|
+
data = RackExceptionData.new(exception, environment, request)
|
14
|
+
Remote.error(data)
|
15
|
+
end
|
16
|
+
end
|
10
17
|
|
11
18
|
def handle(exception, name=nil)
|
12
19
|
if Config.should_send_to_api?
|
@@ -16,4 +23,4 @@ module Exceptional
|
|
16
23
|
end
|
17
24
|
end
|
18
25
|
end
|
19
|
-
end
|
26
|
+
end
|
@@ -8,7 +8,7 @@ module Exceptional
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def to_hash
|
11
|
-
hash = ::Exceptional::ApplicationEnvironment.to_hash
|
11
|
+
hash = ::Exceptional::ApplicationEnvironment.to_hash(framework)
|
12
12
|
hash.merge!({
|
13
13
|
'exception' => {
|
14
14
|
'exception_class' => @exception.class.to_s,
|
@@ -43,6 +43,10 @@ module Exceptional
|
|
43
43
|
end
|
44
44
|
end
|
45
45
|
end
|
46
|
+
|
47
|
+
def framework
|
48
|
+
nil
|
49
|
+
end
|
46
50
|
|
47
51
|
def uniqueness_hash
|
48
52
|
return nil if (@exception.backtrace.nil? || @exception.backtrace.empty?)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rack'
|
3
|
+
|
4
|
+
module Rack
|
5
|
+
class Exceptional
|
6
|
+
|
7
|
+
def initialize(app, exceptional_config = "config/exceptional.yml")
|
8
|
+
@app = app
|
9
|
+
::Exceptional::Config.load(exceptional_config)
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(env)
|
13
|
+
begin
|
14
|
+
status, headers, body = @app.call(env)
|
15
|
+
rescue Exception => e
|
16
|
+
::Exceptional::Catcher.handle_with_rack(e,env, Rack::Request.new(env))
|
17
|
+
raise(e)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'digest/md5'
|
2
|
+
|
3
|
+
module Exceptional
|
4
|
+
class RackExceptionData < ExceptionData
|
5
|
+
def initialize(exception, environment, request)
|
6
|
+
super(exception)
|
7
|
+
@environment = environment
|
8
|
+
@request = request
|
9
|
+
end
|
10
|
+
|
11
|
+
def framework
|
12
|
+
"rack"
|
13
|
+
end
|
14
|
+
|
15
|
+
def extra_stuff
|
16
|
+
return {} if @request.nil?
|
17
|
+
{
|
18
|
+
'request' => {
|
19
|
+
'url' => "#{@request.url}",
|
20
|
+
'parameters' => @request.params,
|
21
|
+
'request_method' => @request.request_method.to_s,
|
22
|
+
'remote_ip' => @request.ip,
|
23
|
+
'headers' => @environment.reject{|k,v| !k.match(/^HTTP_/)},
|
24
|
+
'session' => @request.session
|
25
|
+
}
|
26
|
+
}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/exceptional/remote.rb
CHANGED
@@ -37,10 +37,10 @@ module Exceptional
|
|
37
37
|
response = client.post(url, data)
|
38
38
|
case response
|
39
39
|
when Net::HTTPSuccess
|
40
|
-
Exceptional.logger.info(
|
40
|
+
Exceptional.logger.info( "#{url} Successful")
|
41
41
|
return true
|
42
42
|
else
|
43
|
-
Exceptional.logger.error(
|
43
|
+
Exceptional.logger.error("#{url} - #{response.code} - Failed")
|
44
44
|
end
|
45
45
|
rescue Exception => e
|
46
46
|
Exceptional.logger.error('Problem notifying Exceptional about the error')
|
data/lib/exceptional/startup.rb
CHANGED
@@ -7,7 +7,7 @@ module Exceptional
|
|
7
7
|
if Config.api_key.blank?
|
8
8
|
raise StartupException, 'API Key must be configured (/config/exceptional.yml)'
|
9
9
|
end
|
10
|
-
Remote.startup_announce(::Exceptional::ApplicationEnvironment.to_hash)
|
10
|
+
Remote.startup_announce(::Exceptional::ApplicationEnvironment.to_hash('rails'))
|
11
11
|
end
|
12
12
|
end
|
13
13
|
end
|
@@ -118,6 +118,7 @@ describe Exceptional::ControllerExceptionData, 'with request/controller/params'
|
|
118
118
|
@session_id = '123'
|
119
119
|
end
|
120
120
|
end
|
121
|
+
|
121
122
|
request = ActionController::TestRequest.new
|
122
123
|
session = SessionWithInstanceVariables.new
|
123
124
|
request.stub!(:session).and_return(session)
|
@@ -159,4 +160,6 @@ describe Exceptional::ControllerExceptionData, 'with request/controller/params'
|
|
159
160
|
data = Exceptional::ControllerExceptionData.new(myException)
|
160
161
|
data.uniqueness_hash.should == nil
|
161
162
|
end
|
163
|
+
|
164
|
+
|
162
165
|
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
require 'digest/md5'
|
3
|
+
|
4
|
+
describe Exceptional::RackExceptionData do
|
5
|
+
|
6
|
+
class Exceptional::FunkyError < StandardError
|
7
|
+
def backtrace
|
8
|
+
'backtrace'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
before :each do
|
13
|
+
app = lambda { |env| [200, {'Content-Type'=>'text/plain'}, 'Hello World']}
|
14
|
+
|
15
|
+
@env = {
|
16
|
+
"HTTP_HOST" =>"localhost:9292",
|
17
|
+
"HTTP_ACCEPT" =>"*/*",
|
18
|
+
"SERVER_NAME" =>"localhost",
|
19
|
+
"REQUEST_PATH" =>"/",
|
20
|
+
"rack.url_scheme" =>"http",
|
21
|
+
"HTTP_USER_AGENT" =>"curl/7.19.6 (i386-apple-darwin9.8.0) libcurl/7.19.6 zlib/1.2.3",
|
22
|
+
"REMOTE_HOST" =>"testing.com",
|
23
|
+
"rack.errors" => StringIO.new,
|
24
|
+
"SERVER_PROTOCOL" =>"HTTP/1.1",
|
25
|
+
"rack.version" =>[1, 1],
|
26
|
+
"rack.run_once" =>false,
|
27
|
+
"SERVER_SOFTWARE" =>"WEBrick/1.3.1 (Ruby/1.8.7/2009-06-12)",
|
28
|
+
"REMOTE_ADDR" =>"127.0.0.1",
|
29
|
+
"PATH_INFO" => "/",
|
30
|
+
"SCRIPT_NAME" =>"",
|
31
|
+
"HTTP_VERSION" =>"HTTP/1.1",
|
32
|
+
"rack.multithread" =>true,
|
33
|
+
"rack.multiprocess" =>false,
|
34
|
+
"REQUEST_URI" =>"http://localhost:9292/",
|
35
|
+
"SERVER_PORT" =>"9292",
|
36
|
+
"REQUEST_METHOD" =>"GET",
|
37
|
+
"rack.input" => StringIO.new,
|
38
|
+
"QUERY_STRING" =>"cockle=shell&bay=cool",
|
39
|
+
"GATEWAY_INTERFACE" =>"CGI/1.1"
|
40
|
+
}
|
41
|
+
|
42
|
+
error = Exceptional::FunkyError.new('some message')
|
43
|
+
request = Rack::Request.new(@env)
|
44
|
+
@data = Exceptional::RackExceptionData.new(error, @env, request)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "capture exception details" do
|
48
|
+
error_hash = @data.to_hash['exception']
|
49
|
+
error_hash['exception_class'].should == 'Exceptional::FunkyError'
|
50
|
+
error_hash['message'].should == 'some message'
|
51
|
+
error_hash['backtrace'].should == 'backtrace'
|
52
|
+
error_hash['occurred_at'].should == Time.now.strftime("%Y%m%d %H:%M:%S %Z")
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should capture request details" do
|
56
|
+
request_hash = @data.to_hash['request']
|
57
|
+
request_hash['url'].should == 'http://localhost:9292/?cockle=shell&bay=cool'
|
58
|
+
request_hash['parameters'].should == {"cockle"=>"shell", "bay"=>"cool"}
|
59
|
+
request_hash['request_method'].should == 'GET'
|
60
|
+
request_hash['remote_ip'].should == '127.0.0.1'
|
61
|
+
request_hash['headers'].should == {"HTTP_HOST"=>"localhost:9292", "HTTP_ACCEPT"=>"*/*", "HTTP_USER_AGENT"=>"curl/7.19.6 (i386-apple-darwin9.8.0) libcurl/7.19.6 zlib/1.2.3", "HTTP_VERSION"=>"HTTP/1.1"}
|
62
|
+
request_hash['session'].should == {}
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should capture client detais" do
|
66
|
+
client_hash = @data.to_hash['client']
|
67
|
+
client_hash['name'].should == Exceptional::CLIENT_NAME
|
68
|
+
client_hash['version'].should == Exceptional::VERSION
|
69
|
+
client_hash['protocol_version'].should == Exceptional::PROTOCOL_VERSION
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should captire application environment" do
|
73
|
+
env_hash = @data.to_hash['application_environment']
|
74
|
+
env_hash['env'].should_not be_empty #execution dependent
|
75
|
+
env_hash['libraries_loaded'].should_not be_empty #execution dependent
|
76
|
+
env_hash['language'].should == 'ruby' #execution dependent
|
77
|
+
|
78
|
+
env_hash['language_version'].should_not be_empty #execution dependent
|
79
|
+
env_hash['environment'].should == 'test'
|
80
|
+
env_hash['application_root_directory'].should_not be_empty
|
81
|
+
env_hash['run_as_user'].should_not be_empty
|
82
|
+
env_hash['host'].should_not be_empty
|
83
|
+
|
84
|
+
env_hash['framework'].should == 'rack'
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
require 'rack/mock'
|
3
|
+
|
4
|
+
class ExceptionalTestError < StandardError
|
5
|
+
end
|
6
|
+
|
7
|
+
describe Rack::Exceptional do
|
8
|
+
|
9
|
+
before(:each) do
|
10
|
+
Exceptional::Config.should_receive(:load)
|
11
|
+
@error = ExceptionalTestError.new
|
12
|
+
@app = lambda { |env| raise @error, 'Whoops!' }
|
13
|
+
@env = env = Rack::MockRequest.env_for("/foo")
|
14
|
+
end
|
15
|
+
|
16
|
+
it 're-raises errors caught in the middleware' do
|
17
|
+
rr = Rack::Exceptional.new(@app)
|
18
|
+
Exceptional::Catcher.should_receive(:handle_with_rack)
|
19
|
+
lambda { rr.call(@env)}.should raise_error(ExceptionalTestError)
|
20
|
+
end
|
21
|
+
end
|
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.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Contrast
|
@@ -9,11 +9,11 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-01-
|
12
|
+
date: 2010-01-26 00:00:00 +00:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
16
|
-
description: Exceptional is the
|
16
|
+
description: Exceptional is the Ruby gem 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.
|
17
17
|
email: hello@contrast.ie
|
18
18
|
executables:
|
19
19
|
- exceptional
|
@@ -27,9 +27,11 @@ files:
|
|
27
27
|
- lib/exceptional/config.rb
|
28
28
|
- lib/exceptional/controller_exception_data.rb
|
29
29
|
- lib/exceptional/exception_data.rb
|
30
|
+
- lib/exceptional/integration/rack.rb
|
30
31
|
- lib/exceptional/integration/rails.rb
|
31
32
|
- lib/exceptional/integration/tester.rb
|
32
33
|
- lib/exceptional/log_factory.rb
|
34
|
+
- lib/exceptional/rack_exception_data.rb
|
33
35
|
- lib/exceptional/remote.rb
|
34
36
|
- lib/exceptional/startup.rb
|
35
37
|
- lib/exceptional.rb
|
@@ -37,12 +39,14 @@ files:
|
|
37
39
|
- spec/exceptional/catcher_spec.rb
|
38
40
|
- spec/exceptional/config_spec.rb
|
39
41
|
- spec/exceptional/exception_data_spec.rb
|
42
|
+
- spec/exceptional/rack_exception_data_spec.rb
|
40
43
|
- spec/exceptional/remote_spec.rb
|
41
44
|
- spec/exceptional/startup_spec.rb
|
42
45
|
- spec/exceptional_rescue_spec.rb
|
43
46
|
- spec/fixtures/exceptional.yml
|
44
47
|
- spec/fixtures/exceptional_old.yml
|
45
48
|
- spec/ginger_scenarios.rb
|
49
|
+
- spec/rack_integration_spec.rb
|
46
50
|
- spec/rails_integration_spec.rb
|
47
51
|
- spec/spec_helper.rb
|
48
52
|
- spec/standalone_spec.rb
|
@@ -78,6 +82,6 @@ rubyforge_project: exceptional
|
|
78
82
|
rubygems_version: 1.3.5
|
79
83
|
signing_key:
|
80
84
|
specification_version: 3
|
81
|
-
summary:
|
85
|
+
summary: getexceptional.com is a hosted service for tracking errors in your Ruby/Rails/Rack apps
|
82
86
|
test_files: []
|
83
87
|
|