markbates-hoptoad_notifier 1.2

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/INSTALL ADDED
@@ -0,0 +1,55 @@
1
+ HoptoadNotifier
2
+ ===============
3
+
4
+ This is the notifier plugin for integrating apps with Hoptoad.
5
+
6
+ When an uncaught exception occurs, HoptoadNotifier will POST the relevant data
7
+ to the Hoptoad server specified in your environment.
8
+
9
+
10
+ INSTALLATION
11
+ ------------
12
+
13
+ REMOVE EXCEPTION_NOTIFIER
14
+
15
+ In your ApplicationController, REMOVE this line:
16
+
17
+ include ExceptionNotifiable
18
+
19
+ In your config/environment* files, remove all references to ExceptionNotifier
20
+
21
+ Remove the vendor/plugins/exception_notifier directory.
22
+
23
+ INSTALL HOPTOAD_NOTIFIER
24
+
25
+ From your project's RAILS_ROOT, run:
26
+
27
+ script/plugin install git://github.com/thoughtbot/hoptoad_notifier.git
28
+
29
+ CONFIGURATION
30
+
31
+ You should have something like this in config/initializers/hoptoad.rb.
32
+
33
+ HoptoadNotifier.configure do |config|
34
+ config.api_key = '1234567890abcdef'
35
+ end
36
+
37
+ (Please note that this configuration should be in a global configuration, and
38
+ is *not* enrivonment-specific. Hoptoad is smart enough to know what errors are
39
+ caused by what environments, so your staging errors don't get mixed in with
40
+ your production errors.)
41
+
42
+ After this is in place, all exceptions will be logged to Hoptoad where they can
43
+ be aggregated, filtered, sorted, analyzed, massaged, and searched.
44
+
45
+ ** NOTE FOR RAILS 1.2.* USERS: **
46
+ You will need to copy the hoptoad_notifier_tasks.rake file into your
47
+ RAILS_ROOT/lib/tasks directory in order for the following to work:
48
+
49
+ You can test that hoptoad is working in your production environment by using
50
+ this rake task (from RAILS_ROOT):
51
+
52
+ rake hoptoad:test
53
+
54
+ If everything is configured properly, that task will send a notice to hoptoad
55
+ which will be visible immediately.
data/README ADDED
@@ -0,0 +1,171 @@
1
+ HoptoadNotifier
2
+ ===============
3
+
4
+ This is the notifier plugin for integrating apps with Hoptoad.
5
+
6
+ When an uncaught exception occurs, HoptoadNotifier will POST the relevant data
7
+ to the Hoptoad server specified in your environment.
8
+
9
+ INSTALLATION
10
+ ------------
11
+
12
+ REMOVE EXCEPTION_NOTIFIER
13
+
14
+ In your ApplicationController, REMOVE this line:
15
+
16
+ include ExceptionNotifiable
17
+
18
+ In your config/environment* files, remove all references to ExceptionNotifier
19
+
20
+ Remove the vendor/plugins/exception_notifier directory.
21
+
22
+ INSTALL HOPTOAD_NOTIFIER
23
+
24
+ From your project's RAILS_ROOT, run:
25
+
26
+ script/plugin install git://github.com/thoughtbot/hoptoad_notifier.git
27
+
28
+ CONFIGURATION
29
+
30
+ You should have something like this in config/initializers/hoptoad.rb.
31
+
32
+ HoptoadNotifier.configure do |config|
33
+ config.api_key = '1234567890abcdef'
34
+ end
35
+
36
+ (Please note that this configuration should be in a global configuration, and
37
+ is *not* environment-specific. Hoptoad is smart enough to know what errors are
38
+ caused by what environments, so your staging errors don't get mixed in with
39
+ your production errors.)
40
+
41
+ That should be it! Now all exceptions will be logged to Hoptoad where they can
42
+ be aggregated, filtered, sorted, analyzed, massaged, and searched. In previous
43
+ releases you had to include HoptoadNotifier::Catcher into your
44
+ ApplicationController, but the plugin takes care of that now.
45
+
46
+ ** NOTE FOR RAILS 1.2.* USERS: **
47
+ You will need to copy the hoptoad_notifier_tasks.rake file into your
48
+ RAILS_ROOT/lib/tasks directory in order for the following to work:
49
+
50
+ You can test that hoptoad is working in your production environment by using
51
+ this rake task (from RAILS_ROOT):
52
+
53
+ rake hoptoad:test
54
+
55
+ If everything is configured properly, that task will send a notice to hoptoad
56
+ which will be visible immediately.
57
+
58
+ USAGE
59
+
60
+ For the most part, hoptoad works for itself. Once you've included the notifier
61
+ in your ApplicationController (which is now done automatically by the plugin),
62
+ all errors will be rescued by the #rescue_action_in_public provided by the plugin.
63
+
64
+ If you want to log arbitrary things which you've rescued yourself from a
65
+ controller, you can do something like this:
66
+
67
+ ...
68
+ rescue => ex
69
+ notify_hoptoad(ex)
70
+ flash[:failure] = 'Encryptions could not be rerouted, try again.'
71
+ end
72
+ ...
73
+
74
+ The #notify_hoptoad call will send the notice over to hoptoad for later
75
+ analysis.
76
+
77
+ GOING BEYOND EXCEPTIONS
78
+
79
+ You can also pass a hash to notify_hoptoad method and store whatever you want, not just an exception. And you can also use it anywhere, not just in controllers:
80
+
81
+ begin
82
+ params = {
83
+ # params that you pass to a method that can throw an exception
84
+ }
85
+ my_unpredicable_method(params)
86
+ rescue => e
87
+ HoptoadNotifier.notify(
88
+ :error_class => "Special Error",
89
+ :error_message => "Special Error: #{e.message}",
90
+ :request => { :params => params }
91
+ )
92
+ end
93
+
94
+ While in your controllers you use the notify_hoptoad method, anywhere else in your code, use HoptoadNotifier.notify. Hoptoad will get all the information about the error itself. As for a hash, these are the keys you should pass:
95
+
96
+ * :error_class – Use this to group similar errors together. When Hoptoad catches an exception it sends the class name of that exception object.
97
+ * :error_message – This is the title of the error you see in the errors list. For exceptions it is "#{exception.class.name}: #{exception.message}"
98
+ * :request – While there are several ways to send additional data to Hoptoad, passing a Hash with :params key as :request as in the example above is the most common use case. When Hoptoad catches an exception in a controller, the actual HTTP client request is being sent using this key.
99
+
100
+ Hoptoad merges the hash you pass with these default options:
101
+
102
+ def default_notice_options
103
+ {
104
+ :api_key => HoptoadNotifier.api_key,
105
+ :error_message => 'Notification',
106
+ :backtrace => caller,
107
+ :request => {},
108
+ :session => {},
109
+ :environment => ENV.to_hash
110
+ }
111
+ end
112
+
113
+ You can override any of those parameters.
114
+
115
+ FILTERING
116
+
117
+ You can specify a whitelist of errors, that Hoptoad will not report on. Use
118
+ this feature when you are so apathetic to certain errors that you don't want
119
+ them even logged.
120
+
121
+ This filter will only be applied to automatic notifications, not manual
122
+ notifications (when #notify is called directly).
123
+
124
+ Hoptoad ignores the following exceptions by default:
125
+ ActiveRecord::RecordNotFound
126
+ ActionController::RoutingError
127
+ ActionController::InvalidAuthenticityToken
128
+ CGI::Session::CookieStore::TamperedWithCookie
129
+
130
+ To ignore errors in addition to those, specify their names in your Hoptoad
131
+ configuration block.
132
+
133
+ HoptoadNotifier.configure do |config|
134
+ config.api_key = '1234567890abcdef'
135
+ config.ignore << ActiveRecord::IgnoreThisError
136
+ end
137
+
138
+ To ignore *only* certain errors (and override the defaults), use the
139
+ #ignore_only attribute.
140
+
141
+ HoptoadNotifier.configure do |config|
142
+ config.api_key = '1234567890abcdef'
143
+ config.ignore_only = [ActiveRecord::IgnoreThisError]
144
+ end
145
+
146
+ To ignore certain user agents, add in the #ignore_user_agent attribute as a
147
+ string or regexp:
148
+
149
+ HoptoadNotifier.configure do |config|
150
+ config.api_key = '1234567890abcdef'
151
+ config.ignore_user_agent << /Ignored/
152
+ config.ignore_user_agent << 'IgnoredUserAgent'
153
+ end
154
+
155
+ TESTING
156
+
157
+ When you run your tests, you might notice that the hoptoad service is recording
158
+ notices generated using #notify when you don't expect it to. You can
159
+ use code like this in your test_helper.rb to redefine that method so those
160
+ errors are not reported while running tests.
161
+
162
+ module HoptoadNotifier::Catcher
163
+ def notify(thing)
164
+ # do nothing.
165
+ end
166
+ end
167
+
168
+ THANKS
169
+
170
+ Thanks to Eugene Bolshakov for the excellent write-up on GOING BEYOND EXCEPTIONS, which we have included above.
171
+
data/Rakefile ADDED
@@ -0,0 +1,30 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => :test
7
+
8
+ desc 'Test the hoptoad_notifier plugin.'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.pattern = 'test/**/*_test.rb'
12
+ t.verbose = true
13
+ end
14
+
15
+ desc 'Generate documentation for the hoptoad_notifier plugin.'
16
+ Rake::RDocTask.new(:rdoc) do |rdoc|
17
+ rdoc.rdoc_dir = 'rdoc'
18
+ rdoc.title = 'HoptoadNotifier'
19
+ rdoc.options << '--line-numbers' << '--inline-source'
20
+ rdoc.rdoc_files.include('README')
21
+ rdoc.rdoc_files.include('lib/**/*.rb')
22
+ end
23
+
24
+ desc 'Run ginger tests'
25
+ task :ginger do
26
+ $LOAD_PATH << File.join(*%w[vendor ginger lib])
27
+ ARGV.clear
28
+ ARGV << 'test'
29
+ load File.join(*%w[vendor ginger bin ginger])
30
+ end
@@ -0,0 +1,386 @@
1
+ require 'net/http'
2
+ require 'net/https'
3
+ require 'rubygems'
4
+ require 'active_support'
5
+
6
+ # Plugin for applications to automatically post errors to the Hoptoad of their choice.
7
+ module HoptoadNotifier
8
+
9
+ IGNORE_DEFAULT = ['ActiveRecord::RecordNotFound',
10
+ 'ActionController::RoutingError',
11
+ 'ActionController::InvalidAuthenticityToken',
12
+ 'CGI::Session::CookieStore::TamperedWithCookie',
13
+ 'ActionController::UnknownAction']
14
+
15
+ # Some of these don't exist for Rails 1.2.*, so we have to consider that.
16
+ IGNORE_DEFAULT.map!{|e| eval(e) rescue nil }.compact!
17
+ IGNORE_DEFAULT.freeze
18
+
19
+ IGNORE_USER_AGENT_DEFAULT = []
20
+
21
+ class << self
22
+ attr_accessor :host, :port, :secure, :api_key, :http_open_timeout, :http_read_timeout,
23
+ :proxy_host, :proxy_port, :proxy_user, :proxy_pass, :application_path,
24
+ :public_environments, :current_environment
25
+
26
+ def backtrace_filters
27
+ @backtrace_filters ||= []
28
+ end
29
+
30
+ # Takes a block and adds it to the list of backtrace filters. When the filters
31
+ # run, the block will be handed each line of the backtrace and can modify
32
+ # it as necessary. For example, by default a path matching the RAILS_ROOT
33
+ # constant will be transformed into "[RAILS_ROOT]"
34
+ def filter_backtrace &block
35
+ self.backtrace_filters << block
36
+ end
37
+
38
+ # The port on which your Hoptoad server runs.
39
+ def port
40
+ @port || (secure ? 443 : 80)
41
+ end
42
+
43
+ # The host to connect to.
44
+ def host
45
+ @host ||= 'hoptoadapp.com'
46
+ end
47
+
48
+ # The file path of the application. If RAILS_ROOT is defined it will default
49
+ # to that, otherwise the default will be FileUtils.pwd.
50
+ def application_path
51
+ @application_path ||= defined?(RAILS_ROOT) ? RAILS_ROOT : FileUtils.pwd
52
+ end
53
+
54
+ # An array of environments that are considered 'public' Default is:
55
+ # ['production', 'staging']
56
+ def public_environments
57
+ @public_environments ||= ['production', 'staging']
58
+ end
59
+
60
+ def current_environment=(environment)
61
+ @current_environment = environment
62
+ ENV['RAILS_ENV'] = environment unless ENV['RAILS_ENV']
63
+ end
64
+
65
+ def current_environment
66
+ @current_environment ||= defined?(RAILS_ENV) ? RAILS_ENV : 'development'
67
+ end
68
+
69
+ # The HTTP open timeout (defaults to 2 seconds).
70
+ def http_open_timeout
71
+ @http_open_timeout ||= 2
72
+ end
73
+
74
+ # The HTTP read timeout (defaults to 5 seconds).
75
+ def http_read_timeout
76
+ @http_read_timeout ||= 5
77
+ end
78
+
79
+ # Returns the list of errors that are being ignored. The array can be appended to.
80
+ def ignore
81
+ @ignore ||= (HoptoadNotifier::IGNORE_DEFAULT.dup)
82
+ @ignore.flatten!
83
+ @ignore
84
+ end
85
+
86
+ # Sets the list of ignored errors to only what is passed in here. This method
87
+ # can be passed a single error or a list of errors.
88
+ def ignore_only=(names)
89
+ @ignore = [names].flatten
90
+ end
91
+
92
+ # Returns the list of user agents that are being ignored. The array can be appended to.
93
+ def ignore_user_agent
94
+ @ignore_user_agent ||= (HoptoadNotifier::IGNORE_USER_AGENT_DEFAULT.dup)
95
+ @ignore_user_agent.flatten!
96
+ @ignore_user_agent
97
+ end
98
+
99
+ # Sets the list of ignored user agents to only what is passed in here. This method
100
+ # can be passed a single user agent or a list of user agents.
101
+ def ignore_user_agent_only=(names)
102
+ @ignore_user_agent = [names].flatten
103
+ end
104
+
105
+ # Returns a list of parameters that should be filtered out of what is sent to Hoptoad.
106
+ # By default, all "password" attributes will have their contents replaced.
107
+ def params_filters
108
+ @params_filters ||= %w(password)
109
+ end
110
+
111
+ def environment_filters
112
+ @environment_filters ||= %w()
113
+ end
114
+
115
+ # Call this method to modify defaults in your initializers.
116
+ #
117
+ # HoptoadNotifier.configure do |config|
118
+ # config.api_key = '1234567890abcdef'
119
+ # config.secure = false
120
+ # end
121
+ #
122
+ # NOTE: secure connections are not yet supported.
123
+ def configure
124
+ add_default_filters
125
+ yield self
126
+ if defined?(ActionController::Base) && !ActionController::Base.include?(HoptoadNotifier::Catcher)
127
+ ActionController::Base.send(:include, HoptoadNotifier::Catcher)
128
+ end
129
+ end
130
+
131
+ def protocol #:nodoc:
132
+ secure ? "https" : "http"
133
+ end
134
+
135
+ def url #:nodoc:
136
+ URI.parse("#{protocol}://#{host}:#{port}/notices/")
137
+ end
138
+
139
+ def default_notice_options #:nodoc:
140
+ {
141
+ :api_key => HoptoadNotifier.api_key,
142
+ :error_message => 'Notification',
143
+ :backtrace => caller,
144
+ :request => {},
145
+ :session => {},
146
+ :environment => ENV.to_hash
147
+ }
148
+ end
149
+
150
+ # You can send an exception manually using this method, even when you are not in a
151
+ # controller. You can pass an exception or a hash that contains the attributes that
152
+ # would be sent to Hoptoad:
153
+ # * api_key: The API key for this project. The API key is a unique identifier that Hoptoad
154
+ # uses for identification.
155
+ # * error_message: The error returned by the exception (or the message you want to log).
156
+ # * backtrace: A backtrace, usually obtained with +caller+.
157
+ # * request: The controller's request object.
158
+ # * session: The contents of the user's session.
159
+ # * environment: ENV merged with the contents of the request's environment.
160
+ def notify notice = {}
161
+ Sender.new.notify_hoptoad( notice )
162
+ end
163
+
164
+ def add_default_filters
165
+ self.backtrace_filters.clear
166
+
167
+ filter_backtrace do |line|
168
+ line.gsub(/#{application_path}/, "[RAILS_ROOT]")
169
+ end
170
+
171
+ filter_backtrace do |line|
172
+ line.gsub(/^\.\//, "")
173
+ end
174
+
175
+ filter_backtrace do |line|
176
+ if defined?(Gem)
177
+ Gem.path.inject(line) do |line, path|
178
+ line.gsub(/#{path}/, "[GEM_ROOT]")
179
+ end
180
+ end
181
+ end
182
+
183
+ filter_backtrace do |line|
184
+ line if line !~ /lib\/#{File.basename(__FILE__)}/
185
+ end
186
+ end
187
+ end
188
+
189
+ # Include this module in Controllers in which you want to be notified of errors.
190
+ module Catcher
191
+
192
+ def self.included(base) #:nodoc:
193
+ if base.instance_methods.include? 'rescue_action_in_public' and !base.instance_methods.include? 'rescue_action_in_public_without_hoptoad'
194
+ base.send(:alias_method, :rescue_action_in_public_without_hoptoad, :rescue_action_in_public)
195
+ base.send(:alias_method, :rescue_action_in_public, :rescue_action_in_public_with_hoptoad)
196
+ end
197
+ end
198
+
199
+ # Overrides the rescue_action method in ActionController::Base, but does not inhibit
200
+ # any custom processing that is defined with Rails 2's exception helpers.
201
+ def rescue_action_in_public_with_hoptoad exception
202
+ notify_hoptoad(exception) unless ignore?(exception) || ignore_user_agent?
203
+ rescue_action_in_public_without_hoptoad(exception)
204
+ end
205
+
206
+ # This method should be used for sending manual notifications while you are still
207
+ # inside the controller. Otherwise it works like HoptoadNotifier.notify.
208
+ def notify_hoptoad hash_or_exception
209
+ if public_environment?
210
+ notice = normalize_notice(hash_or_exception)
211
+ notice = clean_notice(notice)
212
+ send_to_hoptoad(:notice => notice)
213
+ end
214
+ end
215
+
216
+ alias_method :inform_hoptoad, :notify_hoptoad
217
+
218
+ # Returns the default logger or a logger that prints to STDOUT. Necessary for manual
219
+ # notifications outside of controllers.
220
+ def logger
221
+ ActiveRecord::Base.logger
222
+ rescue
223
+ @logger ||= Logger.new(STDERR)
224
+ end
225
+
226
+ private
227
+
228
+ def public_environment? #nodoc:
229
+ HoptoadNotifier.public_environments.include?(HoptoadNotifier.current_environment)
230
+ end
231
+
232
+ def ignore?(exception) #:nodoc:
233
+ ignore_these = HoptoadNotifier.ignore.flatten
234
+ ignore_these.include?(exception.class) || ignore_these.include?(exception.class.name)
235
+ end
236
+
237
+ def ignore_user_agent? #:nodoc:
238
+ HoptoadNotifier.ignore_user_agent.flatten.any? { |ua| ua === request.user_agent }
239
+ end
240
+
241
+ def exception_to_data exception #:nodoc:
242
+ data = {
243
+ :api_key => HoptoadNotifier.api_key,
244
+ :error_class => exception.class.name,
245
+ :error_message => "#{exception.class.name}: #{exception.message}",
246
+ :backtrace => exception.backtrace,
247
+ :environment => ENV.to_hash
248
+ }
249
+
250
+ if self.respond_to? :request
251
+ data[:request] = {
252
+ :params => request.parameters.to_hash,
253
+ :rails_root => File.expand_path(HoptoadNotifier.application_path),
254
+ :url => "#{request.protocol}#{request.host}#{request.request_uri}"
255
+ }
256
+ data[:environment].merge!(request.env.to_hash)
257
+ end
258
+
259
+ if self.respond_to? :session
260
+ data[:session] = {
261
+ :key => session.instance_variable_get("@session_id"),
262
+ :data => session.instance_variable_get("@data")
263
+ }
264
+ end
265
+
266
+ data
267
+ end
268
+
269
+ def normalize_notice(notice) #:nodoc:
270
+ case notice
271
+ when Hash
272
+ HoptoadNotifier.default_notice_options.merge(notice)
273
+ when Exception
274
+ HoptoadNotifier.default_notice_options.merge(exception_to_data(notice))
275
+ end
276
+ end
277
+
278
+ def clean_notice(notice) #:nodoc:
279
+ notice[:backtrace] = clean_hoptoad_backtrace(notice[:backtrace])
280
+ if notice[:request].is_a?(Hash) && notice[:request][:params].is_a?(Hash)
281
+ notice[:request][:params] = filter_parameters(notice[:request][:params]) if respond_to?(:filter_parameters)
282
+ notice[:request][:params] = clean_hoptoad_params(notice[:request][:params])
283
+ end
284
+ if notice[:environment].is_a?(Hash)
285
+ notice[:environment] = filter_parameters(notice[:environment]) if respond_to?(:filter_parameters)
286
+ notice[:environment] = clean_hoptoad_environment(notice[:environment])
287
+ end
288
+ clean_non_serializable_data(notice)
289
+ end
290
+
291
+ def send_to_hoptoad data #:nodoc:
292
+ headers = {
293
+ 'Content-type' => 'application/x-yaml',
294
+ 'Accept' => 'text/xml, application/xml'
295
+ }
296
+
297
+ url = HoptoadNotifier.url
298
+
299
+ http = Net::HTTP::Proxy(HoptoadNotifier.proxy_host,
300
+ HoptoadNotifier.proxy_port,
301
+ HoptoadNotifier.proxy_user,
302
+ HoptoadNotifier.proxy_pass).new(url.host, url.port)
303
+
304
+ http.use_ssl = true
305
+ http.read_timeout = HoptoadNotifier.http_read_timeout
306
+ http.open_timeout = HoptoadNotifier.http_open_timeout
307
+ http.use_ssl = !!HoptoadNotifier.secure
308
+
309
+ response = begin
310
+ http.post(url.path, stringify_keys(data).to_yaml, headers)
311
+ rescue TimeoutError => e
312
+ logger.error "Timeout while contacting the Hoptoad server." if logger
313
+ nil
314
+ end
315
+
316
+ case response
317
+ when Net::HTTPSuccess then
318
+ logger.info "Hoptoad Success: #{response.class}" if logger
319
+ else
320
+ logger.error "Hoptoad Failure: #{response.class}\n#{response.body if response.respond_to? :body}" if logger
321
+ end
322
+ end
323
+
324
+ def clean_hoptoad_backtrace backtrace #:nodoc:
325
+ if backtrace.to_a.size == 1
326
+ backtrace = backtrace.to_a.first.split(/\n\s*/)
327
+ end
328
+
329
+ filtered = backtrace.to_a.map do |line|
330
+ HoptoadNotifier.backtrace_filters.inject(line) do |line, proc|
331
+ proc.call(line)
332
+ end
333
+ end
334
+
335
+ filtered.compact
336
+ end
337
+
338
+ def clean_hoptoad_params params #:nodoc:
339
+ params.each do |k, v|
340
+ params[k] = "[FILTERED]" if HoptoadNotifier.params_filters.any? do |filter|
341
+ k.to_s.match(/#{filter}/)
342
+ end
343
+ end
344
+ end
345
+
346
+ def clean_hoptoad_environment env #:nodoc:
347
+ env.each do |k, v|
348
+ env[k] = "[FILTERED]" if HoptoadNotifier.environment_filters.any? do |filter|
349
+ k.to_s.match(/#{filter}/)
350
+ end
351
+ end
352
+ end
353
+
354
+ def clean_non_serializable_data(notice) #:nodoc:
355
+ notice.select{|k,v| serializable?(v) }.inject({}) do |h, pair|
356
+ h[pair.first] = pair.last.is_a?(Hash) ? clean_non_serializable_data(pair.last) : pair.last
357
+ h
358
+ end
359
+ end
360
+
361
+ def serializable?(value) #:nodoc:
362
+ value.is_a?(Fixnum) ||
363
+ value.is_a?(Array) ||
364
+ value.is_a?(String) ||
365
+ value.is_a?(Hash) ||
366
+ value.is_a?(Bignum)
367
+ end
368
+
369
+ def stringify_keys(hash) #:nodoc:
370
+ hash.inject({}) do |h, pair|
371
+ h[pair.first.to_s] = pair.last.is_a?(Hash) ? stringify_keys(pair.last) : pair.last
372
+ h
373
+ end
374
+ end
375
+
376
+ end
377
+
378
+ # A dummy class for sending notifications manually outside of a controller.
379
+ class Sender
380
+ def rescue_action_in_public(exception)
381
+ end
382
+
383
+ include HoptoadNotifier::Catcher
384
+ end
385
+ end
386
+
@@ -0,0 +1,63 @@
1
+ namespace :hoptoad do
2
+ desc "Notify Hoptoad of a new deploy."
3
+ task :deploy => :environment do
4
+ require 'hoptoad_tasks'
5
+ HoptoadTasks.deploy_to(ENV['TO'])
6
+ end
7
+
8
+ desc "Verify your plugin installation by sending a test exception to the hoptoad service"
9
+ task :test => :environment do
10
+ require 'action_controller/test_process'
11
+
12
+ request = ActionController::TestRequest.new
13
+
14
+ response = ActionController::TestResponse.new
15
+
16
+ class HoptoadTestingException < RuntimeError; end
17
+
18
+ unless HoptoadNotifier.api_key
19
+ puts "Hoptoad needs an API key configured! Check the README to see how to add it."
20
+ exit
21
+ end
22
+
23
+ in_controller = ApplicationController.included_modules.include? HoptoadNotifier::Catcher
24
+ in_base = ActionController::Base.included_modules.include? HoptoadNotifier::Catcher
25
+ if !in_controller || !in_base
26
+ puts "HoptoadNotifier::Catcher must be included inside your ApplicationController class."
27
+ exit
28
+ end
29
+
30
+ puts 'Setting up the Controller.'
31
+ class ApplicationController
32
+ # This is to bypass any filters that may prevent access to the action.
33
+ prepend_before_filter :test_hoptoad
34
+ def test_hoptoad
35
+ puts "Raising '#{exception_class.name}' to simulate application failure."
36
+ raise exception_class.new, 'Testing hoptoad via "rake hoptoad:test". If you can see this, it works.'
37
+ end
38
+
39
+ def rescue_action exception
40
+ rescue_action_in_public exception
41
+ end
42
+
43
+ def public_environment?
44
+ true
45
+ end
46
+
47
+ # Ensure we actually have an action to go to.
48
+ def verify; end
49
+
50
+ def exception_class
51
+ exception_name = ENV['EXCEPTION'] || "HoptoadTestingException"
52
+ Object.const_get(exception_name)
53
+ rescue
54
+ Object.const_set(exception_name, Class.new(Exception))
55
+ end
56
+ end
57
+
58
+ puts 'Processing request.'
59
+ class HoptoadVerificationController < ApplicationController; end
60
+ HoptoadVerificationController.new.process(request, response)
61
+ end
62
+ end
63
+
metadata ADDED
@@ -0,0 +1,57 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: markbates-hoptoad_notifier
3
+ version: !ruby/object:Gem::Version
4
+ version: "1.2"
5
+ platform: ruby
6
+ authors:
7
+ - Thoughtbot
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-03-26 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Rails plugin that reports exceptions to Hoptoad.
17
+ email: info@thoughtbot.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - INSTALL
26
+ - lib/hoptoad_notifier.rb
27
+ - Rakefile
28
+ - README
29
+ - tasks/hoptoad_notifier_tasks.rake
30
+ has_rdoc: true
31
+ homepage: http://github.com/thoughtbot/hoptoad_notifier
32
+ post_install_message:
33
+ rdoc_options: []
34
+
35
+ require_paths:
36
+ - lib
37
+ required_ruby_version: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: "0"
42
+ version:
43
+ required_rubygems_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: "0"
48
+ version:
49
+ requirements: []
50
+
51
+ rubyforge_project:
52
+ rubygems_version: 1.2.0
53
+ signing_key:
54
+ specification_version: 2
55
+ summary: Rails plugin that reports exceptions to Hoptoad.
56
+ test_files: []
57
+