hutch 0.18.0 → 1.1.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 (73) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +3 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +20 -8
  5. data/.yardopts +5 -0
  6. data/CHANGELOG.md +466 -2
  7. data/Gemfile +18 -4
  8. data/Guardfile +13 -4
  9. data/LICENSE +2 -1
  10. data/README.md +397 -32
  11. data/Rakefile +8 -1
  12. data/bin/ci/before_build.sh +20 -0
  13. data/bin/ci/install_on_debian.sh +46 -0
  14. data/hutch.gemspec +6 -7
  15. data/lib/hutch/acknowledgements/base.rb +16 -0
  16. data/lib/hutch/acknowledgements/nack_on_all_failures.rb +19 -0
  17. data/lib/hutch/adapters/march_hare.rb +1 -1
  18. data/lib/hutch/broker.rb +127 -103
  19. data/lib/hutch/cli.rb +66 -25
  20. data/lib/hutch/config.rb +230 -55
  21. data/lib/hutch/consumer.rb +42 -3
  22. data/lib/hutch/error_handlers/airbrake.rb +44 -16
  23. data/lib/hutch/error_handlers/base.rb +15 -0
  24. data/lib/hutch/error_handlers/bugsnag.rb +30 -0
  25. data/lib/hutch/error_handlers/honeybadger.rb +33 -18
  26. data/lib/hutch/error_handlers/logger.rb +12 -6
  27. data/lib/hutch/error_handlers/rollbar.rb +28 -0
  28. data/lib/hutch/error_handlers/sentry.rb +15 -12
  29. data/lib/hutch/error_handlers/sentry_raven.rb +31 -0
  30. data/lib/hutch/error_handlers.rb +3 -0
  31. data/lib/hutch/exceptions.rb +8 -1
  32. data/lib/hutch/logging.rb +5 -5
  33. data/lib/hutch/message.rb +2 -4
  34. data/lib/hutch/publisher.rb +75 -0
  35. data/lib/hutch/serializers/identity.rb +19 -0
  36. data/lib/hutch/serializers/json.rb +22 -0
  37. data/lib/hutch/tracers/datadog.rb +17 -0
  38. data/lib/hutch/tracers.rb +1 -0
  39. data/lib/hutch/version.rb +1 -2
  40. data/lib/hutch/waiter.rb +104 -0
  41. data/lib/hutch/worker.rb +81 -75
  42. data/lib/hutch.rb +15 -6
  43. data/lib/yard-settings/handler.rb +38 -0
  44. data/lib/yard-settings/yard-settings.rb +2 -0
  45. data/spec/hutch/broker_spec.rb +162 -77
  46. data/spec/hutch/cli_spec.rb +16 -3
  47. data/spec/hutch/config_spec.rb +121 -22
  48. data/spec/hutch/consumer_spec.rb +82 -4
  49. data/spec/hutch/error_handlers/airbrake_spec.rb +25 -10
  50. data/spec/hutch/error_handlers/bugsnag_spec.rb +55 -0
  51. data/spec/hutch/error_handlers/honeybadger_spec.rb +24 -2
  52. data/spec/hutch/error_handlers/logger_spec.rb +14 -1
  53. data/spec/hutch/error_handlers/rollbar_spec.rb +45 -0
  54. data/spec/hutch/error_handlers/sentry_raven_spec.rb +37 -0
  55. data/spec/hutch/error_handlers/sentry_spec.rb +21 -2
  56. data/spec/hutch/logger_spec.rb +12 -6
  57. data/spec/hutch/message_spec.rb +2 -2
  58. data/spec/hutch/serializers/json_spec.rb +17 -0
  59. data/spec/hutch/tracers/datadog_spec.rb +44 -0
  60. data/spec/hutch/waiter_spec.rb +51 -0
  61. data/spec/hutch/worker_spec.rb +89 -5
  62. data/spec/spec_helper.rb +7 -5
  63. data/templates/default/class/html/settings.erb +0 -0
  64. data/templates/default/class/setup.rb +4 -0
  65. data/templates/default/fulldoc/html/css/hutch.css +13 -0
  66. data/templates/default/layout/html/setup.rb +7 -0
  67. data/templates/default/method_details/html/settings.erb +5 -0
  68. data/templates/default/method_details/setup.rb +4 -0
  69. data/templates/default/method_details/text/settings.erb +0 -0
  70. data/templates/default/module/html/settings.erb +40 -0
  71. data/templates/default/module/setup.rb +4 -0
  72. metadata +62 -43
  73. data/circle.yml +0 -3
data/lib/hutch/config.rb CHANGED
@@ -1,69 +1,237 @@
1
1
  require 'hutch/error_handlers/logger'
2
+ require 'hutch/tracers'
3
+ require 'hutch/serializers/json'
2
4
  require 'erb'
3
5
  require 'logger'
4
6
 
5
7
  module Hutch
6
8
  class UnknownAttributeError < StandardError; end
7
9
 
10
+ # Configuration settings, available everywhere
11
+ #
12
+ # There are defaults, which can be overridden by ENV variables prefixed by
13
+ # <tt>HUTCH_</tt>, and each of these can be overridden using the {.set}
14
+ # method.
15
+ #
16
+ # @example Configuring on the command-line
17
+ # HUTCH_PUBLISHER_CONFIRMS=false hutch
8
18
  module Config
9
19
  require 'yaml'
20
+ @string_keys = Set.new
21
+ @number_keys = Set.new
22
+ @boolean_keys = Set.new
23
+ @settings_defaults = {}
10
24
 
11
- def self.initialize(params={})
12
- @config = {
13
- mq_host: 'localhost',
14
- mq_port: 5672,
15
- mq_exchange: 'hutch', # TODO: should this be required?
16
- mq_vhost: '/',
17
- mq_tls: false,
25
+ # Define a String user setting
26
+ # @!visibility private
27
+ def self.string_setting(name, default_value)
28
+ @string_keys << name
29
+ @settings_defaults[name] = default_value
30
+ end
31
+
32
+ # Define a Number user setting
33
+ # @!visibility private
34
+ def self.number_setting(name, default_value)
35
+ @number_keys << name
36
+ @settings_defaults[name] = default_value
37
+ end
38
+
39
+ # Define a Boolean user setting
40
+ # @!visibility private
41
+ def self.boolean_setting(name, default_value)
42
+ @boolean_keys << name
43
+ @settings_defaults[name] = default_value
44
+ end
45
+
46
+ # RabbitMQ hostname
47
+ string_setting :mq_host, '127.0.0.1'
48
+
49
+ # RabbitMQ Exchange to use for publishing
50
+ string_setting :mq_exchange, 'hutch'
51
+
52
+ # RabbitMQ Exchange type to use for publishing
53
+ string_setting :mq_exchange_type, 'topic'
54
+
55
+ # RabbitMQ vhost to use
56
+ string_setting :mq_vhost, '/'
57
+
58
+ # RabbitMQ username to use.
59
+ #
60
+ # As of RabbitMQ 3.3.0, <tt>guest</tt> can only can connect from localhost.
61
+ string_setting :mq_username, 'guest'
62
+
63
+ # RabbitMQ password
64
+ string_setting :mq_password, 'guest'
65
+
66
+ # RabbitMQ URI (takes precedence over MQ username, password, host, port and vhost settings)
67
+ string_setting :uri, nil
68
+
69
+ # RabbitMQ HTTP API hostname
70
+ string_setting :mq_api_host, '127.0.0.1'
71
+
72
+ # RabbitMQ port
73
+ number_setting :mq_port, 5672
74
+
75
+ # RabbitMQ HTTP API port
76
+ number_setting :mq_api_port, 15672
77
+
78
+ # [RabbitMQ heartbeat timeout](http://rabbitmq.com/heartbeats.html)
79
+ number_setting :heartbeat, 30
80
+
81
+ # The <tt>basic.qos</tt> prefetch value to use.
82
+ #
83
+ # Default: `0`, no limit. See Bunny and RabbitMQ documentation.
84
+ number_setting :channel_prefetch, 0
85
+
86
+ # Bunny's socket open timeout
87
+ number_setting :connection_timeout, 11
88
+
89
+ # Bunny's socket read timeout
90
+ number_setting :read_timeout, 11
91
+
92
+ # Bunny's socket write timeout
93
+ number_setting :write_timeout, 11
94
+
95
+ # Bunny's enable/disable network recovery
96
+ boolean_setting :automatically_recover, true
97
+
98
+ # Bunny's reconnect interval
99
+ number_setting :network_recovery_interval, 1
100
+
101
+ # FIXME: DOCUMENT THIS
102
+ number_setting :graceful_exit_timeout, 11
103
+
104
+ # Bunny consumer work pool size
105
+ number_setting :consumer_pool_size, 1
106
+
107
+ # Should TLS be used?
108
+ boolean_setting :mq_tls, false
109
+
110
+ # Should SSL certificate be verified?
111
+ boolean_setting :mq_verify_peer, true
112
+
113
+ # Should SSL be used for the RabbitMQ API?
114
+ boolean_setting :mq_api_ssl, false
115
+
116
+ # Should the current Rails app directory be required?
117
+ boolean_setting :autoload_rails, true
118
+
119
+ # Should the Hutch runner process daemonise?
120
+ #
121
+ # The option is ignored on JRuby.
122
+ boolean_setting :daemonise, false
123
+
124
+ # Should RabbitMQ publisher confirms be enabled?
125
+ #
126
+ # Leaves it up to the app how they are tracked
127
+ # (e.g. using Hutch::Broker#confirm_select callback or Hutch::Broker#wait_for_confirms)
128
+ boolean_setting :publisher_confirms, false
129
+
130
+ # Enables publisher confirms, forces Hutch::Broker#wait_for_confirms for
131
+ # every publish.
132
+ #
133
+ # **This is the safest option which also offers the
134
+ # lowest throughput**.
135
+ boolean_setting :force_publisher_confirms, false
136
+
137
+ # Should the RabbitMQ HTTP API be used?
138
+ boolean_setting :enable_http_api_use, true
139
+
140
+ # Should Bunny's consumer work pool threads abort on exception.
141
+ #
142
+ # The option is ignored on JRuby.
143
+ boolean_setting :consumer_pool_abort_on_exception, false
144
+
145
+ # Prefix displayed on the consumers tags.
146
+ string_setting :consumer_tag_prefix, 'hutch'
147
+
148
+ # A namespace to help group your queues
149
+ string_setting :namespace, nil
150
+
151
+ string_setting :group, ''
152
+
153
+ # Set of all setting keys
154
+ ALL_KEYS = @boolean_keys + @number_keys + @string_keys
155
+
156
+ def self.initialize(params = {})
157
+ unless @config
158
+ @config = default_config
159
+ define_methods
160
+ @config.merge!(env_based_config)
161
+ end
162
+ @config.merge!(params)
163
+ @config
164
+ end
165
+
166
+ # Default settings
167
+ #
168
+ # @return [Hash]
169
+ def self.default_config
170
+ @settings_defaults.merge({
171
+ mq_exchange_options: {},
18
172
  mq_tls_cert: nil,
19
173
  mq_tls_key: nil,
20
- mq_username: 'guest',
21
- mq_password: 'guest',
22
- mq_api_host: 'localhost',
23
- mq_api_port: 15672,
24
- mq_api_ssl: false,
25
- heartbeat: 30,
26
- # placeholder, allows specifying connection parameters
27
- # as a URI.
174
+ mq_tls_ca_certificates: nil,
28
175
  uri: nil,
29
176
  log_level: Logger::INFO,
177
+ client_logger: nil,
30
178
  require_paths: [],
31
- autoload_rails: true,
32
179
  error_handlers: [Hutch::ErrorHandlers::Logger.new],
180
+ # note that this is not a list, it is a chain of responsibility
181
+ # that will fall back to "nack unconditionally"
182
+ error_acknowledgements: [],
183
+ setup_procs: [],
184
+ consumer_groups: {},
33
185
  tracer: Hutch::Tracers::NullTracer,
34
186
  namespace: nil,
35
- daemonise: false,
36
187
  pidfile: nil,
37
- channel_prefetch: 0,
38
- # enables publisher confirms, leaves it up to the app
39
- # how they are tracked
40
- publisher_confirms: false,
41
- # like `publisher_confirms` above but also
42
- # forces waiting for a confirm for every publish
43
- force_publisher_confirms: false,
44
- # Heroku needs > 10. MK.
45
- connection_timeout: 11,
46
- read_timeout: 11,
47
- write_timeout: 11,
48
- enable_http_api_use: true,
49
- # Number of seconds that a running consumer is given
50
- # to finish its job when gracefully exiting Hutch, before
51
- # it's killed.
52
- graceful_exit_timeout: 11,
53
- client_logger: nil,
188
+ serializer: Hutch::Serializers::JSON
189
+ })
190
+ end
191
+
192
+ # Override defaults with ENV variables which begin with <tt>HUTCH_</tt>
193
+ #
194
+ # @return [Hash]
195
+ def self.env_based_config
196
+ env_keys_configured.each_with_object({}) {|attr, result|
197
+ value = ENV[key_for(attr)]
54
198
 
55
- consumer_pool_size: 1,
56
- }.merge(params)
199
+ result[attr] = type_cast(attr, value)
200
+ }
201
+ end
202
+
203
+ # @return [Array<Symbol>]
204
+ def self.env_keys_configured
205
+ ALL_KEYS.each {|attr| check_attr(attr) }
206
+
207
+ ALL_KEYS.select { |attr| ENV.key?(key_for(attr)) }
57
208
  end
58
209
 
59
210
  def self.get(attr)
60
- check_attr(attr)
61
- user_config[attr]
211
+ check_attr(attr.to_sym)
212
+ user_config[attr.to_sym]
213
+ end
214
+
215
+ def self.key_for(attr)
216
+ key = attr.to_s.gsub('.', '__').upcase
217
+ "HUTCH_#{key}"
218
+ end
219
+
220
+ def self.is_bool(attr)
221
+ @boolean_keys.include?(attr)
222
+ end
223
+
224
+ def self.to_bool(value)
225
+ !(value.nil? || value == '' || value =~ /^(false|f|no|n|0)$/i || value == false)
226
+ end
227
+
228
+ def self.is_num(attr)
229
+ @number_keys.include?(attr)
62
230
  end
63
231
 
64
232
  def self.set(attr, value)
65
- check_attr(attr)
66
- user_config[attr] = value
233
+ check_attr(attr.to_sym)
234
+ user_config[attr.to_sym] = type_cast(attr, value)
67
235
  end
68
236
 
69
237
  class << self
@@ -73,17 +241,16 @@ module Hutch
73
241
 
74
242
  def self.check_attr(attr)
75
243
  unless user_config.key?(attr)
76
- raise UnknownAttributeError, "#{attr} is not a valid config attribute"
244
+ raise UnknownAttributeError, "#{attr.inspect} is not a valid config attribute"
77
245
  end
78
246
  end
79
247
 
80
248
  def self.user_config
81
- initialize unless @config
82
- @config
249
+ @config ||= initialize
83
250
  end
84
251
 
85
252
  def self.to_hash
86
- self.user_config
253
+ user_config
87
254
  end
88
255
 
89
256
  def self.load_from_file(file)
@@ -94,28 +261,36 @@ module Hutch
94
261
 
95
262
  def self.convert_value(attr, value)
96
263
  case attr
97
- when "tracer"
264
+ when 'tracer'
98
265
  Kernel.const_get(value)
99
266
  else
100
267
  value
101
268
  end
102
269
  end
103
270
 
104
- def self.method_missing(method, *args, &block)
105
- attr = method.to_s.sub(/=$/, '').to_sym
106
- return super unless user_config.key?(attr)
107
-
108
- if method =~ /=$/
109
- set(attr, args.first)
271
+ def self.type_cast(attr, value)
272
+ case
273
+ when is_bool(attr) || value == 'false'
274
+ to_bool(value)
275
+ when is_num(attr)
276
+ value.to_i
110
277
  else
111
- get(attr)
278
+ value
112
279
  end
113
280
  end
281
+ private_class_method :type_cast
114
282
 
115
- private
283
+ def self.define_methods
284
+ @config.keys.each do |key|
285
+ define_singleton_method(key) do
286
+ get(key)
287
+ end
116
288
 
117
- def deep_copy(obj)
118
- Marshal.load(Marshal.dump(obj))
289
+ define_singleton_method("#{key}=") do |val|
290
+ set(key, val)
291
+ end
292
+ end
119
293
  end
120
294
  end
121
295
  end
296
+ Hutch::Config.initialize
@@ -19,7 +19,7 @@ module Hutch
19
19
  def requeue!
20
20
  broker.requeue(delivery_info.delivery_tag)
21
21
  end
22
-
22
+
23
23
  def logger
24
24
  Hutch::Logging.logger
25
25
  end
@@ -29,18 +29,47 @@ module Hutch
29
29
  # wants to subscribe to.
30
30
  def consume(*routing_keys)
31
31
  @routing_keys = self.routing_keys.union(routing_keys)
32
+ # these are opt-in
33
+ @queue_mode = nil
34
+ @queue_type = nil
32
35
  end
33
36
 
37
+ attr_reader :queue_mode, :queue_type, :initial_group_size
38
+
34
39
  # Explicitly set the queue name
35
40
  def queue_name(name)
36
41
  @queue_name = name
37
42
  end
38
43
 
39
- # Allow to specify custom arguments that will be passed when creating the queue.
44
+ # Explicitly set the queue mode to 'lazy'
45
+ def lazy_queue
46
+ @queue_mode = 'lazy'
47
+ end
48
+
49
+ # Explicitly set the queue type to 'classic'
50
+ def classic_queue
51
+ @queue_type = 'classic'
52
+ end
53
+
54
+ # Explicitly set the queue type to 'quorum'
55
+ # @param [Hash] options the options params related to quorum queue
56
+ # @option options [Integer] :initial_group_size Initial Replication Factor
57
+ def quorum_queue(options = {})
58
+ @queue_type = 'quorum'
59
+ @initial_group_size = options[:initial_group_size]
60
+ end
61
+
62
+ # Configures an optional argument that will be passed when declaring the queue.
63
+ # Prefer using a policy to this DSL: https://www.rabbitmq.com/parameters.html#policies
40
64
  def arguments(arguments = {})
41
65
  @arguments = arguments
42
66
  end
43
67
 
68
+ # Set custom serializer class, override global value
69
+ def serializer(name)
70
+ @serializer = name
71
+ end
72
+
44
73
  # The RabbitMQ queue name for the consumer. This is derived from the
45
74
  # fully-qualified class name. Module separators are replaced with single
46
75
  # colons, camelcased class names are converted to snake case.
@@ -53,13 +82,23 @@ module Hutch
53
82
 
54
83
  # Returns consumer custom arguments.
55
84
  def get_arguments
56
- @arguments || {}
85
+ all_arguments = @arguments || {}
86
+
87
+ all_arguments['x-queue-mode'] = @queue_mode if @queue_mode
88
+ all_arguments['x-queue-type'] = @queue_type if @queue_type
89
+ all_arguments['x-quorum-initial-group-size'] = @initial_group_size if @initial_group_size
90
+
91
+ all_arguments
57
92
  end
58
93
 
59
94
  # Accessor for the consumer's routing key.
60
95
  def routing_keys
61
96
  @routing_keys ||= Set.new
62
97
  end
98
+
99
+ def get_serializer
100
+ @serializer
101
+ end
63
102
  end
64
103
  end
65
104
  end
@@ -1,25 +1,53 @@
1
1
  require 'hutch/logging'
2
2
  require 'airbrake'
3
+ require 'hutch/error_handlers/base'
3
4
 
4
5
  module Hutch
5
6
  module ErrorHandlers
6
- class Airbrake
7
- include Logging
7
+ class Airbrake < Base
8
8
 
9
- def handle(message_id, payload, consumer, ex)
10
- prefix = "message(#{message_id || '-'}): "
11
- logger.error prefix + "Logging event to Airbrake"
12
- logger.error prefix + "#{ex.class} - #{ex.message}"
13
- ::Airbrake.notify_or_ignore(ex, {
14
- :error_class => ex.class.name,
15
- :error_message => "#{ ex.class.name }: #{ ex.message }",
16
- :backtrace => ex.backtrace,
17
- :parameters => {
18
- :payload => payload,
19
- :consumer => consumer,
20
- },
21
- :cgi_data => ENV.to_hash,
22
- })
9
+ def handle(properties, payload, consumer, ex)
10
+ message_id = properties.message_id
11
+ prefix = "message(#{message_id || '-'}):"
12
+ logger.error "#{prefix} Logging event to Airbrake"
13
+ logger.error "#{prefix} #{ex.class} - #{ex.message}"
14
+
15
+ if ::Airbrake.respond_to?(:notify_or_ignore)
16
+ ::Airbrake.notify_or_ignore(ex, {
17
+ error_class: ex.class.name,
18
+ error_message: "#{ ex.class.name }: #{ ex.message }",
19
+ backtrace: ex.backtrace,
20
+ parameters: {
21
+ payload: payload,
22
+ consumer: consumer,
23
+ },
24
+ cgi_data: ENV.to_hash,
25
+ })
26
+ else
27
+ ::Airbrake.notify(ex, {
28
+ payload: payload,
29
+ consumer: consumer,
30
+ cgi_data: ENV.to_hash,
31
+ })
32
+ end
33
+ end
34
+
35
+ def handle_setup_exception(ex)
36
+ logger.error "Logging setup exception to Airbrake"
37
+ logger.error "#{ex.class} - #{ex.message}"
38
+
39
+ if ::Airbrake.respond_to?(:notify_or_ignore)
40
+ ::Airbrake.notify_or_ignore(ex, {
41
+ error_class: ex.class.name,
42
+ error_message: "#{ ex.class.name }: #{ ex.message }",
43
+ backtrace: ex.backtrace,
44
+ cgi_data: ENV.to_hash,
45
+ })
46
+ else
47
+ ::Airbrake.notify(ex, {
48
+ cgi_data: ENV.to_hash,
49
+ })
50
+ end
23
51
  end
24
52
  end
25
53
  end
@@ -0,0 +1,15 @@
1
+ module Hutch
2
+ module ErrorHandlers
3
+ class Base
4
+ include Logging
5
+
6
+ def handle(properties, payload, consumer, ex)
7
+ raise NotImplementedError.new
8
+ end
9
+
10
+ def handle_setup_exception(ex)
11
+ raise NotImplementedError.new
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,30 @@
1
+ require "hutch/logging"
2
+ require "bugsnag"
3
+ require "hutch/error_handlers/base"
4
+
5
+ module Hutch
6
+ module ErrorHandlers
7
+ class Bugsnag < Base
8
+ def handle(properties, payload, consumer, ex)
9
+ message_id = properties.message_id
10
+ prefix = "message(#{message_id || "-"}):"
11
+ logger.error "#{prefix} Logging event to Bugsnag"
12
+ logger.error "#{prefix} #{ex.class} - #{ex.message}"
13
+
14
+ ::Bugsnag.notify(ex) do |report|
15
+ report.add_tab(:hutch, {
16
+ payload: payload,
17
+ consumer: consumer
18
+ })
19
+ end
20
+ end
21
+
22
+ def handle_setup_exception(ex)
23
+ logger.error "Logging setup exception to Bugsnag"
24
+ logger.error "#{ex.class} - #{ex.message}"
25
+
26
+ ::Bugsnag.notify(ex)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -1,27 +1,42 @@
1
1
  require 'hutch/logging'
2
2
  require 'honeybadger'
3
+ require 'hutch/error_handlers/base'
3
4
 
4
5
  module Hutch
5
6
  module ErrorHandlers
6
- class Honeybadger
7
- include Logging
7
+ # Error handler for the Honeybadger.io service
8
+ class Honeybadger < Base
8
9
 
9
- def handle(message_id, payload, consumer, ex)
10
- prefix = "message(#{message_id || '-'}): "
11
- logger.error prefix + "Logging event to Honeybadger"
12
- logger.error prefix + "#{ex.class} - #{ex.message}"
13
- ::Honeybadger.notify_or_ignore(
14
- :error_class => ex.class.name,
15
- :error_message => "#{ ex.class.name }: #{ ex.message }",
16
- :backtrace => ex.backtrace,
17
- :context => {
18
- :message_id => message_id,
19
- :consumer => consumer
20
- },
21
- :parameters => {
22
- :payload => payload
23
- }
24
- )
10
+ def handle(properties, payload, consumer, ex)
11
+ message_id = properties.message_id
12
+ prefix = "message(#{message_id || '-'}):"
13
+ logger.error "#{prefix} Logging event to Honeybadger"
14
+ logger.error "#{prefix} #{ex.class} - #{ex.message}"
15
+ notify_honeybadger(error_class: ex.class.name,
16
+ error_message: "#{ex.class.name}: #{ex.message}",
17
+ backtrace: ex.backtrace,
18
+ context: { message_id: message_id,
19
+ consumer: consumer },
20
+ parameters: { payload: payload })
21
+ end
22
+
23
+ def handle_setup_exception(ex)
24
+ logger.error "Logging setup exception to Honeybadger"
25
+ logger.error "#{ex.class} - #{ex.message}"
26
+ notify_honeybadger(error_class: ex.class.name,
27
+ error_message: "#{ex.class.name}: #{ex.message}",
28
+ backtrace: ex.backtrace)
29
+ end
30
+
31
+ # Wrap API to support 3.0.0+
32
+ #
33
+ # @see https://github.com/honeybadger-io/honeybadger-ruby/blob/master/CHANGELOG.md#300---2017-02-06
34
+ def notify_honeybadger(message)
35
+ if ::Honeybadger.respond_to?(:notify_or_ignore)
36
+ ::Honeybadger.notify_or_ignore(message)
37
+ else
38
+ ::Honeybadger.notify(message)
39
+ end
25
40
  end
26
41
  end
27
42
  end
@@ -1,14 +1,20 @@
1
1
  require 'hutch/logging'
2
+ require 'hutch/error_handlers/base'
2
3
 
3
4
  module Hutch
4
5
  module ErrorHandlers
5
- class Logger
6
- include Logging
6
+ class Logger < ErrorHandlers::Base
7
7
 
8
- def handle(message_id, payload, consumer, ex)
9
- prefix = "message(#{message_id || '-'}): "
10
- logger.error prefix + "error in consumer '#{consumer}'"
11
- logger.error prefix + "#{ex.class} - #{ex.message}"
8
+ def handle(properties, payload, consumer, ex)
9
+ message_id = properties.message_id
10
+ prefix = "message(#{message_id || '-'}):"
11
+ logger.error "#{prefix} error in consumer '#{consumer}'"
12
+ logger.error "#{prefix} #{ex.class} - #{ex.message}"
13
+ logger.error (['backtrace:'] + ex.backtrace).join("\n")
14
+ end
15
+
16
+ def handle_setup_exception(ex)
17
+ logger.error "#{ex.class} - #{ex.message}"
12
18
  logger.error (['backtrace:'] + ex.backtrace).join("\n")
13
19
  end
14
20
  end
@@ -0,0 +1,28 @@
1
+ require 'hutch/logging'
2
+ require 'rollbar'
3
+ require 'hutch/error_handlers/base'
4
+
5
+ module Hutch
6
+ module ErrorHandlers
7
+ class Rollbar < Base
8
+ def handle(properties, payload, consumer, ex)
9
+ message_id = properties.message_id
10
+ prefix = "message(#{message_id || '-'}):"
11
+ logger.error "#{prefix} Logging event to Rollbar"
12
+ logger.error "#{prefix} #{ex.class} - #{ex.message}"
13
+
14
+ ::Rollbar.error(ex,
15
+ payload: payload,
16
+ consumer: consumer
17
+ )
18
+ end
19
+
20
+ def handle_setup_exception(ex)
21
+ logger.error "Logging setup exception to Rollbar"
22
+ logger.error "#{ex.class} - #{ex.message}"
23
+
24
+ ::Rollbar.error(ex)
25
+ end
26
+ end
27
+ end
28
+ end