Skip to content

Commit 0290c19

Browse files
committed
use shooter
1 parent d87c47c commit 0290c19

24 files changed

+629
-0
lines changed

app/controllers/application_controller.rb

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
class ApplicationController < ActionController::Base
55
include SslRequirement
6+
include ExceptionNotifiable
67

78
helper :all # include all helpers, all the time
89
protect_from_forgery # See ActionController::RequestForgeryProtection for details

config/initializers/shooter.rb

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ExceptionNotifier.api_key = site_config[:shooter_api_key]

config/site_config.yml.example

+2
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,7 @@ smtp_port: '25'
77
smtp_user_name: "[email protected]"
88
smtp_password: "example"
99

10+
shooter_api_key: "shooterapi.com api key"
11+
1012
tracking_code: |
1113
<!-- Sample Tracking Code -->
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
lib/**/*.rb
2+
rails/*
3+
views/**/*
4+
bin/*
5+
features/**/*.feature
6+
LICENSE
7+
README

vendor/plugins/shooterplugin/LICENSE

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
Copyright (c) 2009 Paul Campbell
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.

vendor/plugins/shooterplugin/README

+113
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
= Exception Notifier Plugin for Rails, using Shooter
2+
3+
Shooter is a web application that allows creation of "Shooters". Each shooter
4+
can store a single payload, which can be set using a REST API. When the payload
5+
is set, the account owner is notified by email. Any further attempts to set
6+
the payload will be rejected until the current payload is "shot" away.
7+
8+
The concept is that:
9+
1) Exceptions should never happen
10+
2) Most of the time, only the most recent exception is of interest
11+
3) Focus should be on clearing, or ignoring the current exception
12+
13+
The Exception Notifier plugin for Shooter provides a hook into the REST API
14+
and a default set of templates for sending notifications when errors occur in a Rails
15+
application. The plugin is configurable, allowing programmers to specify:
16+
17+
* the API key of the Shooter to notify
18+
* custom variables
19+
20+
The notification includes information about the current request, session, and
21+
environment, and also gives a backtrace of the exception.
22+
23+
== Usage
24+
25+
First, include the ExceptionNotifiable mixin in whichever controller you want
26+
to generate error emails (typically ApplicationController):
27+
28+
class ApplicationController < ActionController::Base
29+
include ExceptionNotifiable
30+
...
31+
end
32+
33+
Then, specify your API key in your environment:
34+
35+
ExceptionNotifier.api_key = 'API_KEY'
36+
37+
And that's it! The defaults take care of the rest.
38+
39+
== Configuration
40+
41+
You can tweak other values to your liking, as well. In your environment file,
42+
just set any or all of the following values:
43+
44+
Notifications will only occur when the IP address is determined not to
45+
be local. You can specify certain addresses to always be local so that you'll
46+
get a detailed error instead of the generic error page. You do this in your
47+
controller (or even per-controller):
48+
49+
consider_local "64.72.18.143", "14.17.21.25"
50+
51+
You can specify subnet masks as well, so that all matching addresses are
52+
considered local:
53+
54+
consider_local "64.72.18.143/24"
55+
56+
The address "127.0.0.1" is always considered local. If you want to completely
57+
reset the list of all addresses (for instance, if you wanted "127.0.0.1" to
58+
NOT be considered local), you can simply do, somewhere in your controller:
59+
60+
local_addresses.clear
61+
62+
== Customization
63+
64+
By default, the notification email includes four parts: request, session,
65+
environment, and backtrace (in that order). You can customize how each of those
66+
sections are rendered by placing a partial named for that part in your
67+
app/views/exception_notifier directory (e.g., _session.rhtml). Each partial has
68+
access to the following variables:
69+
70+
* @controller: the controller that caused the error
71+
* @request: the current request object
72+
* @exception: the exception that was raised
73+
* @host: the name of the host that made the request
74+
* @backtrace: a sanitized version of the exception's backtrace
75+
* @rails_root: a sanitized version of RAILS_ROOT
76+
* @data: a hash of optional data values that were passed to the notifier
77+
* @sections: the array of sections to include in the email
78+
79+
You can reorder the sections, or exclude sections completely, by altering the
80+
ExceptionNotifier.sections variable. You can even add new sections that
81+
describe application-specific data--just add the section's name to the list
82+
(whereever you'd like), and define the corresponding partial. Then, if your
83+
new section requires information that isn't available by default, make sure
84+
it is made available to the email using the exception_data macro:
85+
86+
class ApplicationController < ActionController::Base
87+
...
88+
protected
89+
exception_data :additional_data
90+
91+
def additional_data
92+
{ :document => @document,
93+
:person => @person }
94+
end
95+
...
96+
end
97+
98+
In the above case, @document and @person would be made available to the email
99+
renderer, allowing your new section(s) to access and display them. See the
100+
existing sections defined by the plugin for examples of how to write your own.
101+
102+
== Advanced Customization
103+
104+
By default, the email notifier will only notify on critical errors. For
105+
ActiveRecord::RecordNotFound and ActionController::UnknownAction, it will
106+
simply render the contents of your public/404.html file. Other exceptions
107+
will render public/500.html and will send the email notification. If you want
108+
to use different rules for the notification, you will need to implement your
109+
own rescue_action_in_public method. You can look at the default implementation
110+
in ExceptionNotifiable for an example of how to go about that.
111+
112+
113+
Copyright (c) 2005 Jamis Buck, released under the MIT license

vendor/plugins/shooterplugin/Rakefile

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
require 'rubygems'
2+
require 'rake'
3+
4+
begin
5+
require 'jeweler'
6+
Jeweler::Tasks.new do |gem|
7+
gem.name = "exception_shooter"
8+
gem.summary = %Q{Exception Shooter is a gem / plugin that posts exceptions to Shooter}
9+
gem.description = %Q{Shooter lets you deal with one exception at a time}
10+
gem.email = "[email protected]"
11+
gem.homepage = "http://github.com/paulca/exception_shooter"
12+
gem.authors = ["Paul Campbell"]
13+
14+
end
15+
rescue LoadError
16+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
17+
end
18+
19+
require 'rake/testtask'
20+
Rake::TestTask.new(:test) do |test|
21+
test.libs << 'lib' << 'test'
22+
test.pattern = 'test/**/*_test.rb'
23+
test.verbose = true
24+
end
25+
26+
begin
27+
require 'rcov/rcovtask'
28+
Rcov::RcovTask.new do |test|
29+
test.libs << 'test'
30+
test.pattern = 'test/**/*_test.rb'
31+
test.verbose = true
32+
end
33+
rescue LoadError
34+
task :rcov do
35+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
36+
end
37+
end
38+
39+
task :test => :check_dependencies
40+
41+
task :default => :test
42+
43+
require 'rake/rdoctask'
44+
Rake::RDocTask.new do |rdoc|
45+
if File.exist?('VERSION')
46+
version = File.read('VERSION')
47+
else
48+
version = ""
49+
end
50+
51+
rdoc.rdoc_dir = 'rdoc'
52+
rdoc.title = "exception_shooter #{version}"
53+
rdoc.rdoc_files.include('README*')
54+
rdoc.rdoc_files.include('lib/**/*.rb')
55+
end

vendor/plugins/shooterplugin/VERSION

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
0.0.1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Generated by jeweler
2+
# DO NOT EDIT THIS FILE
3+
# Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
4+
# -*- encoding: utf-8 -*-
5+
6+
Gem::Specification.new do |s|
7+
s.name = %q{exception_shooter}
8+
s.version = "0.0.1"
9+
10+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11+
s.authors = ["Paul Campbell"]
12+
s.date = %q{2009-10-17}
13+
s.description = %q{Shooter lets you deal with one exception at a time}
14+
s.email = %q{[email protected]}
15+
s.extra_rdoc_files = [
16+
"LICENSE",
17+
"README"
18+
]
19+
s.files = [
20+
".document",
21+
".gitignore",
22+
"LICENSE",
23+
"README",
24+
"Rakefile",
25+
"VERSION",
26+
"lib/exception_notifiable.rb",
27+
"lib/exception_notifier.rb",
28+
"lib/exception_notifier_helper.rb",
29+
"lib/exception_shooter.rb",
30+
"rails/init.rb",
31+
"test/exception_notifier_helper_test.rb",
32+
"test/exception_shooter_test.rb",
33+
"test/test_helper.rb",
34+
"views/exception_notifier/_backtrace.rhtml",
35+
"views/exception_notifier/_environment.rhtml",
36+
"views/exception_notifier/_inspect_model.rhtml",
37+
"views/exception_notifier/_request.rhtml",
38+
"views/exception_notifier/_session.rhtml",
39+
"views/exception_notifier/_title.rhtml",
40+
"views/exception_notifier/exception_notification.rhtml"
41+
]
42+
s.homepage = %q{http://github.com/paulca/exception_shooter}
43+
s.rdoc_options = ["--charset=UTF-8"]
44+
s.require_paths = ["lib"]
45+
s.rubygems_version = %q{1.3.5}
46+
s.summary = %q{Exception Shooter is a gem / plugin that posts exceptions to Shooter}
47+
s.test_files = [
48+
"test/exception_notifier_helper_test.rb",
49+
"test/exception_shooter_test.rb",
50+
"test/test_helper.rb"
51+
]
52+
53+
if s.respond_to? :specification_version then
54+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
55+
s.specification_version = 3
56+
57+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
58+
else
59+
end
60+
else
61+
end
62+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
require 'ipaddr'
2+
3+
# Copyright (c) 2005 Jamis Buck
4+
#
5+
# Permission is hereby granted, free of charge, to any person obtaining
6+
# a copy of this software and associated documentation files (the
7+
# "Software"), to deal in the Software without restriction, including
8+
# without limitation the rights to use, copy, modify, merge, publish,
9+
# distribute, sublicense, and/or sell copies of the Software, and to
10+
# permit persons to whom the Software is furnished to do so, subject to
11+
# the following conditions:
12+
#
13+
# The above copyright notice and this permission notice shall be
14+
# included in all copies or substantial portions of the Software.
15+
#
16+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23+
module ExceptionNotifiable
24+
def self.included(target)
25+
target.extend(ClassMethods)
26+
end
27+
28+
module ClassMethods
29+
def consider_local(*args)
30+
local_addresses.concat(args.flatten.map { |a| IPAddr.new(a) })
31+
end
32+
33+
def local_addresses
34+
addresses = read_inheritable_attribute(:local_addresses)
35+
unless addresses
36+
addresses = [IPAddr.new("127.0.0.1")]
37+
write_inheritable_attribute(:local_addresses, addresses)
38+
end
39+
addresses
40+
end
41+
42+
def exception_data(deliverer=self)
43+
if deliverer == self
44+
read_inheritable_attribute(:exception_data)
45+
else
46+
write_inheritable_attribute(:exception_data, deliverer)
47+
end
48+
end
49+
50+
def exceptions_to_treat_as_404
51+
exceptions = [ActiveRecord::RecordNotFound,
52+
ActionController::UnknownController,
53+
ActionController::UnknownAction]
54+
exceptions << ActionController::RoutingError if ActionController.const_defined?(:RoutingError)
55+
exceptions
56+
end
57+
end
58+
59+
private
60+
61+
def local_request?
62+
remote = IPAddr.new(request.remote_ip)
63+
!self.class.local_addresses.detect { |addr| addr.include?(remote) }.nil?
64+
end
65+
66+
def render_404
67+
respond_to do |type|
68+
type.html { render :file => "#{RAILS_ROOT}/public/404.html", :status => "404 Not Found" }
69+
type.all { render :nothing => true, :status => "404 Not Found" }
70+
end
71+
end
72+
73+
def render_500
74+
respond_to do |type|
75+
type.html { render :file => "#{RAILS_ROOT}/public/500.html", :status => "500 Error" }
76+
type.all { render :nothing => true, :status => "500 Error" }
77+
end
78+
end
79+
80+
def rescue_action_in_public(exception)
81+
logger.info "rescuing action in public"
82+
case exception
83+
when *self.class.exceptions_to_treat_as_404
84+
render_404
85+
86+
else
87+
render_500
88+
89+
deliverer = self.class.exception_data
90+
data = case deliverer
91+
when nil then {}
92+
when Symbol then send(deliverer)
93+
when Proc then deliverer.call(self)
94+
end
95+
96+
notification = ExceptionNotifier.create_exception_notification(exception, self,
97+
request, data)
98+
logger.info("sending data to shooter")
99+
RestClient.put("http://shooterapi.com/api/shooters/#{ExceptionNotifier.api_key}", {:payload => notification.body})
100+
end
101+
end
102+
end

0 commit comments

Comments
 (0)