chatterbox 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (30) hide show
  1. data/CHANGELOG.markdown +15 -0
  2. data/README.markdown +1 -1
  3. data/Rakefile +2 -2
  4. data/chatterbox.gemspec +31 -16
  5. data/examples/example_helper.rb +13 -3
  6. data/examples/lib/chatterbox/exception_notification/filter_example.rb +38 -0
  7. data/examples/lib/chatterbox/exception_notification/presenter_example.rb +89 -0
  8. data/examples/lib/chatterbox/exception_notification/rails_extracter_example.rb +50 -0
  9. data/examples/lib/chatterbox/rails_catcher_example.rb +17 -10
  10. data/examples/lib/chatterbox/services/email/mailer_example.rb +54 -0
  11. data/examples/lib/chatterbox/services/email_example.rb +89 -0
  12. data/examples/lib/chatterbox/services_example.rb +0 -0
  13. data/examples/{chatterbox_example.rb → lib/chatterbox_example.rb} +22 -24
  14. data/lib/chatterbox/{notification.rb → exception_notification/extracter.rb} +23 -35
  15. data/lib/chatterbox/exception_notification/presenter.rb +81 -0
  16. data/lib/chatterbox/exception_notification/rails_extracter.rb +51 -0
  17. data/lib/chatterbox/exception_notification.rb +8 -0
  18. data/lib/chatterbox/rails_catcher.rb +11 -1
  19. data/lib/chatterbox/services/email/mailer.rb +28 -0
  20. data/lib/chatterbox/services/email/views/chatterbox/services/email/mailer/message.erb +0 -0
  21. data/lib/chatterbox/services/email.rb +66 -0
  22. data/lib/chatterbox/services.rb +4 -0
  23. data/lib/chatterbox.rb +21 -24
  24. data/todo.markdown +0 -2
  25. data/version.yml +2 -1
  26. metadata +26 -12
  27. data/examples/lib/chatterbox/consumers/email_consumer_example.rb +0 -65
  28. data/examples/lib/chatterbox/notification_example.rb +0 -147
  29. data/lib/consumers/email_consumer.rb +0 -64
  30. data/lib/consumers.rb +0 -2
@@ -1,19 +1,21 @@
1
- module Chatterbox
2
-
3
- class Notification
4
-
1
+ module Chatterbox::ExceptionNotification
2
+ class Extracter
5
3
  attr_reader :message
6
-
7
- def initialize(message = nil)
4
+
5
+ def self.wrap(notification = {})
6
+ new(notification).notice
7
+ end
8
+
9
+ def initialize(message = {})
8
10
  @message = message
9
11
  end
10
-
12
+
11
13
  def notice
12
14
  hash = normalize_message_to_hash(message)
13
15
  hash = exception_to_notice(hash)
14
16
  default_info.merge(hash)
15
17
  end
16
-
18
+
17
19
  def normalize_message_to_hash(message)
18
20
  case
19
21
  when Exception === message
@@ -24,23 +26,20 @@ module Chatterbox
24
26
  string_to_notice(message.to_s)
25
27
  end
26
28
  end
27
-
29
+
28
30
  def default_info
29
31
  default_info = {
30
32
  :summary => "N/A",
31
- :environment => env,
32
- :ruby_version => ruby_version,
33
- :ruby_platform => ruby_platform
33
+ :environment => env
34
34
  }
35
35
  default_info = add_ruby_info(default_info)
36
- default_info = add_rails_info(default_info) if rails_configuration
37
36
  default_info
38
37
  end
39
-
38
+
40
39
  def string_to_notice(message)
41
40
  { :summary => message }
42
41
  end
43
-
42
+
44
43
  def exception_to_notice(hash)
45
44
  return hash unless hash.key?(:exception)
46
45
  exception = hash[:exception]
@@ -51,37 +50,26 @@ module Chatterbox
51
50
  :backtrace => exception.backtrace,
52
51
  }.merge(hash)
53
52
  end
54
-
55
- def add_rails_info(data)
56
- data.merge({
57
- :rails_env => rails_configuration.env,
58
- :rails_root => rails_configuration.root,
59
- :rails_version => rails_configuration.version
60
- })
61
- end
62
-
53
+
63
54
  def add_ruby_info(data)
64
- data.merge({
65
- :ruby_version => ruby_version,
66
- :ruby_platform => ruby_platform
55
+ data.merge({
56
+ :ruby_info => {
57
+ :ruby_version => ruby_version,
58
+ :ruby_platform => ruby_platform
59
+ }
67
60
  })
68
61
  end
69
62
 
70
63
  def ruby_version
71
64
  RUBY_VERSION
72
65
  end
73
-
66
+
74
67
  def ruby_platform
75
68
  RUBY_PLATFORM
76
69
  end
77
-
70
+
78
71
  def env
79
72
  ENV.to_hash
80
73
  end
81
-
82
- def rails_configuration
83
- defined?(Rails) && Rails
84
- end
85
-
86
74
  end
87
- end
75
+ end
@@ -0,0 +1,81 @@
1
+ require 'yaml'
2
+
3
+ module Chatterbox::ExceptionNotification
4
+ class Presenter
5
+ attr_reader :options
6
+
7
+ def self.render(options)
8
+ new(options).to_message
9
+ end
10
+
11
+ def initialize(options = {})
12
+ @options = options
13
+ @config = options[:config]
14
+ end
15
+
16
+ def summary
17
+ options.delete(:summary)
18
+ end
19
+
20
+ def to_message
21
+ { :message => { :summary => summary, :body => body },
22
+ :config => @config }
23
+ end
24
+
25
+ def section_order
26
+ [:error_message, :request, :backtrace, :environment, :ruby_info, :rails_info]
27
+ end
28
+
29
+ def body
30
+ body = ""
31
+ section_order.each do |section|
32
+ output = render_section(section)
33
+ body << output if output
34
+ end
35
+ body
36
+ end
37
+
38
+ def render_section(key)
39
+ return nil unless options.key?(key)
40
+ output = key.to_s.titleize
41
+ output << "\n"
42
+ output << "----------\n"
43
+ output << "#{inspect_value(options[key])}\n\n"
44
+ output
45
+ end
46
+
47
+ # Taken from exception_notification - thanks Jamis.
48
+ def inspect_value(value)
49
+ object_to_yaml(value).strip
50
+ end
51
+
52
+ def object_to_yaml(object)
53
+ result = ""
54
+ result << render_obj(object)
55
+ result
56
+ end
57
+
58
+ def render_obj(object)
59
+ if object.is_a?(Hash)
60
+ render_hash(object)
61
+ else
62
+ render_non_hash(object)
63
+ end
64
+ end
65
+
66
+ def render_non_hash(object)
67
+ object.to_yaml.sub(/^---\s*\n?/, "")
68
+ end
69
+
70
+ # renders hashes with keys in sorted order
71
+ def render_hash(hsh)
72
+ str = ""
73
+ indiff_hsh = hsh.with_indifferent_access
74
+ indiff_hsh.keys.sort.each do |key|
75
+ value = indiff_hsh[key]
76
+ str << "#{key}: #{render_obj(value)}"
77
+ end
78
+ str
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,51 @@
1
+ module Chatterbox::ExceptionNotification
2
+ class RailsExtracter
3
+ def self.wrap(notification = {})
4
+ new(notification).notice
5
+ end
6
+
7
+ def initialize(message = {})
8
+ @message = message
9
+ end
10
+
11
+ def notice
12
+ hsh = extract_rails_info(@message)
13
+ hsh = extract_request_info(hsh)
14
+ hsh
15
+ end
16
+
17
+ def rails_configuration
18
+ Object.const_get("Rails") if Object.const_defined?("Rails")
19
+ end
20
+
21
+ def extract_rails_info(message)
22
+ return message if rails_configuration.nil?
23
+ message.merge({
24
+ :rails_info => {
25
+ :rails_env => rails_configuration.env,
26
+ :rails_root => rails_configuration.root,
27
+ :rails_version => rails_configuration.version
28
+ }
29
+ })
30
+ end
31
+
32
+ def extract_request_info(message)
33
+ return message unless message.key?(:request)
34
+ request = message.delete(:request)
35
+ message.merge({
36
+ :request => {
37
+ :url => request.url,
38
+ :remote_ip => request.remote_ip,
39
+ :parameters => request.parameters
40
+ }
41
+ })
42
+ end
43
+ end
44
+ end
45
+
46
+
47
+ #
48
+ # * URL : <%= @request.protocol %><%= @host %><%= @request.request_uri %>
49
+ # * IP address: <%= @request.env["HTTP_X_FORWARDED_FOR"] || @request.env["REMOTE_ADDR"] %>
50
+ # * Parameters: <%= filter_sensitive_post_data_parameters(@request.parameters).inspect %>
51
+ # * Rails root: <%= @rails_root %>
@@ -0,0 +1,8 @@
1
+ module Chatterbox
2
+ module ExceptionNotification
3
+ end
4
+ end
5
+
6
+ require 'chatterbox/exception_notification/extracter'
7
+ require 'chatterbox/exception_notification/rails_extracter'
8
+ require 'chatterbox/exception_notification/presenter'
@@ -6,6 +6,7 @@ module Chatterbox
6
6
  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'
7
7
  base.send(:alias_method, :rescue_action_in_public_without_chatterbox, :rescue_action_in_public)
8
8
  base.send(:alias_method, :rescue_action_in_public, :rescue_action_in_public_with_chatterbox)
9
+ base.hide_action(:rescue_action_in_public_with_chatterbox, :rescue_action_in_public_without_chatterbox)
9
10
  end
10
11
  end
11
12
 
@@ -13,12 +14,21 @@ module Chatterbox
13
14
  # any custom processing that is defined with Rails 2's exception helpers.
14
15
  def rescue_action_in_public_with_chatterbox exception
15
16
  Chatterbox.logger.debug { "#{self.class}#rescue_action_in_public_with_chatterbox: caught exception #{exception} - about to handle"}
16
- Chatterbox.handle_notice(exception)
17
+ options = extract_exception_details(exception)
18
+ Chatterbox.handle_notice(options)
17
19
  Chatterbox.logger.debug { "#{self.class}#rescue_action_in_public_with_chatterbox: handing exception #{exception} off to normal rescue handling"}
18
20
 
19
21
  rescue_action_in_public_without_chatterbox(exception)
20
22
  end
21
23
 
24
+ def extract_exception_details(exception)
25
+ options = { :exception => exception, :request => request }
26
+ options = Chatterbox::ExceptionNotification::Extracter.wrap(options)
27
+ options = Chatterbox::ExceptionNotification::RailsExtracter.wrap(options)
28
+ options = Chatterbox::ExceptionNotification::Presenter.render(options)
29
+ options
30
+ end
31
+
22
32
  end
23
33
 
24
34
  end
@@ -0,0 +1,28 @@
1
+ require 'action_mailer'
2
+
3
+ module Chatterbox::Services
4
+ class Email
5
+ class Mailer < ActionMailer::Base
6
+ self.template_root = File.join(File.dirname(__FILE__), *%w[views])
7
+
8
+ def self.reloadable?() false end
9
+
10
+ def message(data={})
11
+ data = data.dup.symbolize_keys
12
+
13
+ content_type data[:config][:content_type] || "text/plain"
14
+
15
+ recipients data[:config][:to]
16
+ from data[:config][:from]
17
+
18
+ reply_to data[:config][:reply_to] if data[:config][:reply_to]
19
+ bcc data[:config][:bcc] if data[:config][:bcc]
20
+ cc data[:config][:cc] if data[:config][:cc]
21
+
22
+ subject data[:message][:summary]
23
+ body data[:message][:body] if data[:message][:body]
24
+ end
25
+
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,66 @@
1
+ require 'chatterbox'
2
+ require 'chatterbox/services/email/mailer'
3
+
4
+ module Chatterbox::Services
5
+ class Email
6
+ attr_reader :options
7
+ @default_configuration = {}
8
+
9
+ def self.default_configuration
10
+ @default_configuration
11
+ end
12
+
13
+ def self.configure(config_options)
14
+ @default_configuration = config_options
15
+ end
16
+
17
+ def self.deliver(options = {})
18
+ new(options).deliver
19
+ end
20
+
21
+ def initialize(options = {})
22
+ @options = options
23
+ merge_configs
24
+ validate_options
25
+ end
26
+
27
+ def deliver
28
+ Mailer.deliver_message(options)
29
+ end
30
+
31
+ private
32
+
33
+ def merge_configs
34
+ @options[:config] ||= {}
35
+ @options[:config] = self.class.default_configuration.merge(options[:config])
36
+ end
37
+
38
+ def validate_options
39
+ require_message
40
+ require_message_keys(:summary)
41
+
42
+ require_config
43
+ require_config_keys(:to, :from)
44
+ end
45
+
46
+ def require_message
47
+ raise(ArgumentError, "Must configure with a :message - you provided #{options.inspect}") unless options.key?(:message)
48
+ end
49
+
50
+ def require_config
51
+ raise(ArgumentError, "Must configure with a :config or set default_configuration") unless options.key?(:config)
52
+ end
53
+
54
+ def require_config_keys(*keys)
55
+ Array(keys).each do |key|
56
+ raise(ArgumentError, "Must provide #{key.inspect} in the :config\nYou provided #{options.inspect}") unless options[:config].key?(key)
57
+ end
58
+ end
59
+
60
+ def require_message_keys(*keys)
61
+ Array(keys).each do |key|
62
+ raise(ArgumentError, "Must provide #{key.inspect} in the :message") unless options[:message].key?(key)
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,4 @@
1
+ module Chatterbox
2
+ module Services
3
+ end
4
+ end
data/lib/chatterbox.rb CHANGED
@@ -1,51 +1,48 @@
1
- require File.join(File.dirname(__FILE__), *%w[chatterbox notification])
2
- require File.join(File.dirname(__FILE__), *%w[consumers])
1
+ require 'active_support'
3
2
 
4
3
  module Chatterbox
5
-
6
4
  def handle_notice(message)
7
5
  publish_notice(message)
6
+ message
8
7
  end
8
+
9
+ alias_method :notify, :handle_notice
9
10
 
10
11
  def publish_notice(message)
11
- Publishers.publishers.each { |p| p.call(message) }
12
+ Publishers.publishers.each { |p| p.call(message.with_indifferent_access) }
12
13
  end
13
14
 
14
15
  def logger
15
- @logger ||= rails_default_logger || Logger.new(STDOUT)
16
+ @logger ||= Logger.new(nil)
16
17
  end
17
18
 
18
19
  def logger=(logger)
19
20
  @logger = logger
20
21
  end
21
22
 
22
- def rails_default_logger
23
- defined?(RAILS_DEFAULT_LOGGER) ? RAILS_DEFAULT_LOGGER : nil
23
+ def register(&blk)
24
+ Publishers.register(&blk)
24
25
  end
25
26
 
26
27
  extend self
27
28
 
28
29
  module Publishers
29
-
30
- class << self
31
-
32
- def publishers
33
- @publishers ||= []
34
- end
35
-
36
- def register(&blk)
37
- Chatterbox.logger.debug { "Registering publisher: #{blk}"}
38
- publishers << blk
39
- blk
40
- end
30
+ def publishers
31
+ @publishers ||= []
32
+ end
41
33
 
42
- def clear!
43
- @publishers = []
44
- end
45
-
34
+ def register(&blk)
35
+ Chatterbox.logger.debug { "Registering publisher: #{blk}"}
36
+ publishers << blk
37
+ blk
46
38
  end
47
39
 
40
+ def clear!
41
+ @publishers = []
42
+ end
43
+
44
+ extend self
48
45
  end
49
-
50
46
  end
51
47
 
48
+ require "chatterbox/services"
data/todo.markdown CHANGED
@@ -1,5 +1,3 @@
1
- * shouldn't require _action_mailer_ unless really needed by the mailer
2
-
3
1
  # rails catcher
4
2
  * make sure we push through request info for exceptions
5
3
  * wire ignore exceptions in rails catcher
data/version.yml CHANGED
@@ -1,4 +1,5 @@
1
1
  ---
2
2
  :major: 0
3
- :minor: 4
3
+ :minor: 5
4
4
  :patch: 0
5
+ :build:
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.4.0
4
+ version: 0.5.0
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-10-09 00:00:00 -06:00
12
+ date: 2009-11-06 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -52,7 +52,7 @@ dependencies:
52
52
  - !ruby/object:Gem::Version
53
53
  version: "0"
54
54
  version:
55
- description: "[\"Send\", \"messages.\", \"However\", \"you\", \"want.\"]"
55
+ description: Send notifications and messages. However you want.
56
56
  email: rsanheim@gmail.com
57
57
  executables: []
58
58
 
@@ -64,21 +64,31 @@ extra_rdoc_files:
64
64
  files:
65
65
  - .gitignore
66
66
  - .treasure_map.rb
67
+ - CHANGELOG.markdown
67
68
  - LICENSE
68
69
  - README.markdown
69
70
  - Rakefile
70
71
  - chatterbox.gemspec
71
- - examples/chatterbox_example.rb
72
72
  - examples/example_helper.rb
73
- - examples/lib/chatterbox/consumers/email_consumer_example.rb
74
- - examples/lib/chatterbox/notification_example.rb
73
+ - examples/lib/chatterbox/exception_notification/filter_example.rb
74
+ - examples/lib/chatterbox/exception_notification/presenter_example.rb
75
+ - examples/lib/chatterbox/exception_notification/rails_extracter_example.rb
75
76
  - examples/lib/chatterbox/rails_catcher_example.rb
77
+ - examples/lib/chatterbox/services/email/mailer_example.rb
78
+ - examples/lib/chatterbox/services/email_example.rb
79
+ - examples/lib/chatterbox/services_example.rb
80
+ - examples/lib/chatterbox_example.rb
76
81
  - init.rb
77
82
  - lib/chatterbox.rb
78
- - lib/chatterbox/notification.rb
83
+ - lib/chatterbox/exception_notification.rb
84
+ - lib/chatterbox/exception_notification/extracter.rb
85
+ - lib/chatterbox/exception_notification/presenter.rb
86
+ - lib/chatterbox/exception_notification/rails_extracter.rb
79
87
  - lib/chatterbox/rails_catcher.rb
80
- - lib/consumers.rb
81
- - lib/consumers/email_consumer.rb
88
+ - lib/chatterbox/services.rb
89
+ - lib/chatterbox/services/email.rb
90
+ - lib/chatterbox/services/email/mailer.rb
91
+ - lib/chatterbox/services/email/views/chatterbox/services/email/mailer/message.erb
82
92
  - rails/init.rb
83
93
  - todo.markdown
84
94
  - version.yml
@@ -112,8 +122,12 @@ signing_key:
112
122
  specification_version: 3
113
123
  summary: Notifications and messages
114
124
  test_files:
115
- - examples/chatterbox_example.rb
116
125
  - examples/example_helper.rb
117
- - examples/lib/chatterbox/consumers/email_consumer_example.rb
118
- - examples/lib/chatterbox/notification_example.rb
126
+ - examples/lib/chatterbox/exception_notification/filter_example.rb
127
+ - examples/lib/chatterbox/exception_notification/presenter_example.rb
128
+ - examples/lib/chatterbox/exception_notification/rails_extracter_example.rb
119
129
  - examples/lib/chatterbox/rails_catcher_example.rb
130
+ - examples/lib/chatterbox/services/email/mailer_example.rb
131
+ - examples/lib/chatterbox/services/email_example.rb
132
+ - examples/lib/chatterbox/services_example.rb
133
+ - examples/lib/chatterbox_example.rb
@@ -1,65 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), *%w[.. .. .. example_helper]))
2
- require 'chatterbox'
3
-
4
- describe Chatterbox::Mailer do
5
-
6
- it "displays environment vars sorted" do
7
- notice = {
8
- :environment => {
9
- "PATH" => "/usr/bin",
10
- "PS1" => "$",
11
- "TMPDIR" => "/tmp"
12
- }
13
- }
14
- expected = <<EOL
15
- PATH => /usr/bin
16
- PS1 => $
17
- TMPDIR => /tmp
18
- EOL
19
- mail = Chatterbox::Mailer.create_exception_notification(notice)
20
- mail.body.should include(expected.strip)
21
- end
22
-
23
- it "displays any other details in the hash in the email body" do
24
- notice = {
25
- :details => { "message_id" => "user01-create", "current_user" => "Chris Liebing" },
26
- :environment => { "foo" => "path" }
27
- }
28
- Chatterbox::Mailer.create_exception_notification(notice)
29
- expected = <<EOL
30
- Details
31
- -------
32
- current_user => Chris Liebing
33
- message_id => user01-create
34
- EOL
35
- mail = Chatterbox::Mailer.create_exception_notification(notice)
36
- mail.body.should include(expected.strip)
37
- end
38
-
39
- it "does not mutate the provided hash" do
40
- notice = {'foo' => 'bar', :environment => {}}
41
- Chatterbox::Mailer.create_exception_notification(notice)
42
- notice.should == {'foo' => 'bar', :environment => {}}
43
- end
44
-
45
- describe "subject" do
46
-
47
- it "extracts the subject from the given data hash when the key is a symbol" do
48
- mail = Chatterbox::Mailer.create_exception_notification(:environment => {}, :summary => 'foo')
49
- mail.subject.should include('foo')
50
- end
51
-
52
- it "extracts the subject from the given data hash when the key is a string" do
53
- mail = Chatterbox::Mailer.create_exception_notification(:environment => {}, 'summary' => 'foo')
54
- mail.subject.should include('foo')
55
- end
56
-
57
- it "includes the given prefix" do
58
- Chatterbox::Mailer.email_prefix = '[super important email]'
59
- mail = Chatterbox::Mailer.create_exception_notification(:environment => {})
60
- mail.subject.should match(/\[super important email\]/)
61
- end
62
-
63
- end
64
-
65
- end