exceptiontrap 0.0.1.alpha → 0.0.2.alpha
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -1
- data/exceptiontrap.gemspec +2 -2
- data/generators/exceptiontrap/exceptiontrap_generator.rb +2 -3
- data/generators/exceptiontrap/templates/exceptiontrap.yml +1 -0
- data/lib/exceptiontrap/catcher.rb +0 -2
- data/lib/exceptiontrap/config.rb +16 -41
- data/lib/exceptiontrap/data.rb +62 -59
- data/lib/exceptiontrap/notifier.rb +24 -9
- data/lib/exceptiontrap/rack.rb +3 -3
- data/lib/exceptiontrap/railtie.rb +3 -3
- data/lib/exceptiontrap/version.rb +1 -1
- data/lib/exceptiontrap.rb +7 -7
- data/lib/generators/exceptiontrap/exceptiontrap_generator.rb +9 -9
- data/lib/generators/exceptiontrap/templates/exceptiontrap.yml +1 -0
- metadata +23 -45
data/Gemfile
CHANGED
data/exceptiontrap.gemspec
CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |s|
|
|
8
8
|
s.authors = ["tbuehl"]
|
9
9
|
s.email = ["tbuehl@itm-labs.de"]
|
10
10
|
s.homepage = "http://exceptiontrap.com"
|
11
|
-
s.summary = %q{
|
12
|
-
s.description = %q{The
|
11
|
+
s.summary = %q{Exception notifier, used to report your apps exceptions to the exceptiontrap webservice}
|
12
|
+
s.description = %q{Exception notifier. The Gem catches your applications exceptions and sends those to the exceptiontrap webservice hosted at http://exceptiontrap.com}
|
13
13
|
|
14
14
|
s.rubyforge_project = "exceptiontrap"
|
15
15
|
|
data/lib/exceptiontrap/config.rb
CHANGED
@@ -2,73 +2,48 @@ module Exceptiontrap
|
|
2
2
|
class Config
|
3
3
|
class << self
|
4
4
|
DEFAULTS = {
|
5
|
-
:
|
6
|
-
:
|
5
|
+
:enabled_environments => %w(production),
|
6
|
+
:ignored_exceptions => %w(ActiveRecord::RecordNotFound ActionController::RoutingError),
|
7
|
+
:filtered_params => %w(password s3-key),
|
8
|
+
:ssl => false
|
7
9
|
}
|
8
10
|
|
9
|
-
|
10
|
-
|
11
|
-
def load(config_file=nil)
|
11
|
+
def load(config_file = nil)
|
12
12
|
if (config_file && File.file?(config_file))
|
13
13
|
begin
|
14
14
|
config = YAML::load(File.open(config_file))
|
15
|
-
env_config = config[application_environment] || {}
|
16
15
|
|
17
|
-
@api_key = config['api-key']
|
18
|
-
@ssl = config['ssl']
|
19
|
-
@
|
20
|
-
@
|
21
|
-
@
|
16
|
+
@api_key = config['api-key']
|
17
|
+
@ssl = config['ssl']
|
18
|
+
@ignored_exceptions = config['ignoreExceptions']
|
19
|
+
@enabled_environments = config['enabledEnvironments']
|
20
|
+
@filtered_params = config['filterParams']
|
22
21
|
rescue Exception => e
|
23
|
-
raise ConfigException.new("Unable to load configuration #{config_file}
|
22
|
+
raise ConfigException.new("Unable to load configuration #{config_file} : #{e.message}")
|
24
23
|
end
|
25
24
|
end
|
26
25
|
end
|
27
26
|
|
28
27
|
def api_key
|
29
|
-
|
28
|
+
@api_key
|
30
29
|
end
|
31
30
|
|
32
31
|
def enabled_environments
|
33
|
-
@
|
32
|
+
@enabled_environments ||= DEFAULTS[:enabled_environments]
|
34
33
|
end
|
35
34
|
|
36
35
|
def ignored_exceptions
|
37
|
-
@
|
36
|
+
@ignored_exceptions ||= DEFAULTS[:ignored_exceptions]
|
38
37
|
end
|
39
38
|
|
40
39
|
def filtered_params
|
41
|
-
@
|
42
|
-
end
|
43
|
-
|
44
|
-
def application_environment
|
45
|
-
ENV['RACK_ENV'] || ENV['RAILS_ENV'] || 'development'
|
46
|
-
end
|
47
|
-
|
48
|
-
def should_send_to_api?
|
49
|
-
@enabled ||= DEFAULTS[:disabled_by_default].include?(application_environment) ? false : true
|
50
|
-
end
|
51
|
-
|
52
|
-
def application_root
|
53
|
-
defined?(Rails.root) ? Rails.root : Dir.pwd
|
40
|
+
@filtered_params ||= DEFAULTS[:filtered_params]
|
54
41
|
end
|
55
42
|
|
56
|
-
def
|
43
|
+
def use_ssl?
|
57
44
|
@ssl ||= DEFAULTS[:ssl]
|
58
45
|
end
|
59
46
|
|
60
|
-
def remote_host
|
61
|
-
@remote_host ||= DEFAULTS[:remote_host_http]
|
62
|
-
end
|
63
|
-
|
64
|
-
def remote_port
|
65
|
-
@remote_port ||= ssl? ? 443 : 80
|
66
|
-
end
|
67
|
-
|
68
|
-
def reset
|
69
|
-
@enabled = @ssl = @api_key = nil
|
70
|
-
end
|
71
|
-
|
72
47
|
end
|
73
48
|
end
|
74
49
|
end
|
data/lib/exceptiontrap/data.rb
CHANGED
@@ -1,106 +1,93 @@
|
|
1
1
|
module Exceptiontrap
|
2
2
|
class Data
|
3
3
|
class << self
|
4
|
-
# TODO: Remove the duplication
|
4
|
+
# TODO: Remove the duplication or separate classes
|
5
5
|
# Creates Notification Data for action controller requests (Rails 2)
|
6
6
|
def rails2_data(exception, request, session, response)
|
7
7
|
data = {
|
8
8
|
'notifier' => NOTIFIER_NAME,
|
9
|
-
'api-key' => Config.api_key,
|
10
9
|
'name' => exception.class.name,
|
11
10
|
'message' => exception.message,
|
12
|
-
'
|
13
|
-
'
|
14
|
-
'
|
15
|
-
'
|
16
|
-
'
|
11
|
+
'location' => location(exception),
|
12
|
+
'root' => application_root.to_s,
|
13
|
+
'app_environment' => application_environment,
|
14
|
+
'request_uri' => request.url || REQUEST_URI,
|
15
|
+
'request_params' => clean_params(request.params),
|
16
|
+
'request_session' => clean_params(extrap_session_data(session)),
|
17
17
|
'environment' => clean_params(request.env),
|
18
|
-
'trace' => clean_backtrace(exception
|
19
|
-
'
|
18
|
+
'trace' => clean_backtrace(exception.backtrace),
|
19
|
+
'request_components' => { :controller => request.params[:controller], :action => request.params[:action] }
|
20
20
|
}
|
21
21
|
end
|
22
22
|
|
23
23
|
# Creates Notification Data for rack requests (Rails 3)
|
24
24
|
def rack_data(exception, env)
|
25
|
-
components = {
|
25
|
+
components = {}
|
26
26
|
if env["action_dispatch.request.parameters"] != nil
|
27
|
-
components[:controller] = env[
|
28
|
-
components[:action] = env[
|
29
|
-
components[:module] = env[
|
27
|
+
components[:controller] = env['action_dispatch.request.parameters'][:controller] || nil
|
28
|
+
components[:action] = env['action_dispatch.request.parameters'][:action] || nil
|
29
|
+
components[:module] = env['action_dispatch.request.parameters'][:module] || nil
|
30
30
|
end
|
31
31
|
|
32
32
|
data = {
|
33
33
|
'notifier' => NOTIFIER_NAME,
|
34
|
-
'api-key' => Config.api_key,
|
35
34
|
'name' => exception.class.name,
|
36
35
|
'message' => exception.message,
|
37
|
-
'
|
38
|
-
'
|
39
|
-
'
|
40
|
-
'
|
41
|
-
'
|
36
|
+
'location' => location(exception),
|
37
|
+
'root' => application_root.to_s,
|
38
|
+
'app_environment' => application_environment,
|
39
|
+
'request_uri' => env['REQUEST_URI'],
|
40
|
+
'request_params' => clean_params(env['action_dispatch.request.parameters']),
|
41
|
+
'request_session' => clean_params(extrap_session_data(env['rack.session'])),
|
42
42
|
'environment' => clean_params(env),
|
43
|
-
'trace' => clean_backtrace(exception
|
44
|
-
'
|
43
|
+
'trace' => clean_backtrace(exception.backtrace),
|
44
|
+
'request_components' => components
|
45
45
|
}
|
46
46
|
end
|
47
47
|
|
48
|
-
|
48
|
+
# Cleanup data
|
49
49
|
def clean_params(params)
|
50
50
|
return if params == nil
|
51
|
-
|
52
51
|
params = normalize_data(params)
|
53
52
|
params = filter_params(params)
|
54
|
-
params
|
55
|
-
end
|
56
|
-
|
57
|
-
# Deletes params from env / set in config file
|
58
|
-
def remove_params
|
59
|
-
remove_params = ["rack.request.form_hash", "rack.request.form_vars", "rack.request.form_hash"]
|
60
53
|
end
|
61
54
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
hash.each do |key, value|
|
68
|
-
key_s = key.to_s.dup
|
69
|
-
key_s.sub!("_", "") if key_s[0].chr == "_"
|
70
|
-
key_s.sub!("_", "") if key_s[0].chr == "_"
|
71
|
-
|
72
|
-
if value.respond_to?(:to_hash) # if hash, normalize these too
|
73
|
-
new_hash[key_s] = normalize_data(value.to_hash)
|
74
|
-
else
|
75
|
-
new_hash[key_s] = value.to_s
|
76
|
-
end
|
55
|
+
def clean_backtrace(backtrace)
|
56
|
+
if Rails.respond_to?(:backtrace_cleaner)
|
57
|
+
Rails.backtrace_cleaner.send(:filter, backtrace)
|
58
|
+
else
|
59
|
+
backtrace
|
77
60
|
end
|
61
|
+
end
|
78
62
|
|
79
|
-
|
63
|
+
# Deletes params from env / set in config file
|
64
|
+
def remove_params
|
65
|
+
remove_params = ['rack.request.form_hash', 'rack.request.form_vars']
|
80
66
|
end
|
81
67
|
|
82
68
|
# Replaces parameter values with a string / set in config file
|
83
69
|
def filter_params(params)
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
70
|
+
return params unless Config.filtered_params
|
71
|
+
|
72
|
+
params.each do |k, v|
|
73
|
+
if filter_key?(k)
|
74
|
+
params[k] = '[FILTERED]'
|
75
|
+
elsif v.respond_to?(:to_hash)
|
76
|
+
filter_params(params[k])
|
91
77
|
end
|
92
78
|
end
|
79
|
+
|
93
80
|
params
|
94
81
|
end
|
95
82
|
|
96
83
|
# Check, if a key should be filtered
|
97
84
|
def filter_key?(key)
|
98
85
|
Config.filtered_params.any? do |filter|
|
99
|
-
key.to_s.include?(filter.to_s)
|
86
|
+
key.to_s == filter.to_s # key.to_s.include?(filter.to_s)
|
100
87
|
end
|
101
88
|
end
|
102
89
|
|
103
|
-
|
90
|
+
# Retrieve data
|
104
91
|
def extrap_session_data(session)
|
105
92
|
return if session == nil
|
106
93
|
if session.respond_to?(:to_hash)
|
@@ -110,6 +97,10 @@ module Exceptiontrap
|
|
110
97
|
end
|
111
98
|
end
|
112
99
|
|
100
|
+
def location(exception)
|
101
|
+
#TODO: Implement
|
102
|
+
end
|
103
|
+
|
113
104
|
def application_environment
|
114
105
|
ENV['RACK_ENV'] || ENV['RAILS_ENV'] || 'development'
|
115
106
|
end
|
@@ -118,12 +109,24 @@ module Exceptiontrap
|
|
118
109
|
defined?(Rails.root) ? Rails.root : Dir.pwd
|
119
110
|
end
|
120
111
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
112
|
+
# Trims first underscore from keys, to prevent "malformed" rails XML-tags
|
113
|
+
def normalize_data(hash)
|
114
|
+
new_hash = {}
|
115
|
+
|
116
|
+
# TODO: Do this nicer
|
117
|
+
hash.each do |key, value|
|
118
|
+
# key_s = key.to_s.dup
|
119
|
+
# key_s.sub!("_", "") if key_s[0].chr == "_"
|
120
|
+
# key_s.sub!("_", "") if key_s[0].chr == "_"
|
121
|
+
|
122
|
+
if value.respond_to?(:to_hash) # if hash, normalize these too
|
123
|
+
new_hash[key] = normalize_data(value.to_hash)
|
124
|
+
else
|
125
|
+
new_hash[key] = value.to_s
|
126
|
+
end
|
126
127
|
end
|
128
|
+
|
129
|
+
new_hash
|
127
130
|
end
|
128
131
|
|
129
132
|
end
|
@@ -2,33 +2,48 @@ module Exceptiontrap
|
|
2
2
|
class Notifier
|
3
3
|
class << self
|
4
4
|
def notify(data)
|
5
|
-
puts
|
5
|
+
puts 'DEBUG: Notify Exception'
|
6
6
|
|
7
7
|
@data = data
|
8
|
-
|
9
|
-
send_problem(
|
8
|
+
serialized_data = { :problem => data }.to_json
|
9
|
+
send_problem(serialized_data) unless ignore_exception?
|
10
10
|
end
|
11
11
|
|
12
|
-
def send_problem(
|
13
|
-
puts
|
12
|
+
def send_problem(serialized_data)
|
13
|
+
puts 'DEBUG: Send Exception'
|
14
14
|
|
15
|
-
url = URI.parse(NOTIFICATION_URL)
|
16
|
-
|
15
|
+
url = URI.parse((Config.use_ssl? ? 'https://' : 'http://') << NOTIFICATION_URL)
|
16
|
+
client = prepare_client(url)
|
17
|
+
|
18
|
+
headers = HEADERS
|
19
|
+
headers['X-Api-Key'] = Config.api_key
|
17
20
|
|
18
21
|
response = begin
|
19
|
-
|
22
|
+
client.post(url.path, serialized_data, headers)
|
20
23
|
rescue TimeoutError => e
|
21
|
-
puts
|
24
|
+
puts 'ERROR: Timeout while contacting Exceptiontrap.'
|
22
25
|
nil
|
23
26
|
rescue Exception => e
|
24
27
|
puts "ERROR: Error on sending: #{e.class} - #{e.message}"
|
25
28
|
end
|
26
29
|
end
|
27
30
|
|
31
|
+
private
|
28
32
|
def ignore_exception?
|
29
33
|
Config.ignored_exceptions.include?(@data['name'])
|
30
34
|
end
|
31
35
|
|
36
|
+
def prepare_client(url)
|
37
|
+
if Config.use_ssl?
|
38
|
+
client = Net::HTTP.new(url.host, url.port || 443)
|
39
|
+
client.use_ssl = true
|
40
|
+
client.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
41
|
+
else
|
42
|
+
client = Net::HTTP.new(url.host, url.port || 80)
|
43
|
+
end
|
44
|
+
|
45
|
+
client
|
46
|
+
end
|
32
47
|
end
|
33
48
|
end
|
34
49
|
end
|
data/lib/exceptiontrap/rack.rb
CHANGED
@@ -6,10 +6,10 @@ module Exceptiontrap
|
|
6
6
|
|
7
7
|
def call(env)
|
8
8
|
begin
|
9
|
-
puts
|
9
|
+
puts 'DEBUG: Begin Exceptiontrap::Rack'
|
10
10
|
response = @app.call(env)
|
11
11
|
rescue Exception => raised
|
12
|
-
puts
|
12
|
+
puts 'DEBUG: Raised Exceptiontrap::Rack::Exception'
|
13
13
|
data = Exceptiontrap::Data.rack_data(raised, env)
|
14
14
|
Exceptiontrap::Notifier.notify(data)
|
15
15
|
raise
|
@@ -19,4 +19,4 @@ module Exceptiontrap
|
|
19
19
|
end
|
20
20
|
|
21
21
|
end
|
22
|
-
end
|
22
|
+
end
|
@@ -4,12 +4,12 @@ require 'rails'
|
|
4
4
|
|
5
5
|
module Exceptiontrap
|
6
6
|
class ExceptiontrapRailtie < Rails::Railtie
|
7
|
-
initializer
|
8
|
-
Exceptiontrap::Config.load(File.join(Rails.root,
|
7
|
+
initializer 'exceptiontrap.middleware' do |app|
|
8
|
+
Exceptiontrap::Config.load(File.join(Rails.root, '/config/exceptiontrap.yml'))
|
9
9
|
if Config.enabled_environments.include?(Exceptiontrap::Data.application_environment)
|
10
10
|
# puts "-> Activated Exceptiontrap::Rack for Rails 3 (Railtie)"
|
11
11
|
app.config.middleware.insert_after 'ActionDispatch::ShowExceptions', 'Exceptiontrap::Rack'
|
12
12
|
end
|
13
13
|
end
|
14
14
|
end
|
15
|
-
end
|
15
|
+
end
|
data/lib/exceptiontrap.rb
CHANGED
@@ -12,19 +12,19 @@ require 'exceptiontrap/railtie' if defined?(Rails::Railtie)
|
|
12
12
|
|
13
13
|
# Exceptiontrap
|
14
14
|
module Exceptiontrap
|
15
|
-
API_VERSION =
|
16
|
-
NOTIFIER_NAME =
|
17
|
-
|
18
|
-
|
15
|
+
API_VERSION = '1'
|
16
|
+
NOTIFIER_NAME = 'exceptiontrap-rails'
|
17
|
+
NOTIFICATION_URL = 'alpha.exceptiontrap.com/notifier/api/v1/problems'
|
18
|
+
DEPLOYMENT_URL = 'alpha.exceptiontrap.com/notifier/api/v1/deployments'
|
19
19
|
|
20
20
|
HEADERS = {
|
21
|
-
'Content-type' => '
|
22
|
-
'Accept' => '
|
21
|
+
'Content-type' => 'application/json',
|
22
|
+
'Accept' => 'application/json'
|
23
23
|
}
|
24
24
|
|
25
25
|
# Load for Rails 2.3 (Rack and Exceptiontrap::Catcher)
|
26
26
|
if !defined?(Rails::Railtie) && defined?(Rails.configuration) && Rails.configuration.respond_to?(:middleware)
|
27
|
-
Exceptiontrap::Config.load(File.join(Rails.root,
|
27
|
+
Exceptiontrap::Config.load(File.join(Rails.root, '/config/exceptiontrap.yml'))
|
28
28
|
|
29
29
|
if Config.enabled_environments.include?(Exceptiontrap::Data.application_environment)
|
30
30
|
if defined?(ActionController::Base) && !ActionController::Base.include?(Exceptiontrap::Catcher)
|
@@ -2,27 +2,27 @@ require 'rails/generators'
|
|
2
2
|
|
3
3
|
class ExceptiontrapGenerator < Rails::Generators::Base
|
4
4
|
desc "Run this generator to create the Exceptiontrap config file"
|
5
|
-
|
6
|
-
class_option :api_key, :aliases =>
|
7
|
-
|
5
|
+
|
6
|
+
class_option :api_key, :aliases => '-k', :type => :string, :desc => 'Your Exceptiontrap API key'
|
7
|
+
|
8
8
|
def self.source_root
|
9
9
|
@source_root ||= File.join(File.dirname(__FILE__), 'templates')
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
def install
|
13
13
|
if !options[:api_key]
|
14
|
-
puts
|
14
|
+
puts 'You have to pass --api-key or create config/exceptiontrap.yml manually'
|
15
15
|
exit
|
16
16
|
end
|
17
17
|
#copy_config
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
def api_key
|
21
|
-
|
21
|
+
s = "#{options[:api_key]}"
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
def copy_config
|
25
|
-
puts
|
25
|
+
puts 'Copying config file to your app'
|
26
26
|
template 'exceptiontrap.yml', 'config/exceptiontrap.yml'
|
27
27
|
end
|
28
28
|
end
|
metadata
CHANGED
@@ -1,35 +1,24 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: exceptiontrap
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2.alpha
|
5
5
|
prerelease: 6
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 0
|
9
|
-
- 1
|
10
|
-
- alpha
|
11
|
-
version: 0.0.1.alpha
|
12
6
|
platform: ruby
|
13
|
-
authors:
|
7
|
+
authors:
|
14
8
|
- tbuehl
|
15
9
|
autorequire:
|
16
10
|
bindir: bin
|
17
11
|
cert_chain: []
|
18
|
-
|
19
|
-
date: 2012-01-04 00:00:00 +01:00
|
20
|
-
default_executable:
|
12
|
+
date: 2012-08-18 00:00:00.000000000 Z
|
21
13
|
dependencies: []
|
22
|
-
|
23
|
-
|
24
|
-
email:
|
14
|
+
description: Exception notifier. The Gem catches your applications exceptions and
|
15
|
+
sends those to the exceptiontrap webservice hosted at http://exceptiontrap.com
|
16
|
+
email:
|
25
17
|
- tbuehl@itm-labs.de
|
26
18
|
executables: []
|
27
|
-
|
28
19
|
extensions: []
|
29
|
-
|
30
20
|
extra_rdoc_files: []
|
31
|
-
|
32
|
-
files:
|
21
|
+
files:
|
33
22
|
- .gitignore
|
34
23
|
- Gemfile
|
35
24
|
- MIT-LICENSE
|
@@ -56,42 +45,31 @@ files:
|
|
56
45
|
- test/exceptiontrap_test.rb
|
57
46
|
- test/test_helper.rb
|
58
47
|
- uninstall.rb
|
59
|
-
has_rdoc: true
|
60
48
|
homepage: http://exceptiontrap.com
|
61
49
|
licenses: []
|
62
|
-
|
63
50
|
post_install_message:
|
64
51
|
rdoc_options: []
|
65
|
-
|
66
|
-
require_paths:
|
52
|
+
require_paths:
|
67
53
|
- lib
|
68
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
69
55
|
none: false
|
70
|
-
requirements:
|
71
|
-
- -
|
72
|
-
- !ruby/object:Gem::Version
|
73
|
-
|
74
|
-
|
75
|
-
- 0
|
76
|
-
version: "0"
|
77
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ! '>='
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '0'
|
60
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
61
|
none: false
|
79
|
-
requirements:
|
80
|
-
- -
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
hash: 25
|
83
|
-
segments:
|
84
|
-
- 1
|
85
|
-
- 3
|
86
|
-
- 1
|
62
|
+
requirements:
|
63
|
+
- - ! '>'
|
64
|
+
- !ruby/object:Gem::Version
|
87
65
|
version: 1.3.1
|
88
66
|
requirements: []
|
89
|
-
|
90
67
|
rubyforge_project: exceptiontrap
|
91
|
-
rubygems_version: 1.
|
68
|
+
rubygems_version: 1.8.24
|
92
69
|
signing_key:
|
93
70
|
specification_version: 3
|
94
|
-
summary:
|
95
|
-
|
71
|
+
summary: Exception notifier, used to report your apps exceptions to the exceptiontrap
|
72
|
+
webservice
|
73
|
+
test_files:
|
96
74
|
- test/exceptiontrap_test.rb
|
97
75
|
- test/test_helper.rb
|