chatterbox 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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