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.
- checksums.yaml +5 -5
- data/.gitignore +3 -0
- data/.rspec +1 -0
- data/.travis.yml +20 -8
- data/.yardopts +5 -0
- data/CHANGELOG.md +466 -2
- data/Gemfile +18 -4
- data/Guardfile +13 -4
- data/LICENSE +2 -1
- data/README.md +397 -32
- data/Rakefile +8 -1
- data/bin/ci/before_build.sh +20 -0
- data/bin/ci/install_on_debian.sh +46 -0
- data/hutch.gemspec +6 -7
- data/lib/hutch/acknowledgements/base.rb +16 -0
- data/lib/hutch/acknowledgements/nack_on_all_failures.rb +19 -0
- data/lib/hutch/adapters/march_hare.rb +1 -1
- data/lib/hutch/broker.rb +127 -103
- data/lib/hutch/cli.rb +66 -25
- data/lib/hutch/config.rb +230 -55
- data/lib/hutch/consumer.rb +42 -3
- data/lib/hutch/error_handlers/airbrake.rb +44 -16
- data/lib/hutch/error_handlers/base.rb +15 -0
- data/lib/hutch/error_handlers/bugsnag.rb +30 -0
- data/lib/hutch/error_handlers/honeybadger.rb +33 -18
- data/lib/hutch/error_handlers/logger.rb +12 -6
- data/lib/hutch/error_handlers/rollbar.rb +28 -0
- data/lib/hutch/error_handlers/sentry.rb +15 -12
- data/lib/hutch/error_handlers/sentry_raven.rb +31 -0
- data/lib/hutch/error_handlers.rb +3 -0
- data/lib/hutch/exceptions.rb +8 -1
- data/lib/hutch/logging.rb +5 -5
- data/lib/hutch/message.rb +2 -4
- data/lib/hutch/publisher.rb +75 -0
- data/lib/hutch/serializers/identity.rb +19 -0
- data/lib/hutch/serializers/json.rb +22 -0
- data/lib/hutch/tracers/datadog.rb +17 -0
- data/lib/hutch/tracers.rb +1 -0
- data/lib/hutch/version.rb +1 -2
- data/lib/hutch/waiter.rb +104 -0
- data/lib/hutch/worker.rb +81 -75
- data/lib/hutch.rb +15 -6
- data/lib/yard-settings/handler.rb +38 -0
- data/lib/yard-settings/yard-settings.rb +2 -0
- data/spec/hutch/broker_spec.rb +162 -77
- data/spec/hutch/cli_spec.rb +16 -3
- data/spec/hutch/config_spec.rb +121 -22
- data/spec/hutch/consumer_spec.rb +82 -4
- data/spec/hutch/error_handlers/airbrake_spec.rb +25 -10
- data/spec/hutch/error_handlers/bugsnag_spec.rb +55 -0
- data/spec/hutch/error_handlers/honeybadger_spec.rb +24 -2
- data/spec/hutch/error_handlers/logger_spec.rb +14 -1
- data/spec/hutch/error_handlers/rollbar_spec.rb +45 -0
- data/spec/hutch/error_handlers/sentry_raven_spec.rb +37 -0
- data/spec/hutch/error_handlers/sentry_spec.rb +21 -2
- data/spec/hutch/logger_spec.rb +12 -6
- data/spec/hutch/message_spec.rb +2 -2
- data/spec/hutch/serializers/json_spec.rb +17 -0
- data/spec/hutch/tracers/datadog_spec.rb +44 -0
- data/spec/hutch/waiter_spec.rb +51 -0
- data/spec/hutch/worker_spec.rb +89 -5
- data/spec/spec_helper.rb +7 -5
- data/templates/default/class/html/settings.erb +0 -0
- data/templates/default/class/setup.rb +4 -0
- data/templates/default/fulldoc/html/css/hutch.css +13 -0
- data/templates/default/layout/html/setup.rb +7 -0
- data/templates/default/method_details/html/settings.erb +5 -0
- data/templates/default/method_details/setup.rb +4 -0
- data/templates/default/method_details/text/settings.erb +0 -0
- data/templates/default/module/html/settings.erb +40 -0
- data/templates/default/module/setup.rb +4 -0
- metadata +62 -43
- 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
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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
|
-
|
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
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
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
|
-
|
56
|
-
}
|
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
|
-
|
82
|
-
@config
|
249
|
+
@config ||= initialize
|
83
250
|
end
|
84
251
|
|
85
252
|
def self.to_hash
|
86
|
-
|
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
|
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.
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
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
|
-
|
278
|
+
value
|
112
279
|
end
|
113
280
|
end
|
281
|
+
private_class_method :type_cast
|
114
282
|
|
115
|
-
|
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
|
-
|
118
|
-
|
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
|
data/lib/hutch/consumer.rb
CHANGED
@@ -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
|
-
#
|
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(
|
10
|
-
|
11
|
-
|
12
|
-
logger.error
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
:
|
19
|
-
:
|
20
|
-
|
21
|
-
|
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
|
-
|
7
|
-
|
7
|
+
# Error handler for the Honeybadger.io service
|
8
|
+
class Honeybadger < Base
|
8
9
|
|
9
|
-
def handle(
|
10
|
-
|
11
|
-
|
12
|
-
logger.error
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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(
|
9
|
-
|
10
|
-
|
11
|
-
logger.error
|
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
|