super_exception_notifier 2.0.8 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. data/{README.rdoc → README} +13 -17
  2. data/VERSION.yml +3 -3
  3. data/lib/exception_notification.rb +15 -0
  4. data/rails/init.rb +8 -12
  5. data/super_exception_notifier.gemspec +88 -0
  6. data/test/exception_notifier_helper_test.rb +2 -10
  7. data/test/exception_notifier_test.rb +2 -2
  8. data/test/exception_notify_functional_test.rb +6 -6
  9. data/test/mocks/controllers.rb +22 -15
  10. data/test/notifiable_test.rb +6 -6
  11. data/test/test_helper.rb +6 -4
  12. metadata +35 -33
  13. data/lib/exception_notifiable.rb +0 -177
  14. data/lib/exception_notifier.rb +0 -176
  15. data/lib/exception_notifier_helper.rb +0 -60
  16. data/lib/notifiable.rb +0 -92
  17. data/lib/super_exception_notifier/custom_exception_classes.rb +0 -16
  18. data/lib/super_exception_notifier/custom_exception_methods.rb +0 -50
  19. data/lib/super_exception_notifier/deprecated_methods.rb +0 -60
  20. data/lib/super_exception_notifier/git_blame.rb +0 -52
  21. data/lib/super_exception_notifier/helpful_hashes.rb +0 -66
  22. data/lib/super_exception_notifier/hooks_notifier.rb +0 -55
  23. data/lib/super_exception_notifier/notifiable_helper.rb +0 -80
  24. data/tasks/notified_task.rake +0 -15
  25. data/views/exception_notifier/_backtrace.html.erb +0 -1
  26. data/views/exception_notifier/_environment.html.erb +0 -14
  27. data/views/exception_notifier/_inspect_model.html.erb +0 -16
  28. data/views/exception_notifier/_request.html.erb +0 -8
  29. data/views/exception_notifier/_session.html.erb +0 -6
  30. data/views/exception_notifier/_title.html.erb +0 -3
  31. data/views/exception_notifier/background_exception_notification.text.plain.erb +0 -10
  32. data/views/exception_notifier/exception_notification.text.plain.erb +0 -15
  33. data/views/exception_notifier/rake_exception_notification.text.plain.erb +0 -6
@@ -1,60 +0,0 @@
1
- require 'pp'
2
-
3
- module ExceptionNotifierHelper
4
- VIEW_PATH = "views/exception_notifier" unless defined?(VIEW_PATH)
5
- APP_PATH = "#{RAILS_ROOT}/app/#{VIEW_PATH}" unless defined?(APP_PATH)
6
- PARAM_FILTER_REPLACEMENT = "[FILTERED]" unless defined?(PARAM_FILTER_REPLACEMENT)
7
- COMPAT_MODE = defined?(RAILS_GEM_VERSION) ? RAILS_GEM_VERSION < '2' : false unless defined?(COMPAT_MODE)
8
-
9
- def render_section(section)
10
- RAILS_DEFAULT_LOGGER.info("rendering section #{section.inspect}")
11
- summary = render_overridable(section).strip
12
- unless summary.blank?
13
- title = render_overridable(:title, :locals => { :title => section }).strip
14
- "#{title}\n\n#{summary.gsub(/^/, " ")}\n\n"
15
- end
16
- end
17
-
18
- def render_overridable(partial, options={})
19
- if File.exist?(path = "#{APP_PATH}/_#{partial}.html.erb") ||
20
- File.exist?(path = "#{File.dirname(__FILE__)}/../#{VIEW_PATH}/_#{partial}.html.erb") ||
21
- File.exist?(path = "#{APP_PATH}/_#{partial}.rhtml") ||
22
- File.exist?(path = "#{APP_PATH}/_#{partial}.erb")
23
- render(options.merge(:file => path, :use_full_path => false))
24
- else
25
- ""
26
- end
27
- end
28
-
29
- def inspect_model_object(model, locals={})
30
- render_overridable(:inspect_model,
31
- :locals => { :inspect_model => model,
32
- :show_instance_variables => true,
33
- :show_attributes => true }.merge(locals))
34
- end
35
-
36
- def inspect_value(value)
37
- len = 512
38
- result = object_to_yaml(value).gsub(/\n/, "\n ").strip
39
- result = result[0,len] + "... (#{result.length-len} bytes more)" if result.length > len+20
40
- result
41
- end
42
-
43
- def object_to_yaml(object)
44
- object.to_yaml.sub(/^---\s*/m, "")
45
- end
46
-
47
- def exclude_raw_post_parameters?
48
- @controller && @controller.respond_to?(:filter_parameters)
49
- end
50
-
51
- def filter_sensitive_post_data_parameters(parameters)
52
- exclude_raw_post_parameters? ? COMPAT_MODE ? @controller.filter_parameters(parameters) : @controller.__send__(:filter_parameters, parameters) : parameters
53
- end
54
-
55
- def filter_sensitive_post_data_from_env(env_key, env_value)
56
- return env_value unless exclude_raw_post_parameters?
57
- return PARAM_FILTER_REPLACEMENT if (env_key =~ /RAW_POST_DATA/i)
58
- return COMPAT_MODE ? @controller.filter_parameters({env_key => env_value}).values[0] : @controller.__send__(:filter_parameters, {env_key => env_value}).values[0]
59
- end
60
- end
data/lib/notifiable.rb DELETED
@@ -1,92 +0,0 @@
1
- module Notifiable
2
- include SuperExceptionNotifier::NotifiableHelper
3
-
4
- def self.included(base)
5
- base.extend ClassMethods
6
-
7
- # Verbosity of the gem
8
- base.cattr_accessor :notifiable_verbose
9
- base.notifiable_verbose = false
10
- # Do Not Ever send error notification emails for these Error Classes
11
- base.cattr_accessor :notifiable_silent_exceptions
12
- base.notifiable_silent_exceptions = SILENT_EXCEPTIONS
13
- # Notification Level
14
- base.cattr_accessor :notifiable_notification_level
15
- base.notifiable_notification_level = [:email, :web_hooks]
16
-
17
- # Since there is no concept of locality from a request here allow user to explicitly define which env's are noisy (send notifications)
18
- base.cattr_accessor :notifiable_noisy_environments
19
- base.notifiable_noisy_environments = [:production]
20
- end
21
-
22
- module ClassMethods
23
- # set the exception_data deliverer OR retrieve the exception_data
24
- def exception_data(deliverer = nil)
25
- if deliverer
26
- write_inheritable_attribute(:exception_data, deliverer)
27
- else
28
- read_inheritable_attribute(:exception_data)
29
- end
30
- end
31
-
32
- def be_silent_for_exception?(exception)
33
- self.notifiable_silent_exceptions.respond_to?(:any?) && self.notifiable_silent_exceptions.any? {|klass| klass === exception }
34
- end
35
-
36
- end
37
-
38
- # Usage:
39
- # notifiable { Klass.some_method }
40
- # This will rescue any errors that occur within Klass.some_method
41
- def notifiable(&block)
42
- yield
43
- rescue => exception
44
- rescue_with_hooks(exception)
45
- raise
46
- end
47
-
48
- def be_silent_for_exception?(exception)
49
- self.class.be_silent_for_exception?(exception)
50
- end
51
-
52
- private
53
-
54
- def notification_level_sends_email?
55
- self.class.notifiable_notification_level.include?(:email)
56
- end
57
-
58
- def notification_level_sends_web_hooks?
59
- self.class.notifiable_notification_level.include?(:web_hooks)
60
- end
61
-
62
- def rescue_with_hooks(exception)
63
- verbose = self.class.notifiable_verbose
64
- puts "[RESCUE STYLE] rescue_with_hooks" if verbose
65
- data = get_exception_data
66
- # With ExceptionNotifiable you have an inherent request, and using a status code makes sense.
67
- # With Notifiable class to wrap around everything that doesn't have a request,
68
- # the errors you want to be notified of need to be specified either positively or negatively
69
- # 1. positive eg. set ExceptionNotifier.config[:notify_error_classes] to an array of classes
70
- # set ExceptionNotifier.config[:notify_other_errors] to false
71
- # 1. negative eg. set Klass.silent_exceptions to the ones to keep quiet
72
- # set ExceptionNotifier.config[:notify_other_errors] to true
73
- status_code = nil
74
- #We only send email if it has been configured in environment
75
- send_email = should_email_on_exception?(exception, status_code, verbose)
76
- #We only send web hooks if they've been configured in environment
77
- send_web_hooks = should_web_hook_on_exception?(exception, status_code, verbose)
78
- the_blamed = ExceptionNotifier.config[:git_repo_path].nil? ? nil : lay_blame(exception)
79
- rejected_sections = %w(request session)
80
- verbose_output(exception, status_code, "rescued by handler", send_email, send_web_hooks, nil, the_blamed, rejected_sections) if verbose
81
- # Send the exception notification email
82
- perform_exception_notify_mailing(exception, data, nil, the_blamed, verbose, rejected_sections) if send_email
83
- # Send Web Hook requests
84
- HooksNotifier.deliver_exception_to_web_hooks(ExceptionNotifier.config, exception, self, request, data, the_blamed) if send_web_hooks
85
- end
86
-
87
- def is_local? #like asking is_silent?
88
- eenv = defined?(Rails) ? Rails.env : RAILS_ENV
89
- !self.notifiable_noisy_environments.include?(eenv)
90
- end
91
-
92
- end
@@ -1,16 +0,0 @@
1
- #Copyright (c) 2008-2009 Peter H. Boling of 9thBit LLC
2
- #Released under the MIT license
3
-
4
- module SuperExceptionNotifier
5
- module CustomExceptionClasses
6
-
7
- class AccessDenied < StandardError; end
8
- class ResourceGone < StandardError; end
9
- class NotImplemented < StandardError; end
10
- class PageNotFound < StandardError; end
11
- class InvalidMethod < StandardError; end
12
- class CorruptData < StandardError; end
13
- class MethodDisabled < StandardError; end
14
-
15
- end
16
- end
@@ -1,50 +0,0 @@
1
- #Copyright (c) 2008-2009 Peter H. Boling of 9thBit LLC
2
- #Released under the MIT license
3
-
4
- module SuperExceptionNotifier
5
- module CustomExceptionMethods
6
-
7
- protected
8
-
9
- #For a while after disabling a route/URL that had been functional we should set it to resource gone to inform people to remove bookmarks.
10
- def resource_gone
11
- raise ResourceGone
12
- end
13
- #Then for things that have never existed or have not for a long time we call not_implemented
14
- def not_implemented
15
- raise NotImplemented
16
- end
17
- #Resources that must be requested with a specific HTTP Method (GET, PUT, POST, DELETE, AJAX, etc) but are requested otherwise should:
18
- def invalid_method
19
- raise InvalidMethod
20
- end
21
- #If your ever at a spot in the code that should never get reached, but corrupt data might get you there anyways then this is for you:
22
- def corrupt_data
23
- raise CorruptData
24
- end
25
- def page_not_found
26
- raise PageNotFound
27
- end
28
- def record_not_found
29
- raise ActiveRecord::RecordNotFound
30
- end
31
- def method_disabled
32
- raise MethodDisabled
33
- end
34
- #The current user does not have enough privileges to access the requested resource
35
- def access_denied
36
- raise AccessDenied
37
- end
38
-
39
- def generic_error
40
- error_stickie("Sorry, an error has occurred.")
41
- corrupt_data
42
- end
43
-
44
- def invalid_page
45
- error_stickie("Sorry, the page number you requested was not valid.")
46
- page_not_found
47
- end
48
-
49
- end
50
- end
@@ -1,60 +0,0 @@
1
- #Copyright (c) 2008-2009 Peter H. Boling of 9thBit LLC
2
- #Released under the MIT license
3
-
4
- module SuperExceptionNotifier
5
- module DeprecatedMethods
6
- @@namespacing = "Better namespacing to allow for Notifiable and ExceptionNotifiable to have similar APIs"
7
- @@rails2ruby = "An effort to make this a 'Ruby' Gem and not a strictly 'Rails' Gem"
8
-
9
- def http_error_codes
10
- deprecation_warning("http_error_codes", "error_class_status_codes")
11
- error_class_status_codes
12
- end
13
-
14
- def http_error_codes=(arg)
15
- deprecation_warning("http_error_codes", "error_class_status_codes")
16
- error_class_status_codes=(arg)
17
- end
18
-
19
- def rails_error_codes
20
- deprecation_warning("rails_error_codes", "error_class_status_codes", @@rails2ruby)
21
- error_class_status_codes
22
- end
23
-
24
- def rails_error_codes=(arg)
25
- deprecation_warning("rails_error_codes=", "error_class_status_codes=", @@rails2ruby)
26
- error_class_status_codes=(arg)
27
- end
28
-
29
- # Now defined in Object class by init.rb & Notifiable module,
30
- # so we need to override them for with the controller settings
31
- def exception_notifier_verbose
32
- deprecation_warning("exception_notifier_verbose", "exception_notifiable_verbose", @@namespacing)
33
- exception_notifiable_verbose
34
- end
35
- def silent_exceptions
36
- deprecation_warning("silent_exceptions", "exception_notifiable_silent_exceptions", @@namespacing)
37
- exception_notifiable_silent_exceptions
38
- end
39
- def notification_level
40
- deprecation_warning("notification_level", "exception_notifiable_notification_level", @@namespacing)
41
- exception_notifiable_notification_level
42
- end
43
- def exception_notifier_verbose=(arg)
44
- deprecation_warning("exception_notifier_verbose=", "exception_notifiable_verbose=", @@namespacing)
45
- exception_notifiable_verbose = arg
46
- end
47
- def silent_exceptions=(arg)
48
- deprecation_warning("silent_exceptions=", "exception_notifiable_silent_exceptions=", @@namespacing)
49
- exception_notifiable_silent_exceptions = arg
50
- end
51
- def notification_level=(arg)
52
- deprecation_warning("notification_level=", "exception_notifiable_notification_level=", @@namespacing)
53
- exception_notifiable_notification_level = arg
54
- end
55
-
56
- def deprecation_warning(old, new, reason = "")
57
- puts "[DEPRECATION WARNING] ** Method '#{old}' has been replaced by '#{new}', please update your code.#{' Reason for change: ' + reason + '.' if reason}"
58
- end
59
- end
60
- end
@@ -1,52 +0,0 @@
1
- #Copyright (c) 2008-2009 Peter H. Boling of 9thBit LLC
2
- #Released under the MIT license
3
-
4
- module SuperExceptionNotifier
5
- module GitBlame
6
-
7
- def lay_blame(exception)
8
- error = {}
9
- unless(ExceptionNotifier.config[:git_repo_path].nil?)
10
- if(exception.class == ActionView::TemplateError)
11
- blame = blame_output(exception.line_number, "app/views/#{exception.file_name}")
12
- error[:author] = blame[/^author\s.+$/].gsub(/author\s/,'')
13
- error[:line] = exception.line_number
14
- error[:file] = exception.file_name
15
- else
16
- exception.backtrace.each do |line|
17
- file = exception_in_project?(line[/^.+?(?=:)/])
18
- unless(file.nil?)
19
- line_number = line[/:\d+:/].gsub(/[^\d]/,'')
20
- # Use relative path or weird stuff happens
21
- blame = blame_output(line_number, file.gsub(Regexp.new("#{RAILS_ROOT}/"),''))
22
- error[:author] = blame[/^author\s.+$/].sub(/author\s/,'')
23
- error[:line] = line_number
24
- error[:file] = file
25
- break
26
- end
27
- end
28
- end
29
- end
30
- error
31
- end
32
-
33
- def blame_output(line_number, path)
34
- app_directory = Dir.pwd
35
- Dir.chdir ExceptionNotifier.config[:git_repo_path]
36
- blame = `git blame -p -L #{line_number},#{line_number} #{path}`
37
- Dir.chdir app_directory
38
-
39
- blame
40
- end
41
-
42
- def exception_in_project?(path) # should be a path like /path/to/broken/thingy.rb
43
- dir = File.split(path).first rescue ''
44
- if(File.directory?(dir) and !(path =~ /vendor\/plugins/) and !(path =~ /vendor\/gems/) and path.include?(RAILS_ROOT))
45
- path
46
- else
47
- nil
48
- end
49
- end
50
-
51
- end
52
- end
@@ -1,66 +0,0 @@
1
- #Copyright (c) 2008-2009 Peter H. Boling of 9thBit LLC
2
- #Released under the MIT license
3
-
4
- module SuperExceptionNotifier
5
- module HelpfulHashes
6
- unless defined?(SILENT_EXCEPTIONS)
7
- noiseless = []
8
- noiseless << ActiveRecord::RecordNotFound if defined?(ActiveRecord)
9
- if defined?(ActionController)
10
- noiseless << ActionController::UnknownController
11
- noiseless << ActionController::UnknownAction
12
- noiseless << ActionController::RoutingError
13
- noiseless << ActionController::MethodNotAllowed
14
- end
15
- SILENT_EXCEPTIONS = noiseless
16
- end
17
-
18
- # TODO: use ActionController::StatusCodes
19
- HTTP_STATUS_CODES = {
20
- "400" => "Bad Request",
21
- "403" => "Forbidden",
22
- "404" => "Not Found",
23
- "405" => "Method Not Allowed",
24
- "410" => "Gone",
25
- "418" => "I'm a teapot",
26
- "422" => "Unprocessable Entity",
27
- "423" => "Locked",
28
- "500" => "Internal Server Error",
29
- "501" => "Not Implemented",
30
- "503" => "Service Unavailable"
31
- } unless defined?(HTTP_STATUS_CODES)
32
-
33
- def codes_for_error_classes
34
- #TODO: Format whitespace
35
- classes = {
36
- # These are standard errors in rails / ruby
37
- NameError => "503",
38
- TypeError => "503",
39
- RuntimeError => "500",
40
- ArgumentError => "500",
41
- # These are custom error names defined in lib/super_exception_notifier/custom_exception_classes
42
- AccessDenied => "403",
43
- PageNotFound => "404",
44
- InvalidMethod => "405",
45
- ResourceGone => "410",
46
- CorruptData => "422",
47
- NoMethodError => "500",
48
- NotImplemented => "501",
49
- MethodDisabled => "200"
50
- }
51
- # Highly dependent on the verison of rails, so we're very protective about these'
52
- classes.merge!({ ActionView::TemplateError => "500"}) if defined?(ActionView) && ActionView.const_defined?(:TemplateError)
53
- classes.merge!({ ActiveRecord::RecordNotFound => "400" }) if defined?(ActiveRecord) && ActiveRecord.const_defined?(:RecordNotFound)
54
- classes.merge!({ ActiveResource::ResourceNotFound => "404" }) if defined?(ActiveResource) && ActiveResource.const_defined?(:ResourceNotFound)
55
-
56
- if defined?(ActionController)
57
- classes.merge!({ ActionController::UnknownController => "404" }) if ActionController.const_defined?(:UnknownController)
58
- classes.merge!({ ActionController::MissingTemplate => "404" }) if ActionController.const_defined?(:MissingTemplate)
59
- classes.merge!({ ActionController::MethodNotAllowed => "405" }) if ActionController.const_defined?(:MethodNotAllowed)
60
- classes.merge!({ ActionController::UnknownAction => "501" }) if ActionController.const_defined?(:UnknownAction)
61
- classes.merge!({ ActionController::RoutingError => "404" }) if ActionController.const_defined?(:RoutingError)
62
- classes.merge!({ ActionController::InvalidAuthenticityToken => "405" }) if ActionController.const_defined?(:InvalidAuthenticityToken)
63
- end
64
- end
65
- end
66
- end
@@ -1,55 +0,0 @@
1
- require 'net/http'
2
- require 'uri'
3
-
4
- module SuperExceptionNotifier
5
- module HooksNotifier
6
- # Deliver exception data hash to web hooks, if any
7
- #
8
- def self.deliver_exception_to_web_hooks(config, exception, controller, request, data={}, the_blamed = nil)
9
- params = build_web_hook_params(config, exception, controller, request, data, the_blamed)
10
- # TODO: use threads here
11
- config[:web_hooks].each do |address|
12
- post_hook(params, address)
13
- end
14
- end
15
-
16
-
17
- # Parameters hash based on Merb Exceptions example
18
- #
19
- def self.build_web_hook_params(config, exception, controller, request, data={}, the_blamed = nil)
20
- host = (request.env["HTTP_X_FORWARDED_HOST"] || request.env["HTTP_HOST"])
21
- p = {
22
- 'environment' => (defined?(Rails) ? Rails.env : RAILS_ENV),
23
- 'exceptions' => [{
24
- :class => exception.class.to_s,
25
- :backtrace => exception.backtrace,
26
- :message => exception.message
27
- }],
28
- 'app_name' => config[:app_name],
29
- 'version' => config[:version],
30
- 'blame' => "#{the_blamed}"
31
- }
32
- if !request.nil?
33
- p.merge!({'request_url' => "#{request.protocol}#{host}#{request.request_uri}"})
34
- p.merge!({'request_action' => request.parameters['action']})
35
- p.merge!({'request_params' => request.parameters.inspect})
36
- end
37
- p.merge!({'request_controller' => controller.class.name}) if !controller.nil?
38
- p.merge!({'status' => exception.status}) if exception.respond_to?(:status)
39
- return p
40
- end
41
-
42
- def self.post_hook(params, address)
43
- uri = URI.parse(address)
44
- uri.path = '/' if uri.path=='' # set a path if one isn't provided to keep Net::HTTP happy
45
-
46
- headers = { 'Content-Type' => 'text/x-json' }
47
- data = params.to_json
48
- Net::HTTP.start(uri.host, uri.port) do |http|
49
- http.request_post(uri.path, data, headers)
50
- end
51
- data
52
- end
53
-
54
- end
55
- end