errorapp_notifier 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|