rack_hoptoad 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Corey Donohoe
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,17 @@
1
+ rack_hoptoad
2
+ ============
3
+
4
+ A gem that provides exception notifications to [hoptoad](http://hoptoadapp.com) as rack middleware.
5
+
6
+ Usage
7
+ =====
8
+ Throw something like this in your config.ru to enable notifications.
9
+
10
+ require 'rack_hoptoad'
11
+
12
+ ENV['RACK_ENV'] = 'production'
13
+
14
+ use Rack::HoptoadNotifier, 'fd48c7d26f724503a0280f808f44b339fc65fab8'
15
+
16
+ If your RACK_ENV variable is set to production it'll actually post to hoptoad.
17
+ It won't process in the other environments.
@@ -0,0 +1,65 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+ require 'rubygems/specification'
4
+ require 'spec/rake/spectask'
5
+ require 'date'
6
+
7
+ GEM = "rack_hoptoad"
8
+ GEM_VERSION = "0.0.1"
9
+ AUTHOR = "Corey Donohoe"
10
+ EMAIL = "atmos@atmos.org"
11
+ HOMEPAGE = "http://github.com/atmos/rack_hoptoad"
12
+ SUMMARY = "A gem that provides hoptoad notifications from rack"
13
+
14
+ spec = Gem::Specification.new do |s|
15
+ s.name = GEM
16
+ s.version = GEM_VERSION
17
+ s.platform = Gem::Platform::RUBY
18
+ s.has_rdoc = true
19
+ s.extra_rdoc_files = ["LICENSE", 'TODO']
20
+ s.summary = SUMMARY
21
+ s.description = s.summary
22
+ s.author = AUTHOR
23
+ s.email = EMAIL
24
+ s.homepage = HOMEPAGE
25
+
26
+ # Uncomment this to add a dependency
27
+ s.add_dependency "rack"
28
+
29
+ s.require_path = 'lib'
30
+ s.autorequire = GEM
31
+ s.files = %w(LICENSE README.md Rakefile TODO) + Dir.glob("{lib,specs}/**/*")
32
+ end
33
+
34
+ Rake::GemPackageTask.new(spec) do |pkg|
35
+ pkg.gem_spec = spec
36
+ end
37
+
38
+ desc "install the gem locally"
39
+ task :install => [:package] do
40
+ sh %{sudo gem install pkg/#{GEM}-#{GEM_VERSION}}
41
+ end
42
+
43
+ desc "create a gemspec file"
44
+ task :make_spec do
45
+ File.open("#{GEM}.gemspec", "w") do |file|
46
+ file.puts spec.to_ruby
47
+ end
48
+ end
49
+
50
+ task :default => 'rack_hoptoad:spec'
51
+
52
+ namespace :rack_hoptoad do
53
+ desc "Run unit specifications"
54
+ Spec::Rake::SpecTask.new(:spec) do |t|
55
+ t.spec_opts << %w(-fs --color)
56
+ t.spec_opts << '--loadby' << 'random'
57
+ t.spec_files = Dir["spec/*_spec.rb"]
58
+
59
+ t.rcov_opts << '--exclude' << 'spec'
60
+ t.rcov = ENV.has_key?('NO_RCOV') ? ENV['NO_RCOV'] != 'true' : true
61
+ t.rcov_opts << '--text-summary'
62
+ t.rcov_opts << '--sort' << 'coverage' << '--sort-reverse'
63
+ # t.rcov_opts << '--only-uncovered'
64
+ end
65
+ end
data/TODO ADDED
@@ -0,0 +1 @@
1
+ TODO:
@@ -0,0 +1,139 @@
1
+ require 'net/http'
2
+
3
+ module Rack
4
+ # Catches all exceptions raised from the app it wraps and
5
+ # posts the results to hoptoad.
6
+ class HoptoadNotifier
7
+ attr_accessor :api_key, :environment_filters
8
+
9
+ def initialize(app, api_key = nil)
10
+ @app = app
11
+ @api_key = api_key
12
+ yield self if block_given?
13
+ end
14
+
15
+ def call(env)
16
+ status, headers, body =
17
+ begin
18
+ @app.call(env)
19
+ rescue => boom
20
+ # TODO don't allow exceptions from send_notification to
21
+ # propogate
22
+ send_notification boom, env
23
+ raise
24
+ end
25
+ send_notification env['rack.exception'], env if env['rack.exception']
26
+ [status, headers, body]
27
+ end
28
+
29
+ private
30
+ def environment_filters
31
+ @environment_filters ||= %w(AWS_ACCESS_KEY AWS_SECRET_ACCESS_KEY AWS_ACCOUNT SSH_AUTH_SOCK)
32
+ end
33
+
34
+ def send_notification(exception, env)
35
+ data = {
36
+ :api_key => api_key,
37
+ :error_class => exception.class.name,
38
+ :error_message => "#{exception.class.name}: #{exception.message}",
39
+ :backtrace => exception.backtrace,
40
+ :environment => env.to_hash
41
+ }
42
+
43
+ data[:request] = {
44
+ :params => Rack::Request.new(env).params
45
+ }
46
+
47
+ data[:environment] = clean_hoptoad_environment(ENV.to_hash.merge(env))
48
+ data[:environment][:RAILS_ENV] = ENV['RACK_ENV'] || 'development'
49
+
50
+ data[:session] = {
51
+ :key => env['rack.session'] || 42,
52
+ :data => env['rack.session'] || { }
53
+ }
54
+
55
+ if %w(staging production).include?(ENV['RACK_ENV'])
56
+ send_to_hoptoad :notice => default_notice_options.merge(data)
57
+ end
58
+ env['hoptoad.notified'] = true
59
+ end
60
+
61
+ def extract_body(env)
62
+ if io = env['rack.input']
63
+ io.rewind if io.respond_to?(:rewind)
64
+ io.read
65
+ end
66
+ end
67
+
68
+ def send_to_hoptoad(data) #:nodoc:
69
+ url = URI.parse("http://hoptoadapp.com:80/notices/")
70
+
71
+ Net::HTTP.start(url.host, url.port) do |http|
72
+ headers = {
73
+ 'Content-type' => 'application/x-yaml',
74
+ 'Accept' => 'text/xml, application/xml'
75
+ }
76
+ http.read_timeout = 5 # seconds
77
+ http.open_timeout = 2 # seconds
78
+ # http.use_ssl = HoptoadNotifier.secure
79
+ response = begin
80
+ http.post(url.path, clean_non_serializable_data(data).to_yaml, headers)
81
+ rescue TimeoutError => e
82
+ logger "Timeout while contacting the Hoptoad server."
83
+ nil
84
+ end
85
+ case response
86
+ when Net::HTTPSuccess then
87
+ logger "Hoptoad Success: #{response.class}"
88
+ else
89
+ logger "Hoptoad Failure: #{response.class}\n#{response.body if response.respond_to? :body}"
90
+ end
91
+ end
92
+ end
93
+
94
+ def logger(str)
95
+ puts str if ENV['RACK_DEBUG']
96
+ end
97
+
98
+ def default_notice_options #:nodoc:
99
+ {
100
+ :api_key => api_key,
101
+ :error_message => 'Notification',
102
+ :backtrace => nil,
103
+ :request => {},
104
+ :session => {},
105
+ :environment => {}
106
+ }
107
+ end
108
+
109
+ def clean_non_serializable_data(notice) #:nodoc:
110
+ notice.select{|k,v| serializable?(v) }.inject({}) do |h, pair|
111
+ h[pair.first] = pair.last.is_a?(Hash) ? clean_non_serializable_data(pair.last) : pair.last
112
+ h
113
+ end
114
+ end
115
+
116
+ def serializable?(value) #:nodoc:
117
+ value.is_a?(Fixnum) ||
118
+ value.is_a?(Array) ||
119
+ value.is_a?(String) ||
120
+ value.is_a?(Hash) ||
121
+ value.is_a?(Bignum)
122
+ end
123
+
124
+ def stringify_keys(hash) #:nodoc:
125
+ hash.inject({}) do |h, pair|
126
+ h[pair.first.to_s] = pair.last.is_a?(Hash) ? stringify_keys(pair.last) : pair.last
127
+ h
128
+ end
129
+ end
130
+
131
+ def clean_hoptoad_environment(environ) #:nodoc:
132
+ environ.each do |k, v|
133
+ environ[k] = "[FILTERED]" if environment_filters.any? do |filter|
134
+ k.to_s.match(/#{filter}/)
135
+ end
136
+ end
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,5 @@
1
+ gem 'rack', '~>1.0.0'
2
+ require 'rack'
3
+
4
+ root = File.expand_path(File.dirname(__FILE__))
5
+ require root + '/rack/hoptoad_notifier.rb'
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack_hoptoad
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Corey Donohoe
8
+ autorequire: rack_hoptoad
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-05-11 00:00:00 -06:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rack
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ description: A gem that provides hoptoad notifications from rack
26
+ email: atmos@atmos.org
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - LICENSE
33
+ - TODO
34
+ files:
35
+ - LICENSE
36
+ - README.md
37
+ - Rakefile
38
+ - TODO
39
+ - lib/rack
40
+ - lib/rack/hoptoad_notifier.rb
41
+ - lib/rack_hoptoad.rb
42
+ has_rdoc: true
43
+ homepage: http://github.com/atmos/rack_hoptoad
44
+ post_install_message:
45
+ rdoc_options: []
46
+
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: "0"
54
+ version:
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: "0"
60
+ version:
61
+ requirements: []
62
+
63
+ rubyforge_project:
64
+ rubygems_version: 1.3.1
65
+ signing_key:
66
+ specification_version: 2
67
+ summary: A gem that provides hoptoad notifications from rack
68
+ test_files: []
69
+