tartarus 1.0.1 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -17,8 +17,8 @@ dependencies are used:
17
17
  === Installation
18
18
 
19
19
  1. Install the gem from:
20
- [sudo] gem install tartarus --source=http://gemcutter.org
21
- 2. Add the exceptional gem dependency to your enviroment.rb:
20
+ gem install tartarus
21
+ 2. Add the tartarus gem dependency to your enviroment.rb:
22
22
  config.gem "tartarus"
23
23
  3. Run the generator from the root of your Rails application:
24
24
  script/generate tartarus
@@ -28,6 +28,15 @@ dependencies are used:
28
28
  <script type="text/javascript" src="/javascripts/tartarus.jquery.js"></script>
29
29
  <link href="/stylesheets/tartarus.css" media="all" rel="stylesheet" type="text/css" />
30
30
 
31
+ === Configuration
32
+
33
+ Configuration is handled by config/exceptions.yml, which will be generated for you. You typically
34
+ will not need to change anything in here, however you can use this to set an email address to
35
+ have exception notifications delivered to, and a threshold. The threshold indicates how frequently
36
+ to send the notification, and is handled per-exception grouping (you will be notified every time the
37
+ threshold is reached, so with the default of 10 you will be notified at 10,20,30,etc.). In addition,
38
+ when an email is set, a notification will always be sent everytime a new type of exception is raised.
39
+
31
40
  === License
32
41
 
33
42
  Copyright (c) 2009 Daniel Insley
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.1
1
+ 1.0.3
@@ -2,7 +2,7 @@
2
2
  <td>
3
3
  <strong><%= link_to "#{exception.exception_class}", :action => 'details', :id => exception.group_id %></strong>
4
4
  <br />
5
- <span><%= truncate(exception.message, :length => 115) %></span>
5
+ <span><%= truncate(h(exception.message), :length => 115) %></span>
6
6
  </td>
7
7
 
8
8
  <td>
@@ -1,9 +1,18 @@
1
1
  development:
2
2
  logging_enabled: true
3
3
  logger_class: <%= class_name %>
4
+ notification_address:
5
+ notification_sender: noreply@example.com
6
+ notification_threshold: 10
4
7
  test:
5
8
  logging_enabled: false
6
9
  logger_class: <%= class_name %>
10
+ notification_address:
11
+ notification_sender: noreply@example.com
12
+ notification_threshold: 10
7
13
  production:
8
14
  logging_enabled: true
9
- logger_class: <%= class_name %>
15
+ logger_class: <%= class_name %>
16
+ notification_address:
17
+ notification_sender: noreply@example.com
18
+ notification_threshold: 10
@@ -10,6 +10,7 @@ class Add<%= class_name %>Table < ActiveRecord::Migration
10
10
  t.text :request
11
11
  t.datetime :created_at
12
12
  end
13
+ add_index :<%= plural_name %>, :group_id
13
14
  end
14
15
 
15
16
  def self.down
@@ -1,4 +1,14 @@
1
1
  module Tartarus::Logger
2
+ def group_count
3
+ self.class.count( :conditions => ["group_id = ?", group_id] )
4
+ end
5
+
6
+ def handle_notifications
7
+ notification_address = Tartarus.configuration['notification_address']
8
+ return unless notification_address.present?
9
+ Tartarus::Notifier.deliver_notification( notification_address, self ) if group_count == 1 or (group_count%Tartarus.configuration['notification_threshold']).zero?
10
+ end
11
+
2
12
  def self.included(base)
3
13
  base.extend ClassMethods
4
14
  base.serialize :request
@@ -6,38 +16,20 @@ module Tartarus::Logger
6
16
 
7
17
  module ClassMethods
8
18
  def log(controller, exception)
9
- create do |logged_exception|
10
- group_id = "#{exception.class.name}#{exception.message}#{controller.controller_path}#{controller.action_name}"
19
+ logged = create do |logged_exception|
20
+ group_id = "#{exception.class.name}#{exception.message.gsub(/(#<.+):(.+)(>)/,'\1\3')}#{controller.controller_path}#{controller.action_name}"
11
21
 
12
22
  logged_exception.exception_class = exception.class.name
13
23
  logged_exception.controller_path = controller.controller_path
14
24
  logged_exception.action_name = controller.action_name
15
25
  logged_exception.message = exception.message
16
26
  logged_exception.backtrace = exception.backtrace * "\n"
17
- logged_exception.request = normalize_request_data(controller.request)
27
+ logged_exception.request = controller.normalize_request_data_for_tartarus
18
28
  logged_exception.group_id = Digest::SHA1.hexdigest(group_id)
19
29
  end
30
+ logged.handle_notifications
31
+ logged
20
32
  end
21
33
 
22
- def normalize_request_data(request)
23
- enviroment = request.env.dup
24
-
25
- request_details = {
26
- :enviroment => { :process => $$, :server => `hostname -s`.chomp },
27
- :session => { :variables => enviroment['rack.session'].to_hash, :cookie => enviroment['rack.request.cookie_hash'] },
28
- :http_details => {
29
- :method => request.method.to_s.upcase,
30
- :url => "#{request.protocol}#{request.env["HTTP_HOST"]}#{request.request_uri}",
31
- :format => request.format.to_s,
32
- :parameters => request.parameters
33
- }
34
- }
35
-
36
- enviroment.each_pair do |key, value|
37
- request_details[:enviroment][key.downcase] = value if key.match(/^[A-Z_]*$/)
38
- end
39
-
40
- return request_details
41
- end
42
34
  end
43
35
  end
@@ -0,0 +1,11 @@
1
+ class Tartarus::Notifier < ActionMailer::Base
2
+ self.mailer_name = 'tartarus_notifier'
3
+ self.view_paths << "#{File.dirname(__FILE__)}/../../views"
4
+
5
+ def notification( to, exception )
6
+ @recipients = to
7
+ @from = Tartarus.configuration['sender']
8
+ @subject = "Exception raised at #{exception.controller_path}##{exception.action_name} (#{exception.exception_class}) #{exception.message}"
9
+ @body[:exception] = exception
10
+ end
11
+ end
@@ -14,4 +14,26 @@ module Tartarus::Rescue
14
14
 
15
15
  rescue_action_without_tartarus(exception)
16
16
  end
17
+
18
+ def normalize_request_data_for_tartarus
19
+ enviroment = request.env.dup
20
+ filtered_params = respond_to?(:filter_parameters) ? filter_parameters(request.parameters) : request.parameters.dup
21
+
22
+ request_details = {
23
+ :enviroment => { :process => $$, :server => `hostname -s`.chomp },
24
+ :session => { :variables => enviroment['rack.session'].to_hash, :cookie => enviroment['rack.request.cookie_hash'] },
25
+ :http_details => {
26
+ :method => request.method.to_s.upcase,
27
+ :url => "#{request.protocol}#{request.env["HTTP_HOST"]}#{request.request_uri}",
28
+ :format => request.format.to_s,
29
+ :parameters => filtered_params
30
+ }
31
+ }
32
+
33
+ enviroment.each_pair do |key, value|
34
+ request_details[:enviroment][key.downcase] = value if key.match(/^[A-Z_]*$/)
35
+ end
36
+
37
+ return request_details
38
+ end
17
39
  end
data/lib/tartarus.rb CHANGED
@@ -23,3 +23,4 @@ end
23
23
 
24
24
  require 'tartarus/logger'
25
25
  require 'tartarus/rescue'
26
+ require 'tartarus/notifier'
@@ -8,7 +8,7 @@ describe Tartarus::Logger do
8
8
  describe "#log" do
9
9
  before(:each) do
10
10
  LoggedException.stub!(:normalize_request_data).and_return({})
11
- @controller = mock('controller', :controller_path => 'home', :action_name => 'index', :request => fake_controller_request)
11
+ @controller = mock('controller', :controller_path => 'home', :normalize_request_data_for_tartarus => 'params', :action_name => 'index', :request => fake_controller_request)
12
12
  @exception = StandardError.new('An error has occured!')
13
13
  @exception.stub!(:backtrace).and_return(['one', 'two', 'three'])
14
14
  end
@@ -25,7 +25,7 @@ describe Tartarus::Logger do
25
25
  end
26
26
 
27
27
  it "should normalize the controller request data" do
28
- LoggedException.should_receive(:normalize_request_data).with(@controller.request)
28
+ @controller.should_receive(:normalize_request_data_for_tartarus)
29
29
  @logged_exception = LoggedException.log(@controller, @exception)
30
30
  end
31
31
 
@@ -34,31 +34,44 @@ describe Tartarus::Logger do
34
34
  @logged_exception.should be_an_instance_of(LoggedException)
35
35
  end
36
36
  end
37
-
38
- describe "#normalize_request_data" do
39
- before(:each) do
40
- @request_data = LoggedException.normalize_request_data(fake_controller_request)
37
+
38
+ it 'should return the group count' do
39
+ e = LoggedException.create( :group_id => "hash" )
40
+ LoggedException.should_receive( :count ).with( :conditions => ["group_id = ?", 'hash'] ).and_return( 42 )
41
+ e.group_count.should == 42
42
+ end
43
+
44
+ describe '#handle_notifications' do
45
+ before(:each) do
46
+ @e = LoggedException.create
47
+ Tartarus.configuration['notification_threshold'] = 10
48
+ Tartarus.configuration['notification_address'] = 'test@example.com'
41
49
  end
42
50
 
43
- it 'should have a enviroment hash that contains a hash of only the uppercase keys of the original controller request hash' do
44
- @request_data[:enviroment].should_not be_blank
45
- @request_data[:enviroment].should == { "http_host" => "test_host", "loooooooong_key_two" => "key_two_value", "key_one" => "key_one_value", :server => `hostname -s`.chomp, :process => $$ }
46
- end
51
+ it 'should return and not deliver notification if there is no address present' do
52
+ Tartarus::Notifier.should_receive( :deliver_notification ).never
53
+ Tartarus.configuration['notification_address'] = nil
47
54
 
48
- it 'should have a session hash' do
49
- @request_data[:session].should_not be_blank
50
- @request_data[:session].should be_an_instance_of(Hash)
51
- @request_data[:session].should == { :cookie => {}, :variables => { :id=>"123123" } }
55
+ @e.handle_notifications
52
56
  end
53
57
 
54
- it 'should have a http details hash' do
55
- @request_data[:http_details].should_not be_blank
56
- @request_data[:http_details].should == { :parameters => "params", :format => "html", :method => "POST", :url => "http://test_host/my/uri" }
58
+ it 'should send email if there is an address present and the count matches the threshold' do
59
+ Tartarus::Notifier.should_receive( :deliver_notification ).with( 'test@example.com', @e )
60
+ @e.stub( :group_count ).and_return( 20 )
61
+ @e.handle_notifications
57
62
  end
58
-
59
- it "should return a hash of request data" do
60
- @request_data.should be_an_instance_of(Hash)
63
+
64
+ it 'should send email if there is an address present and it is the first exception in a group' do
65
+ Tartarus::Notifier.should_receive( :deliver_notification ).with( 'test@example.com', @e )
66
+ @e.stub( :group_count ).and_return( 1 )
67
+ @e.handle_notifications
68
+ end
69
+
70
+ it 'should not send email if there is an address present and the count does not match the threshold' do
71
+ Tartarus::Notifier.should_receive( :deliver_notification ).never
72
+ @e.stub( :group_count ).and_return( 22 )
73
+ @e.handle_notifications
61
74
  end
62
-
63
75
  end
76
+
64
77
  end
@@ -15,6 +15,36 @@ describe Tartarus::Rescue do
15
15
  end
16
16
  end
17
17
 
18
+ describe 'when normalizing request data for tartarus' do
19
+ before( :each ) do
20
+ @controller.stub( :request ).and_return( fake_controller_request )
21
+ end
22
+
23
+ it 'should have the session hash' do
24
+ params = @controller.normalize_request_data_for_tartarus
25
+ params[:session].should_not be_blank
26
+ params[:session].should be_an_instance_of(Hash)
27
+ params[:session].should == { :cookie => {}, :variables => { :id=>"123123" } }
28
+ end
29
+
30
+ it 'should have a enviroment hash that contains a hash of only the uppercase keys of the original controller request hash' do
31
+ params = @controller.normalize_request_data_for_tartarus
32
+ params[:enviroment].should_not be_blank
33
+ params[:enviroment].should == { "http_host" => "test_host", "loooooooong_key_two" => "key_two_value", "key_one" => "key_one_value", :server => `hostname -s`.chomp, :process => $$ }
34
+ end
35
+
36
+ it 'should have a http details hash' do
37
+ params = @controller.normalize_request_data_for_tartarus
38
+ params[:http_details].should_not be_blank
39
+ params[:http_details].should == { :parameters => "params", :format => "html", :method => "POST", :url => "http://test_host/my/uri" }
40
+ end
41
+
42
+ it "should return a hash of request data" do
43
+ params = @controller.normalize_request_data_for_tartarus
44
+ params.should be_an_instance_of(Hash)
45
+ end
46
+ end
47
+
18
48
  describe "#rescue_action_with_tartarus" do
19
49
  before(:each) do
20
50
  @exception = StandardError.new
data/tartarus.gemspec CHANGED
@@ -1,15 +1,15 @@
1
1
  # Generated by jeweler
2
- # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
2
+ # DO NOT EDIT THIS FILE
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
4
4
  # -*- encoding: utf-8 -*-
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{tartarus}
8
- s.version = "1.0.1"
8
+ s.version = "1.0.3"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Daniel Insley"]
12
- s.date = %q{2009-11-24}
12
+ s.date = %q{2010-10-27}
13
13
  s.description = %q{Provides exception logging and a generator for creating a clean interface to manage exceptions.}
14
14
  s.email = %q{dinsley@gmail.com}
15
15
  s.extra_rdoc_files = [
@@ -36,6 +36,7 @@ Gem::Specification.new do |s|
36
36
  "generators/tartarus/templates/spec/models/logged_exception_spec.rb",
37
37
  "lib/tartarus.rb",
38
38
  "lib/tartarus/logger.rb",
39
+ "lib/tartarus/notifier.rb",
39
40
  "lib/tartarus/rescue.rb",
40
41
  "rails/init.rb",
41
42
  "spec/rails/app/controllers/application_controller.rb",
@@ -61,7 +62,8 @@ Gem::Specification.new do |s|
61
62
  "spec/tartarus/logger_spec.rb",
62
63
  "spec/tartarus/rescue_spec.rb",
63
64
  "spec/tartarus_spec.rb",
64
- "tartarus.gemspec"
65
+ "tartarus.gemspec",
66
+ "views/tartarus_notifier/notification.html.erb"
65
67
  ]
66
68
  s.homepage = %q{http://github.com/dinsley/tartarus}
67
69
  s.rdoc_options = ["--charset=UTF-8"]
@@ -110,4 +112,3 @@ Gem::Specification.new do |s|
110
112
  s.add_dependency(%q<rspec-rails>, [">= 0"])
111
113
  end
112
114
  end
113
-
@@ -0,0 +1,9 @@
1
+ A new exception was raised (<%= @exception.created_at.strftime("%m/%d/%Y %I:%M%p") %>):
2
+
3
+ Class : <%= @exception.exception_class %>
4
+ Location : <%= @exception.controller_path %>#<%= @exception.action_name %>
5
+ Message : <%= @exception.message %>
6
+ Count : <%= @exception.group_count %>
7
+
8
+ Backtrace:
9
+ <%= @exception.backtrace %>
metadata CHANGED
@@ -1,7 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tartarus
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ hash: 17
5
+ prerelease: false
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 3
10
+ version: 1.0.3
5
11
  platform: ruby
6
12
  authors:
7
13
  - Daniel Insley
@@ -9,49 +15,65 @@ autorequire:
9
15
  bindir: bin
10
16
  cert_chain: []
11
17
 
12
- date: 2009-11-24 00:00:00 -08:00
18
+ date: 2010-10-27 00:00:00 -07:00
13
19
  default_executable:
14
20
  dependencies:
15
21
  - !ruby/object:Gem::Dependency
16
22
  name: will_paginate
17
- type: :runtime
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
20
26
  requirements:
21
27
  - - ">="
22
28
  - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
23
32
  version: "0"
24
- version:
33
+ type: :runtime
34
+ version_requirements: *id001
25
35
  - !ruby/object:Gem::Dependency
26
36
  name: rails
27
- type: :development
28
- version_requirement:
29
- version_requirements: !ruby/object:Gem::Requirement
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
30
40
  requirements:
31
41
  - - ">="
32
42
  - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
33
46
  version: "0"
34
- version:
47
+ type: :development
48
+ version_requirements: *id002
35
49
  - !ruby/object:Gem::Dependency
36
50
  name: rspec
37
- type: :development
38
- version_requirement:
39
- version_requirements: !ruby/object:Gem::Requirement
51
+ prerelease: false
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
40
54
  requirements:
41
55
  - - ">="
42
56
  - !ruby/object:Gem::Version
57
+ hash: 3
58
+ segments:
59
+ - 0
43
60
  version: "0"
44
- version:
61
+ type: :development
62
+ version_requirements: *id003
45
63
  - !ruby/object:Gem::Dependency
46
64
  name: rspec-rails
47
- type: :development
48
- version_requirement:
49
- version_requirements: !ruby/object:Gem::Requirement
65
+ prerelease: false
66
+ requirement: &id004 !ruby/object:Gem::Requirement
67
+ none: false
50
68
  requirements:
51
69
  - - ">="
52
70
  - !ruby/object:Gem::Version
71
+ hash: 3
72
+ segments:
73
+ - 0
53
74
  version: "0"
54
- version:
75
+ type: :development
76
+ version_requirements: *id004
55
77
  description: Provides exception logging and a generator for creating a clean interface to manage exceptions.
56
78
  email: dinsley@gmail.com
57
79
  executables: []
@@ -81,6 +103,7 @@ files:
81
103
  - generators/tartarus/templates/spec/models/logged_exception_spec.rb
82
104
  - lib/tartarus.rb
83
105
  - lib/tartarus/logger.rb
106
+ - lib/tartarus/notifier.rb
84
107
  - lib/tartarus/rescue.rb
85
108
  - rails/init.rb
86
109
  - spec/rails/app/controllers/application_controller.rb
@@ -107,6 +130,7 @@ files:
107
130
  - spec/tartarus/rescue_spec.rb
108
131
  - spec/tartarus_spec.rb
109
132
  - tartarus.gemspec
133
+ - views/tartarus_notifier/notification.html.erb
110
134
  has_rdoc: true
111
135
  homepage: http://github.com/dinsley/tartarus
112
136
  licenses: []
@@ -117,21 +141,27 @@ rdoc_options:
117
141
  require_paths:
118
142
  - lib
119
143
  required_ruby_version: !ruby/object:Gem::Requirement
144
+ none: false
120
145
  requirements:
121
146
  - - ">="
122
147
  - !ruby/object:Gem::Version
148
+ hash: 3
149
+ segments:
150
+ - 0
123
151
  version: "0"
124
- version:
125
152
  required_rubygems_version: !ruby/object:Gem::Requirement
153
+ none: false
126
154
  requirements:
127
155
  - - ">="
128
156
  - !ruby/object:Gem::Version
157
+ hash: 3
158
+ segments:
159
+ - 0
129
160
  version: "0"
130
- version:
131
161
  requirements: []
132
162
 
133
163
  rubyforge_project:
134
- rubygems_version: 1.3.5
164
+ rubygems_version: 1.3.7
135
165
  signing_key:
136
166
  specification_version: 3
137
167
  summary: Exception Logging for Rails