chatterbox 0.5.1 → 0.5.3
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.markdown +5 -0
- data/README.markdown +8 -3
- data/chatterbox.gemspec +6 -4
- data/examples/lib/chatterbox/exception_notification/{filter_example.rb → extracter_example.rb} +0 -0
- data/examples/lib/chatterbox/exception_notification/rails_extracter_example.rb +34 -0
- data/examples/lib/chatterbox/rails_catcher_controller_example.rb +109 -0
- data/examples/lib/chatterbox/rails_catcher_example.rb +21 -46
- data/lib/chatterbox/exception_notification/rails_extracter.rb +20 -12
- data/lib/chatterbox/rails_catcher.rb +35 -6
- data/version.yml +1 -1
- metadata +6 -4
data/CHANGELOG.markdown
CHANGED
data/README.markdown
CHANGED
@@ -1,10 +1,9 @@
|
|
1
1
|
Chatterbox
|
2
2
|
==========================================
|
3
3
|
|
4
|
-
Simple Notifications. Publishing and subscribing to notifications is decoupled by default, so bring your own message queue, web service, database, or whatever to act as an intermediary.
|
4
|
+
Simple Notifications. Publishing and subscribing to notifications is decoupled by default, so bring your own message queue, web service, database, or whatever to act as an intermediary. Of course, you can wire Chatterbox to work directly if you like.
|
5
5
|
|
6
|
-
Installing and Running
|
7
|
-
---------------------------------------
|
6
|
+
## Installing and Running
|
8
7
|
|
9
8
|
For plain old gem install:
|
10
9
|
|
@@ -18,6 +17,12 @@ Then run:
|
|
18
17
|
|
19
18
|
rake gems:install
|
20
19
|
|
20
|
+
## Exception Notification
|
21
|
+
|
22
|
+
One of the first use cases that Chatterbox was developed for was exception notification. To setup Chatterbox for exception notification, install it as a gem with the instructions above, then configure a service.
|
23
|
+
|
24
|
+
then wire the `RailsCatcher` in your `ApplicationController`:
|
25
|
+
|
21
26
|
To enable standard Rails exception catching for your controllers, add the following to `application_controller`
|
22
27
|
|
23
28
|
class ApplicationController < ActionController::Base
|
data/chatterbox.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{chatterbox}
|
8
|
-
s.version = "0.5.
|
8
|
+
s.version = "0.5.3"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Rob Sanheim"]
|
12
|
-
s.date = %q{2009-11-
|
12
|
+
s.date = %q{2009-11-13}
|
13
13
|
s.description = %q{Send notifications and messages. However you want.}
|
14
14
|
s.email = %q{rsanheim@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -25,9 +25,10 @@ Gem::Specification.new do |s|
|
|
25
25
|
"Rakefile",
|
26
26
|
"chatterbox.gemspec",
|
27
27
|
"examples/example_helper.rb",
|
28
|
-
"examples/lib/chatterbox/exception_notification/
|
28
|
+
"examples/lib/chatterbox/exception_notification/extracter_example.rb",
|
29
29
|
"examples/lib/chatterbox/exception_notification/presenter_example.rb",
|
30
30
|
"examples/lib/chatterbox/exception_notification/rails_extracter_example.rb",
|
31
|
+
"examples/lib/chatterbox/rails_catcher_controller_example.rb",
|
31
32
|
"examples/lib/chatterbox/rails_catcher_example.rb",
|
32
33
|
"examples/lib/chatterbox/services/email/mailer_example.rb",
|
33
34
|
"examples/lib/chatterbox/services/email_example.rb",
|
@@ -56,9 +57,10 @@ Gem::Specification.new do |s|
|
|
56
57
|
s.summary = %q{Notifications and messages}
|
57
58
|
s.test_files = [
|
58
59
|
"examples/example_helper.rb",
|
59
|
-
"examples/lib/chatterbox/exception_notification/
|
60
|
+
"examples/lib/chatterbox/exception_notification/extracter_example.rb",
|
60
61
|
"examples/lib/chatterbox/exception_notification/presenter_example.rb",
|
61
62
|
"examples/lib/chatterbox/exception_notification/rails_extracter_example.rb",
|
63
|
+
"examples/lib/chatterbox/rails_catcher_controller_example.rb",
|
62
64
|
"examples/lib/chatterbox/rails_catcher_example.rb",
|
63
65
|
"examples/lib/chatterbox/services/email/mailer_example.rb",
|
64
66
|
"examples/lib/chatterbox/services/email_example.rb",
|
data/examples/lib/chatterbox/exception_notification/{filter_example.rb → extracter_example.rb}
RENAMED
File without changes
|
@@ -36,6 +36,40 @@ describe Chatterbox::ExceptionNotification::RailsExtracter do
|
|
36
36
|
details[:request][:remote_ip].should == "192.5.5.0"
|
37
37
|
end
|
38
38
|
end
|
39
|
+
|
40
|
+
describe "cleaning RAILS_ROOT" do
|
41
|
+
it "does nothing if there is no Rails configuration" do
|
42
|
+
backtrace = %w[/some/path/here.rb]
|
43
|
+
lambda {
|
44
|
+
Chatterbox::ExceptionNotification::RailsExtracter.wrap({:backtrace => backtrace})
|
45
|
+
}.should_not raise_error
|
46
|
+
end
|
47
|
+
|
48
|
+
it "does nothing if there is no rails_root on Rails" do
|
49
|
+
Chatterbox::ExceptionNotification::RailsExtracter.any_instance.stubs(:rails_configuration).returns(stub_everything)
|
50
|
+
backtrace = %w[/some/path/here.rb]
|
51
|
+
lambda {
|
52
|
+
Chatterbox::ExceptionNotification::RailsExtracter.wrap({:backtrace => backtrace})
|
53
|
+
}.should_not raise_error
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should replace the Rails root from the backtrace with RAILS_ROOT" do
|
57
|
+
rails = stub_everything({ :root => "/var/apps/dogs.com" })
|
58
|
+
Chatterbox::ExceptionNotification::RailsExtracter.any_instance.stubs(:rails_configuration).returns(rails)
|
59
|
+
backtrace = %w[
|
60
|
+
/Users/rsanheim/.rvm/gems/ruby/1.9.1/gems/actionpack-2.3.4/lib/action_controller/test_process.rb:398:in `get'
|
61
|
+
/var/apps/dogs.com/app/controllers/users_controller.rb:5:in `index'
|
62
|
+
/var/apps/dogs.com/app/controllers/users_controller.rb:27:in `foo_baz'
|
63
|
+
/var/apps/dogs.com/lib/some_module.rb:10:in `something_else']
|
64
|
+
details = Chatterbox::ExceptionNotification::RailsExtracter.wrap({:backtrace => backtrace})
|
65
|
+
rails_lines = details[:backtrace].select { |line| line.include?("users_controller.rb") }
|
66
|
+
rails_lines.should_not be_empty
|
67
|
+
rails_lines.each do |line|
|
68
|
+
line.should_not match(%r{^/var/apps/dogs.com/})
|
69
|
+
line.should match(%r{^\[RAILS_ROOT\]})
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
39
73
|
end
|
40
74
|
|
41
75
|
describe "rails_configuration" do
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'example_helper'
|
2
|
+
require 'chatterbox/exception_notification'
|
3
|
+
require File.expand_path(File.join(File.dirname(__FILE__), *%w[.. .. .. rails init]))
|
4
|
+
|
5
|
+
ActionController::Routing::Routes.draw { |map| map.connect ':controller/:action/:id' }
|
6
|
+
|
7
|
+
class WidgetException < RuntimeError; end
|
8
|
+
class WidgetsController < ActionController::Base
|
9
|
+
include Chatterbox::RailsCatcher
|
10
|
+
|
11
|
+
def rescue_action(exception)
|
12
|
+
rescue_action_in_public(exception)
|
13
|
+
end
|
14
|
+
|
15
|
+
def rescue_action_in_public_without_chatterbox(exception)
|
16
|
+
raise exception
|
17
|
+
end
|
18
|
+
|
19
|
+
def index
|
20
|
+
raise_exception
|
21
|
+
render :text => "hi"
|
22
|
+
end
|
23
|
+
|
24
|
+
def raise_exception
|
25
|
+
raise WidgetException, "Bad dog!"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe WidgetsController do
|
30
|
+
|
31
|
+
describe "controller haxing" do
|
32
|
+
it "chains the chatterbox method to rescue_action_in_public" do
|
33
|
+
exception = RuntimeError.new
|
34
|
+
@controller.expects(:rescue_action_in_public_without_chatterbox).with(exception)
|
35
|
+
@controller.stubs(:extract_exception_details)
|
36
|
+
@controller.rescue_action_in_public(exception)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should have the catcher included in ApplicationController" do
|
40
|
+
WidgetsController.ancestors.should include(Chatterbox::RailsCatcher)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should hide aliased methods so they are not exposed as actions" do
|
44
|
+
WidgetsController.hidden_actions.should include("rescue_action_in_public_with_chatterbox")
|
45
|
+
WidgetsController.hidden_actions.should include("rescue_action_in_public_without_chatterbox")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "exception handling" do
|
50
|
+
it "should raise on index" do
|
51
|
+
lambda {
|
52
|
+
get :index
|
53
|
+
}.should raise_error(WidgetException, "Bad dog!")
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should send exception notice as hash" do
|
57
|
+
Chatterbox.expects(:handle_notice).with(instance_of(Hash))
|
58
|
+
get :index rescue nil
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "ignoring exceptions" do
|
63
|
+
describe "when configured to ignore RuntimeError (as class)" do
|
64
|
+
before do
|
65
|
+
Chatterbox::RailsCatcher.configure { |c| c.ignore << RuntimeError }
|
66
|
+
end
|
67
|
+
|
68
|
+
after do
|
69
|
+
Chatterbox::RailsCatcher.configure { |c| c.ignore = Chatterbox::RailsCatcher.default_ignored_exceptions }
|
70
|
+
end
|
71
|
+
|
72
|
+
it "handles exceptions normally" do
|
73
|
+
lambda {
|
74
|
+
@controller.rescue_action_in_public(RuntimeError.new)
|
75
|
+
}.should raise_error(RuntimeError)
|
76
|
+
end
|
77
|
+
|
78
|
+
it "ignores anything configured on the ignore list" do
|
79
|
+
Chatterbox.expects(:handle_notice).never
|
80
|
+
begin
|
81
|
+
@controller.rescue_action_in_public(RuntimeError.new)
|
82
|
+
rescue RuntimeError; end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "when configured to ignore RuntimeError (as String)" do
|
87
|
+
before do
|
88
|
+
Chatterbox::RailsCatcher.configure { |c| c.ignore << "RuntimeError" }
|
89
|
+
end
|
90
|
+
|
91
|
+
after do
|
92
|
+
Chatterbox::RailsCatcher.configure { |c| c.ignore = Chatterbox::RailsCatcher.default_ignored_exceptions }
|
93
|
+
end
|
94
|
+
|
95
|
+
it "handles exceptions normally" do
|
96
|
+
lambda {
|
97
|
+
@controller.rescue_action_in_public(RuntimeError.new)
|
98
|
+
}.should raise_error(RuntimeError)
|
99
|
+
end
|
100
|
+
|
101
|
+
it "ignores anything configured on the ignore list" do
|
102
|
+
Chatterbox.expects(:handle_notice).never
|
103
|
+
begin
|
104
|
+
@controller.rescue_action_in_public(RuntimeError.new)
|
105
|
+
rescue RuntimeError; end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -2,60 +2,35 @@ require 'example_helper'
|
|
2
2
|
require 'chatterbox/exception_notification'
|
3
3
|
require File.expand_path(File.join(File.dirname(__FILE__), *%w[.. .. .. rails init]))
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
class WidgetException < RuntimeError; end
|
8
|
-
class WidgetsController < ActionController::Base
|
9
|
-
include Chatterbox::RailsCatcher
|
10
|
-
|
11
|
-
def rescue_action e
|
12
|
-
rescue_action_in_public e
|
13
|
-
end
|
14
|
-
|
15
|
-
def rescue_action_in_public_without_chatterbox e
|
16
|
-
raise e
|
17
|
-
end
|
5
|
+
describe Chatterbox::RailsCatcher do
|
18
6
|
|
19
|
-
def
|
20
|
-
|
21
|
-
|
7
|
+
def helper
|
8
|
+
@helper ||= Class.new {
|
9
|
+
include Chatterbox::RailsCatcher
|
10
|
+
}.new
|
22
11
|
end
|
23
12
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
describe WidgetsController do
|
30
|
-
|
31
|
-
describe "controller haxing" do
|
32
|
-
it "chains the chatterbox method to rescue_action_in_public" do
|
33
|
-
exception = RuntimeError.new
|
34
|
-
@controller.expects(:rescue_action_in_public_without_chatterbox).with(exception)
|
35
|
-
@controller.stubs(:extract_exception_details)
|
36
|
-
@controller.rescue_action_in_public(exception)
|
37
|
-
end
|
38
|
-
|
39
|
-
it "should have the catcher included in ApplicationController" do
|
40
|
-
WidgetsController.ancestors.should include(Chatterbox::RailsCatcher)
|
41
|
-
end
|
42
|
-
|
43
|
-
it "should hide aliased methods so they are not exposed as actions" do
|
44
|
-
WidgetsController.hidden_actions.should include("rescue_action_in_public_with_chatterbox")
|
45
|
-
WidgetsController.hidden_actions.should include("rescue_action_in_public_without_chatterbox")
|
13
|
+
describe "logger" do
|
14
|
+
it "should delegate to Chatterbox#logger" do
|
15
|
+
Chatterbox.expects(:logger)
|
16
|
+
helper.logger
|
46
17
|
end
|
47
18
|
end
|
48
19
|
|
49
|
-
describe "
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
20
|
+
describe "configuration" do
|
21
|
+
after do
|
22
|
+
Chatterbox::RailsCatcher.configure { |c| c.ignore = Chatterbox::RailsCatcher.default_ignored_exceptions }
|
23
|
+
end
|
24
|
+
|
25
|
+
it "ignores common Rails exceptions by default" do
|
26
|
+
Chatterbox::RailsCatcher.configuration.ignore.should == Chatterbox::RailsCatcher.default_ignored_exceptions
|
54
27
|
end
|
55
28
|
|
56
|
-
it "
|
57
|
-
Chatterbox.
|
58
|
-
|
29
|
+
it "allows adding exceptions to the ignore list" do
|
30
|
+
Chatterbox::RailsCatcher.configure do |config|
|
31
|
+
config.ignore << "SomeOtherException"
|
32
|
+
end
|
33
|
+
Chatterbox::RailsCatcher.configuration.ignore.should include("SomeOtherException")
|
59
34
|
end
|
60
35
|
end
|
61
36
|
end
|
@@ -11,11 +11,17 @@ module Chatterbox::ExceptionNotification
|
|
11
11
|
def notice
|
12
12
|
hsh = extract_rails_info(@message)
|
13
13
|
hsh = extract_request_info(hsh)
|
14
|
+
hsh = filter_rails_root(hsh)
|
14
15
|
hsh
|
15
16
|
end
|
16
|
-
|
17
|
-
def
|
18
|
-
|
17
|
+
|
18
|
+
def filter_rails_root(hsh)
|
19
|
+
return hsh unless hsh[:backtrace]
|
20
|
+
cleaner = ActiveSupport::BacktraceCleaner.new
|
21
|
+
cleaner.add_filter { |line| line.gsub(rails_root, "[RAILS_ROOT]") }
|
22
|
+
backtrace = cleaner.clean(hsh[:backtrace])
|
23
|
+
hsh[:backtrace] = backtrace
|
24
|
+
hsh
|
19
25
|
end
|
20
26
|
|
21
27
|
def extract_rails_info(message)
|
@@ -23,7 +29,7 @@ module Chatterbox::ExceptionNotification
|
|
23
29
|
message.merge({
|
24
30
|
:rails_info => {
|
25
31
|
:rails_env => rails_configuration.env.to_s,
|
26
|
-
:rails_root =>
|
32
|
+
:rails_root => rails_root,
|
27
33
|
:rails_version => rails_configuration.version
|
28
34
|
}
|
29
35
|
})
|
@@ -40,12 +46,14 @@ module Chatterbox::ExceptionNotification
|
|
40
46
|
}
|
41
47
|
})
|
42
48
|
end
|
43
|
-
|
44
|
-
|
45
|
-
|
49
|
+
|
50
|
+
def rails_root
|
51
|
+
rails_configuration.try(:root).to_s
|
52
|
+
end
|
46
53
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
54
|
+
def rails_configuration
|
55
|
+
Object.const_get("Rails") if Object.const_defined?("Rails")
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
@@ -1,6 +1,24 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
1
3
|
module Chatterbox
|
2
4
|
|
3
5
|
module RailsCatcher
|
6
|
+
delegate :logger, :to => Chatterbox
|
7
|
+
delegate :configuration, :to => self
|
8
|
+
|
9
|
+
def self.default_ignored_exceptions
|
10
|
+
['ActiveRecord::RecordNotFound', 'ActionController::RoutingError',
|
11
|
+
'ActionController::InvalidAuthenticityToken', 'ActionController::UnknownAction',
|
12
|
+
'CGI::Session::CookieStore::TamperedWithCookie' ]
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.configuration
|
16
|
+
@configuration ||= OpenStruct.new(:ignore => default_ignored_exceptions)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.configure
|
20
|
+
yield(configuration)
|
21
|
+
end
|
4
22
|
|
5
23
|
def self.included(base)
|
6
24
|
if base.instance_methods.map(&:to_s).include? 'rescue_action_in_public' and !base.instance_methods.map(&:to_s).include? 'rescue_action_in_public_without_chatterbox'
|
@@ -12,15 +30,26 @@ module Chatterbox
|
|
12
30
|
|
13
31
|
# Overrides the rescue_action method in ActionController::Base, but does not inhibit
|
14
32
|
# any custom processing that is defined with Rails 2's exception helpers.
|
15
|
-
def rescue_action_in_public_with_chatterbox
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
33
|
+
def rescue_action_in_public_with_chatterbox(exception)
|
34
|
+
logger.debug { "#{log_prefix} caught exception #{exception} - about to handle" }
|
35
|
+
unless on_ignore_list?(exception)
|
36
|
+
Chatterbox.handle_notice(extract_exception_details(exception))
|
37
|
+
end
|
38
|
+
logger.debug { "#{log_prefix} handing exception #{exception} off to normal rescue handling" }
|
21
39
|
rescue_action_in_public_without_chatterbox(exception)
|
22
40
|
end
|
23
41
|
|
42
|
+
private
|
43
|
+
|
44
|
+
def log_prefix
|
45
|
+
"#{self.class}#rescue_action_in_public_with_chatterbox:"
|
46
|
+
end
|
47
|
+
|
48
|
+
def on_ignore_list?(exception)
|
49
|
+
configuration.ignore.include?(exception.class) ||
|
50
|
+
configuration.ignore.include?(exception.class.to_s)
|
51
|
+
end
|
52
|
+
|
24
53
|
def extract_exception_details(exception)
|
25
54
|
options = { :exception => exception, :request => request }
|
26
55
|
options = Chatterbox::ExceptionNotification::Extracter.wrap(options)
|
data/version.yml
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: chatterbox
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rob Sanheim
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-11-
|
12
|
+
date: 2009-11-13 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -70,9 +70,10 @@ files:
|
|
70
70
|
- Rakefile
|
71
71
|
- chatterbox.gemspec
|
72
72
|
- examples/example_helper.rb
|
73
|
-
- examples/lib/chatterbox/exception_notification/
|
73
|
+
- examples/lib/chatterbox/exception_notification/extracter_example.rb
|
74
74
|
- examples/lib/chatterbox/exception_notification/presenter_example.rb
|
75
75
|
- examples/lib/chatterbox/exception_notification/rails_extracter_example.rb
|
76
|
+
- examples/lib/chatterbox/rails_catcher_controller_example.rb
|
76
77
|
- examples/lib/chatterbox/rails_catcher_example.rb
|
77
78
|
- examples/lib/chatterbox/services/email/mailer_example.rb
|
78
79
|
- examples/lib/chatterbox/services/email_example.rb
|
@@ -123,9 +124,10 @@ specification_version: 3
|
|
123
124
|
summary: Notifications and messages
|
124
125
|
test_files:
|
125
126
|
- examples/example_helper.rb
|
126
|
-
- examples/lib/chatterbox/exception_notification/
|
127
|
+
- examples/lib/chatterbox/exception_notification/extracter_example.rb
|
127
128
|
- examples/lib/chatterbox/exception_notification/presenter_example.rb
|
128
129
|
- examples/lib/chatterbox/exception_notification/rails_extracter_example.rb
|
130
|
+
- examples/lib/chatterbox/rails_catcher_controller_example.rb
|
129
131
|
- examples/lib/chatterbox/rails_catcher_example.rb
|
130
132
|
- examples/lib/chatterbox/services/email/mailer_example.rb
|
131
133
|
- examples/lib/chatterbox/services/email_example.rb
|