errorapp_notifier 0.1.0
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.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/MIT-LICENSE +25 -0
- data/README.md +60 -0
- data/Rakefile +8 -0
- data/errorapp_notifier.gemspec +29 -0
- data/lib/errorapp_notifier/action_controller_methods.rb +35 -0
- data/lib/errorapp_notifier/application_environment_data.rb +77 -0
- data/lib/errorapp_notifier/config.rb +67 -0
- data/lib/errorapp_notifier/controller_failure_data.rb +96 -0
- data/lib/errorapp_notifier/exception_data.rb +19 -0
- data/lib/errorapp_notifier/failure_data.rb +87 -0
- data/lib/errorapp_notifier/monkeypatches.rb +11 -0
- data/lib/errorapp_notifier/notifier.rb +80 -0
- data/lib/errorapp_notifier/notifiers/rack_rails.rb +32 -0
- data/lib/errorapp_notifier/notifiers/rails.rb +34 -0
- data/lib/errorapp_notifier/notifiers/tester.rb +16 -0
- data/lib/errorapp_notifier/notify.rb +59 -0
- data/lib/errorapp_notifier/rack_failure_data.rb +29 -0
- data/lib/errorapp_notifier/railtie.rb +48 -0
- data/lib/errorapp_notifier/sanitizer.rb +56 -0
- data/lib/errorapp_notifier/tasks/errorapp_notifier.rake +6 -0
- data/lib/errorapp_notifier/version.rb +3 -0
- data/lib/errorapp_notifier.rb +74 -0
- data/lib/generators/errorapp_notifier/errorapp_notifier_generator.rb +54 -0
- data/lib/generators/errorapp_notifier/templates/errorapp_notifier.rb +2 -0
- data/spec/errorapp_notifier/config_spec.rb +76 -0
- data/spec/errorapp_notifier/controller_failure_data_spec.rb +277 -0
- data/spec/errorapp_notifier/failure_data_spec.rb +32 -0
- data/spec/errorapp_notifier/notifier_spec.rb +31 -0
- data/spec/errorapp_notifier/notify_spec.rb +128 -0
- data/spec/errorapp_notifier/rack_failure_data_spec.rb +87 -0
- data/spec/errorapp_notifier/sanitizer_spec.rb +57 -0
- data/spec/helper.rb +12 -0
- data/spec/spec_helper.rb +16 -0
- metadata +188 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 73aabada015e5a366a71f919330dbda250a796b6
|
4
|
+
data.tar.gz: 81180c1a660b66aa8e2968245bef973665fdabb4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 454ba40d8c73c1cdd81a1081c77e221bf41884ccd3b3afa0024daecb15882199635ec80622338a0eb9e3bb64e383b27dc83b9e0ffd178381f188a5e63cb400c8
|
7
|
+
data.tar.gz: 7bf777670b0e10f70c8dfdb2ea1ba5ca29453f28b7ed35adbacf52b42b46e2758637042275d20de4a9a016fe3b3061fd7b90702ce7e569264336c87b96c7d58c
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
Copyright (c) 2012-2013, ErrorApp
|
2
|
+
|
3
|
+
NOTE: Few code ideas are copyright Exceptional DBA Airbrake.io was available
|
4
|
+
under the MIT license (listed below) on or before May 1, 2013.
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person
|
7
|
+
obtaining a copy of this software and associated documentation
|
8
|
+
files (the "Software"), to deal in the Software without
|
9
|
+
restriction, including without limitation the rights to use,
|
10
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11
|
+
copies of the Software, and to permit persons to whom the
|
12
|
+
Software is furnished to do so, subject to the following
|
13
|
+
conditions:
|
14
|
+
|
15
|
+
The above copyright notice and this permission notice shall be
|
16
|
+
included in all copies or substantial portions of the Software.
|
17
|
+
|
18
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
20
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
22
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
23
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
24
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
25
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
ErrorApp
|
2
|
+
===============
|
3
|
+
|
4
|
+
This is the notifier gem for integrating apps with ErrorApp.
|
5
|
+
|
6
|
+
When an exception occurs, ErrorappNotifier will POST the relevant data to the ErrorApp server specified in your environment.
|
7
|
+
|
8
|
+
## Rails Installation
|
9
|
+
|
10
|
+
Add the ErrorappNotifier gem to your gemfile:
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
gem 'errorapp_notifier'
|
14
|
+
```
|
15
|
+
Install the gem
|
16
|
+
```ruby
|
17
|
+
bundle install
|
18
|
+
```
|
19
|
+
Then run the our generator which will create a initializer file
|
20
|
+
`errorapp_notifier.rb`
|
21
|
+
```ruby
|
22
|
+
rails generate errorapp_notifier --api_key <Your Project Api Key>
|
23
|
+
```
|
24
|
+
|
25
|
+
OR you can manually create initializer file and put below code snippet in that file
|
26
|
+
```ruby
|
27
|
+
ErrorappNotifier.configure do|config|
|
28
|
+
config.api_key = 'api key'
|
29
|
+
end
|
30
|
+
```
|
31
|
+
|
32
|
+
##Testing Integration
|
33
|
+
|
34
|
+
To test that errorapp_notifier is properly installed run below rake task
|
35
|
+
```ruby
|
36
|
+
rake errorapp_notifier:test_exception
|
37
|
+
```
|
38
|
+
A test exception will be sent to your ErrorApp dashboard if everything is configured correctly.
|
39
|
+
|
40
|
+
## Contributing
|
41
|
+
|
42
|
+
1. Fork it.
|
43
|
+
2. Create a topic branch `git checkout -b my_branch`
|
44
|
+
3. Commit your changes `git commit -am "Boom"`
|
45
|
+
3. Push to your branch `git push origin my_branch`
|
46
|
+
4. Send a [pull request](https://github.com/errorapp/errorapp_notifier/pulls)
|
47
|
+
|
48
|
+
## Credits
|
49
|
+
|
50
|
+
Idea from various Apps.
|
51
|
+
|
52
|
+
Thanks to
|
53
|
+
|
54
|
+
1. Airbrake
|
55
|
+
2. Exceptional
|
56
|
+
|
57
|
+
## License
|
58
|
+
|
59
|
+
ErrorApp is Copyright 2014 © ErrorApp. It is free software, and
|
60
|
+
may be redistributed under the terms specified in the MIT-LICENSE file.
|
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'errorapp_notifier/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "errorapp_notifier"
|
8
|
+
spec.version = ErrorappNotifier::VERSION
|
9
|
+
spec.authors = ["Rashmi"]
|
10
|
+
spec.email = ["rays.rashmi@gmail.com"]
|
11
|
+
spec.description = %q{ Notifier for sending errors to ErrorApp }
|
12
|
+
spec.summary = %q{ ErrorApp is a webapp for monitoring exceptions and other failures in your live applications. }
|
13
|
+
spec.homepage = "http://errorapp.com"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(spec)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler"
|
22
|
+
spec.add_development_dependency "actionpack", "~> 3.2"
|
23
|
+
spec.add_development_dependency "rake"
|
24
|
+
spec.add_development_dependency "rspec", "2.14"
|
25
|
+
spec.add_development_dependency "webmock"
|
26
|
+
spec.add_development_dependency "json"
|
27
|
+
|
28
|
+
spec.add_dependency "rack"
|
29
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module ErrorappNotifier
|
2
|
+
module ActionControllerMethods
|
3
|
+
def rescue_with_errorapp(exception)
|
4
|
+
unless exception_handled_by_rescue_from?(exception)
|
5
|
+
notify_with_controller(exception)
|
6
|
+
ErrorappNotifier.context.clear!
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def errorapp_rescue(context=nil, &block)
|
11
|
+
begin
|
12
|
+
ErrorappNotifier.context(context) unless context.nil?
|
13
|
+
block.call
|
14
|
+
rescue Exception => exception
|
15
|
+
notify_with_controller(exception)
|
16
|
+
ensure
|
17
|
+
ErrorappNotifier.context.clear!
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def notify_with_controller(exception)
|
24
|
+
ErrorappNotifier::Notify.notify_with_controller(
|
25
|
+
exception,
|
26
|
+
self,
|
27
|
+
request
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
def exception_handled_by_rescue_from?(exception)
|
32
|
+
respond_to?(:handler_for_rescue) && handler_for_rescue(exception)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
class ApplicationEnvironmentData
|
2
|
+
attr_reader :exception
|
3
|
+
|
4
|
+
def initialize(exception)
|
5
|
+
@exception = exception
|
6
|
+
end
|
7
|
+
|
8
|
+
def data
|
9
|
+
{
|
10
|
+
:application_environment =>
|
11
|
+
{
|
12
|
+
:environment => application_environment,
|
13
|
+
:env => extract_environment(ENV),
|
14
|
+
:host => get_hostname,
|
15
|
+
:run_as_user => get_username,
|
16
|
+
:application_root_directory => application_root_directory,
|
17
|
+
:language => 'ruby',
|
18
|
+
:language_version => language_version_string,
|
19
|
+
:libraries_loaded => libraries_loaded
|
20
|
+
}
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def application_root_directory
|
27
|
+
(application_root.to_s.respond_to?(:force_encoding) ?
|
28
|
+
application_root.to_s.force_encoding("UTF-8") : application_root)
|
29
|
+
end
|
30
|
+
|
31
|
+
def application_environment
|
32
|
+
config.application_environment
|
33
|
+
end
|
34
|
+
|
35
|
+
def application_root
|
36
|
+
config.application_root
|
37
|
+
end
|
38
|
+
|
39
|
+
def config
|
40
|
+
ErrorappNotifier.configuration
|
41
|
+
end
|
42
|
+
|
43
|
+
def extract_environment(env)
|
44
|
+
env.reject do |k, v|
|
45
|
+
is_http_header = (k =~ /^HTTP_/)
|
46
|
+
is_filtered = ErrorappNotifier::ENVIRONMENT_FILTER.include?(k)
|
47
|
+
matches_whitelist = ErrorappNotifier::ENVIRONMENT_WHITELIST.
|
48
|
+
any? do |whitelist_filter|
|
49
|
+
whitelist_filter === k
|
50
|
+
end
|
51
|
+
is_http_header || is_filtered || !matches_whitelist
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def get_hostname
|
56
|
+
require 'socket' unless defined?(Socket)
|
57
|
+
Socket.gethostname
|
58
|
+
rescue
|
59
|
+
'UNKNOWN'
|
60
|
+
end
|
61
|
+
|
62
|
+
def get_username
|
63
|
+
ENV['LOGNAME'] || ENV['USER'] || ENV['USERNAME'] || ENV['APACHE_RUN_USER'] || 'UNKNOWN'
|
64
|
+
end
|
65
|
+
|
66
|
+
def language_version_string
|
67
|
+
"#{RUBY_VERSION rescue '?.?.?'} p#{RUBY_PATCHLEVEL rescue '???'} #{RUBY_RELEASE_DATE rescue '????-??-??'} #{RUBY_PLATFORM rescue '????'}"
|
68
|
+
end
|
69
|
+
|
70
|
+
def libraries_loaded
|
71
|
+
begin
|
72
|
+
return Hash[*Gem.loaded_specs.map{|name, gem_specification| [name, gem_specification.version.to_s]}.flatten]
|
73
|
+
rescue
|
74
|
+
end
|
75
|
+
{}
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module ErrorappNotifier
|
2
|
+
class Config
|
3
|
+
attr_accessor :api_key
|
4
|
+
attr_accessor :disabled_by_default
|
5
|
+
attr_accessor :environment_name
|
6
|
+
attr_accessor :http_open_timeout
|
7
|
+
attr_accessor :http_proxy_host
|
8
|
+
attr_accessor :http_proxy_password
|
9
|
+
attr_accessor :http_proxy_port
|
10
|
+
attr_accessor :http_proxy_username
|
11
|
+
attr_accessor :http_read_timeout
|
12
|
+
attr_accessor :ignore_exceptions
|
13
|
+
attr_accessor :ignore_user_agents
|
14
|
+
attr_accessor :logger
|
15
|
+
attr_accessor :params_filters
|
16
|
+
attr_accessor :project_root
|
17
|
+
attr_accessor :remote_host
|
18
|
+
attr_accessor :remote_port
|
19
|
+
attr_accessor :ssl
|
20
|
+
|
21
|
+
DEFAULT_IGNORE_EXCEPTIONS = ['ActiveRecord::RecordNotFound',
|
22
|
+
'ActionController::RoutingError',
|
23
|
+
'ActionController::InvalidAuthenticityToken',
|
24
|
+
'CGI::Session::CookieStore::TamperedWithCookie',
|
25
|
+
'ActionController::UnknownAction',
|
26
|
+
'AbstractController::ActionNotFound',
|
27
|
+
'ActionController::UnknownFormat',
|
28
|
+
'Mongoid::Errors::DocumentNotFound',
|
29
|
+
'Sinatra::NotFound',
|
30
|
+
"SystemExit",
|
31
|
+
"SignalException"].freeze
|
32
|
+
|
33
|
+
DEFAULT_PARAMS_FILTERS = %w(password password_confirmation).freeze
|
34
|
+
|
35
|
+
alias_method :ssl?, :ssl
|
36
|
+
|
37
|
+
def initialize
|
38
|
+
@api_key = ENV['ERRORAPP_API_KEY']
|
39
|
+
@disabled_by_default = %w(development test)
|
40
|
+
@http_open_timeout = 2
|
41
|
+
@http_read_timeout = 4
|
42
|
+
@ignore_exceptions = DEFAULT_IGNORE_EXCEPTIONS
|
43
|
+
@ignore_user_agents = []
|
44
|
+
@logger = Logger.new(STDOUT)
|
45
|
+
@params_filters = DEFAULT_PARAMS_FILTERS
|
46
|
+
@remote_host = "errorapp.com"
|
47
|
+
@remote_port = nil
|
48
|
+
@ssl = true
|
49
|
+
end
|
50
|
+
|
51
|
+
def should_send_to_api?
|
52
|
+
!disabled_by_default.include?(application_environment)
|
53
|
+
end
|
54
|
+
|
55
|
+
def application_root
|
56
|
+
@project_root || Dir.pwd
|
57
|
+
end
|
58
|
+
|
59
|
+
def remote_port
|
60
|
+
@remote_port ||= ssl? ? 443 : 80
|
61
|
+
end
|
62
|
+
|
63
|
+
def application_environment
|
64
|
+
@environment_name || ENV['RACK_ENV'] || ENV['RAILS_ENV'] || 'development'
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module ErrorappNotifier
|
2
|
+
class ControllerFailureData < FailureData
|
3
|
+
def initialize(exception, controller = nil, request = nil)
|
4
|
+
super(exception)
|
5
|
+
@data = ControllerDataExtractor.new(controller, request) unless request.nil?
|
6
|
+
end
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def extra_stuff
|
11
|
+
return {} if @data.nil?
|
12
|
+
{
|
13
|
+
:request =>
|
14
|
+
{
|
15
|
+
:url => @data.url,
|
16
|
+
:controller => @data.controller,
|
17
|
+
:action => @data.action,
|
18
|
+
:parameters => @data.parameters,
|
19
|
+
:request_method => @data.request_method,
|
20
|
+
:remote_ip => @data.remote_ip,
|
21
|
+
:headers => extract_http_headers(@data.env),
|
22
|
+
:session => Sanitizer.sanitize_session(@data.request)
|
23
|
+
}
|
24
|
+
}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class ControllerDataExtractor
|
29
|
+
def initialize(controller, request)
|
30
|
+
@request = request
|
31
|
+
@controller = controller
|
32
|
+
end
|
33
|
+
|
34
|
+
def controller
|
35
|
+
"#{@controller.class}"
|
36
|
+
end
|
37
|
+
|
38
|
+
def url
|
39
|
+
if @request.respond_to?(:url)
|
40
|
+
@request.url
|
41
|
+
else
|
42
|
+
"#{@request.protocol}#{@request.host}#{@request.request_uri}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def action
|
47
|
+
if @request.respond_to?(:parameters)
|
48
|
+
@request.parameters['action']
|
49
|
+
else
|
50
|
+
@request.params['action']
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def parameters
|
55
|
+
parameters = if @request.respond_to?(:parameters)
|
56
|
+
@request.parameters
|
57
|
+
else
|
58
|
+
@request.params
|
59
|
+
end
|
60
|
+
|
61
|
+
filter_parameters(parameters)
|
62
|
+
end
|
63
|
+
|
64
|
+
def request_method
|
65
|
+
"#{@request.request_method}"
|
66
|
+
end
|
67
|
+
|
68
|
+
def remote_ip
|
69
|
+
if @request.respond_to?(:remote_ip)
|
70
|
+
@request.remote_ip
|
71
|
+
else
|
72
|
+
@request.ip
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def env
|
77
|
+
@request.env
|
78
|
+
end
|
79
|
+
|
80
|
+
def request
|
81
|
+
@request
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def filter_parameters(hash)
|
87
|
+
if @request.respond_to?(:env) && @request.env["action_dispatch.parameter_filter"]
|
88
|
+
Sanitizer.filter_hash(@request.env["action_dispatch.parameter_filter"], hash)
|
89
|
+
elsif @controller.respond_to?(:filter_parameters)
|
90
|
+
@controller.send(:filter_parameters, hash)
|
91
|
+
else
|
92
|
+
hash
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class ExceptionData
|
2
|
+
attr_reader :exception
|
3
|
+
|
4
|
+
def initialize(exception)
|
5
|
+
@exception = exception
|
6
|
+
end
|
7
|
+
|
8
|
+
def data
|
9
|
+
{
|
10
|
+
:exception =>
|
11
|
+
{
|
12
|
+
:exception_class => exception.class.to_s,
|
13
|
+
:message => exception.message,
|
14
|
+
:backtrace => exception.backtrace,
|
15
|
+
:occurred_at => Time.now.utc.iso8601
|
16
|
+
}
|
17
|
+
}
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'digest/md5'
|
2
|
+
require 'time'
|
3
|
+
require 'errorapp_notifier/exception_data'
|
4
|
+
require 'errorapp_notifier/application_environment_data'
|
5
|
+
|
6
|
+
module ErrorappNotifier
|
7
|
+
class FailureData
|
8
|
+
def initialize(exception, name = nil)
|
9
|
+
@exception = exception
|
10
|
+
@name = name
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_hash
|
14
|
+
hash = {}
|
15
|
+
hash.merge!(ExceptionData.new(@exception).data)
|
16
|
+
hash.merge!(ApplicationEnvironmentData.new(@exception).data)
|
17
|
+
hash.merge!(extra_stuff)
|
18
|
+
hash.merge!(context_stuff)
|
19
|
+
hash.merge!(errorapp_client_data)
|
20
|
+
rescue_sanitize_hash do
|
21
|
+
Sanitizer.sanitize_hash(hash)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_json
|
26
|
+
begin
|
27
|
+
to_hash.to_json
|
28
|
+
rescue NoMethodError
|
29
|
+
begin
|
30
|
+
require 'json'
|
31
|
+
return to_hash.to_json
|
32
|
+
rescue StandardError => e
|
33
|
+
ErrorappNotifier.logger.error(e.message)
|
34
|
+
ErrorappNotifier.logger.error(e.backtrace)
|
35
|
+
raise StandardError.new("You need a json gem/library installed to send errors to ErrorApp (Object.to_json not defined). \nInstall json_pure, yajl-ruby, json-jruby, or the c-based json gem")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def uniq_key
|
41
|
+
return nil if (@exception.backtrace.nil? || @exception.backtrace.empty?)
|
42
|
+
Digest::MD5.hexdigest(@exception.backtrace.join)
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def errorapp_client_data
|
48
|
+
{
|
49
|
+
:client =>
|
50
|
+
{
|
51
|
+
:name => ErrorappNotifier::CLIENT_NAME,
|
52
|
+
:version => ErrorappNotifier::VERSION,
|
53
|
+
:protocol_version => ErrorappNotifier::PROTOCOL_VERSION
|
54
|
+
}
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
def extra_stuff
|
59
|
+
{ :rescue_block => {:name => @name} }
|
60
|
+
end
|
61
|
+
|
62
|
+
def context_stuff
|
63
|
+
context = Thread.current[:notifier_context]
|
64
|
+
(context.nil? || context.empty?) ? {} : {'context'=> context}
|
65
|
+
end
|
66
|
+
|
67
|
+
def extract_http_headers(env)
|
68
|
+
headers = {}
|
69
|
+
env.select{|k, v| k =~ /^HTTP_/}.each do |name, value|
|
70
|
+
proper_name = name.sub(/^HTTP_/, '').split('_').map{|upper_case| upper_case.capitalize}.join('-')
|
71
|
+
headers[proper_name] = value
|
72
|
+
end
|
73
|
+
unless headers['Cookie'].nil?
|
74
|
+
headers['Cookie'] = headers['Cookie'].sub(/_session=\S+/, '_session=[FILTERED]')
|
75
|
+
end
|
76
|
+
headers
|
77
|
+
end
|
78
|
+
|
79
|
+
def rescue_sanitize_hash
|
80
|
+
begin
|
81
|
+
yield
|
82
|
+
rescue Exception
|
83
|
+
{}
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'net/https'
|
3
|
+
|
4
|
+
module ErrorappNotifier
|
5
|
+
class Notifier
|
6
|
+
def initialize(data, uniq_key = nil)
|
7
|
+
@uniq_key = uniq_key
|
8
|
+
@data = data
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.notify_error(exception_data)
|
12
|
+
new(
|
13
|
+
exception_data.to_json,
|
14
|
+
exception_data.uniq_key
|
15
|
+
).notify_error
|
16
|
+
end
|
17
|
+
|
18
|
+
def notify_error
|
19
|
+
log_and_send do
|
20
|
+
client.post(url, data)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
attr_reader :data, :uniq_key
|
27
|
+
|
28
|
+
def url
|
29
|
+
"/api/projects/#{config.api_key}/fails?protocol_version=#{PROTOCOL_VERSION}#{hash_param}"
|
30
|
+
end
|
31
|
+
|
32
|
+
def hash_param
|
33
|
+
unless uniq_key.nil?
|
34
|
+
"&hash=#{uniq_key}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def log_and_send
|
39
|
+
begin
|
40
|
+
response = yield
|
41
|
+
case response
|
42
|
+
when Net::HTTPSuccess
|
43
|
+
ErrorappNotifier.logger.info("Error reported to Errorapp")
|
44
|
+
else
|
45
|
+
log_error(response.message)
|
46
|
+
end
|
47
|
+
rescue Exception => e
|
48
|
+
log_error
|
49
|
+
ErrorappNotifier.logger.error(e)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def config
|
54
|
+
ErrorappNotifier.configuration
|
55
|
+
end
|
56
|
+
|
57
|
+
def log_error(message = '')
|
58
|
+
ErrorappNotifier.logger.error(
|
59
|
+
"Problem notifying Errorapp about the error #{message}"
|
60
|
+
)
|
61
|
+
end
|
62
|
+
|
63
|
+
def client
|
64
|
+
client = optional_proxy.new(config.remote_host, config.remote_port)
|
65
|
+
client.open_timeout = config.http_open_timeout
|
66
|
+
client.read_timeout = config.http_read_timeout
|
67
|
+
client.use_ssl = config.ssl?
|
68
|
+
client.verify_mode = OpenSSL::SSL::VERIFY_NONE if config.ssl?
|
69
|
+
client
|
70
|
+
end
|
71
|
+
|
72
|
+
def optional_proxy
|
73
|
+
Net::HTTP::Proxy(config.http_proxy_host,
|
74
|
+
config.http_proxy_port,
|
75
|
+
config.http_proxy_username,
|
76
|
+
config.http_proxy_password
|
77
|
+
)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'rack'
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
class RailsErrorappNotifier
|
5
|
+
def initialize(app)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
begin
|
11
|
+
body = @app.call(env)
|
12
|
+
rescue Exception => e
|
13
|
+
::ErrorappNotifier::Notify.notify_with_controller(
|
14
|
+
e,
|
15
|
+
env['action_controller.instance'],
|
16
|
+
Rack::Request.new(env)
|
17
|
+
)
|
18
|
+
raise
|
19
|
+
end
|
20
|
+
|
21
|
+
if env['rack.exception']
|
22
|
+
::ErrorappNotifier::Notify.notify_with_controller(
|
23
|
+
env['rack.exception'],
|
24
|
+
env['action_controller.instance'],
|
25
|
+
Rack::Request.new(env)
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
body
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# force Rails < 2.0 to use quote keys as per the JSON standard...
|
2
|
+
if defined?(ActiveSupport) &&
|
3
|
+
defined?(ActiveSupport::JSON) &&
|
4
|
+
ActiveSupport::JSON.respond_to?(:unquote_hash_key_identifiers)
|
5
|
+
ActiveSupport::JSON.unquote_hash_key_identifiers = false
|
6
|
+
end
|
7
|
+
|
8
|
+
if defined? ActionController
|
9
|
+
module ActionController
|
10
|
+
class Base
|
11
|
+
def rescue_action_with_errorapp(exception)
|
12
|
+
unless exception_handled_by_rescue_from?(exception)
|
13
|
+
ErrorappNotifier::Notify.notify_with_controller(
|
14
|
+
exception,
|
15
|
+
self,
|
16
|
+
request
|
17
|
+
)
|
18
|
+
ErrorappNotifier.context.clear!
|
19
|
+
end
|
20
|
+
rescue_action_without_errorapp exception
|
21
|
+
end
|
22
|
+
|
23
|
+
alias_method :rescue_action_without_errorapp, :rescue_action
|
24
|
+
alias_method :rescue_action, :rescue_action_with_errorapp
|
25
|
+
protected :rescue_action
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def exception_handled_by_rescue_from?(exception)
|
30
|
+
respond_to?(:handler_for_rescue) && handler_for_rescue(exception)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|