hutch 0.18.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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