honeybadger 5.16.0 → 5.26.4
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 +4 -4
- data/CHANGELOG.md +122 -0
- data/lib/honeybadger/agent.rb +16 -0
- data/lib/honeybadger/backend/test.rb +5 -1
- data/lib/honeybadger/backtrace.rb +2 -1
- data/lib/honeybadger/breadcrumbs/active_support.rb +1 -1
- data/lib/honeybadger/cli/test.rb +1 -0
- data/lib/honeybadger/config/defaults.rb +105 -3
- data/lib/honeybadger/config.rb +15 -1
- data/lib/honeybadger/gauge.rb +1 -0
- data/lib/honeybadger/histogram.rb +14 -0
- data/lib/honeybadger/init/hanami.rb +1 -1
- data/lib/honeybadger/init/rails.rb +9 -4
- data/lib/honeybadger/init/sinatra.rb +2 -2
- data/lib/honeybadger/instrumentation.rb +57 -21
- data/lib/honeybadger/instrumentation_helper.rb +17 -11
- data/lib/honeybadger/karafka.rb +301 -0
- data/lib/honeybadger/notice.rb +14 -7
- data/lib/honeybadger/notification_subscriber.rb +39 -19
- data/lib/honeybadger/plugins/active_job.rb +1 -2
- data/lib/honeybadger/plugins/autotuner.rb +9 -6
- data/lib/honeybadger/plugins/delayed_job.rb +1 -0
- data/lib/honeybadger/plugins/faktory.rb +1 -0
- data/lib/honeybadger/plugins/karafka.rb +7 -16
- data/lib/honeybadger/plugins/net_http.rb +17 -3
- data/lib/honeybadger/plugins/rails.rb +7 -1
- data/lib/honeybadger/plugins/resque.rb +1 -0
- data/lib/honeybadger/plugins/shoryuken.rb +1 -0
- data/lib/honeybadger/plugins/sidekiq.rb +107 -79
- data/lib/honeybadger/plugins/solid_queue.rb +38 -12
- data/lib/honeybadger/plugins/sucker_punch.rb +1 -0
- data/lib/honeybadger/plugins/thor.rb +1 -0
- data/lib/honeybadger/registry_execution.rb +1 -0
- data/lib/honeybadger/version.rb +1 -1
- data/lib/puma/plugin/honeybadger.rb +9 -3
- metadata +18 -6
@@ -56,7 +56,7 @@ module Honeybadger
|
|
56
56
|
metric_instrumentation.time(name, attributes, ->{ callable.call })
|
57
57
|
elsif block_given?
|
58
58
|
metric_instrumentation.time(name, attributes, ->{ yield })
|
59
|
-
|
59
|
+
else
|
60
60
|
metric_instrumentation.time(name, attributes)
|
61
61
|
end
|
62
62
|
end
|
@@ -68,38 +68,44 @@ module Honeybadger
|
|
68
68
|
metric_instrumentation.histogram(name, attributes, ->{ callable.call })
|
69
69
|
elsif block_given?
|
70
70
|
metric_instrumentation.histogram(name, attributes, ->{ yield })
|
71
|
-
|
71
|
+
else
|
72
72
|
metric_instrumentation.histogram(name, attributes)
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
76
76
|
def increment_counter(name, *args)
|
77
77
|
attributes = extract_attributes(args)
|
78
|
-
|
79
|
-
if
|
78
|
+
callable = extract_callable(args)
|
79
|
+
if callable
|
80
|
+
metric_instrumentation.increment_counter(name, attributes, ->{ callable.call })
|
81
|
+
elsif block_given?
|
80
82
|
metric_instrumentation.increment_counter(name, attributes, ->{ yield })
|
81
83
|
else
|
82
|
-
metric_instrumentation.increment_counter(name, attributes
|
84
|
+
metric_instrumentation.increment_counter(name, attributes)
|
83
85
|
end
|
84
86
|
end
|
85
87
|
|
86
88
|
def decrement_counter(name, *args)
|
87
89
|
attributes = extract_attributes(args)
|
88
|
-
|
89
|
-
if
|
90
|
+
callable = extract_callable(args)
|
91
|
+
if callable
|
92
|
+
metric_instrumentation.decrement_counter(name, attributes, ->{ callable.call })
|
93
|
+
elsif block_given?
|
90
94
|
metric_instrumentation.decrement_counter(name, attributes, ->{ yield })
|
91
95
|
else
|
92
|
-
metric_instrumentation.decrement_counter(name, attributes
|
96
|
+
metric_instrumentation.decrement_counter(name, attributes)
|
93
97
|
end
|
94
98
|
end
|
95
99
|
|
96
100
|
def gauge(name, *args)
|
97
101
|
attributes = extract_attributes(args)
|
98
|
-
|
99
|
-
if
|
102
|
+
callable = extract_callable(args)
|
103
|
+
if callable
|
104
|
+
metric_instrumentation.gauge(name, attributes, ->{ callable.call })
|
105
|
+
elsif block_given?
|
100
106
|
metric_instrumentation.gauge(name, attributes, ->{ yield })
|
101
107
|
else
|
102
|
-
metric_instrumentation.gauge(name, attributes
|
108
|
+
metric_instrumentation.gauge(name, attributes)
|
103
109
|
end
|
104
110
|
end
|
105
111
|
|
@@ -0,0 +1,301 @@
|
|
1
|
+
require 'honeybadger/instrumentation_helper'
|
2
|
+
|
3
|
+
module Honeybadger
|
4
|
+
module Karafka
|
5
|
+
class ErrorsListener
|
6
|
+
# Sends error details to Honeybadger
|
7
|
+
#
|
8
|
+
# @param event [Karafka::Core::Monitoring::Event]
|
9
|
+
def on_error_occurred(event)
|
10
|
+
context = {
|
11
|
+
type: event[:type]
|
12
|
+
}
|
13
|
+
tags = ["type:#{event[:type]}"]
|
14
|
+
|
15
|
+
if (consumer = event.payload[:caller]).respond_to?(:messages)
|
16
|
+
messages = consumer.messages
|
17
|
+
metadata = messages.metadata
|
18
|
+
consumer_group_id = consumer.topic.consumer_group.id
|
19
|
+
|
20
|
+
context[:topic] = metadata.topic
|
21
|
+
context[:partition] = metadata.partition
|
22
|
+
context[:consumer_group] = consumer_group_id
|
23
|
+
end
|
24
|
+
|
25
|
+
Honeybadger.notify(event[:error], context: context)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class InsightsListener
|
30
|
+
include ::Honeybadger::InstrumentationHelper
|
31
|
+
|
32
|
+
# Value object for storing a single rdkafka metric publishing details
|
33
|
+
RdKafkaMetric = Struct.new(:type, :scope, :name, :key_location)
|
34
|
+
|
35
|
+
# All the rdkafka metrics we want to publish
|
36
|
+
#
|
37
|
+
# By default we publish quite a lot so this can be tuned
|
38
|
+
# Note, that the once with `_d` come from Karafka, not rdkafka or Kafka
|
39
|
+
RD_KAFKA_METRICS = [
|
40
|
+
# Client metrics
|
41
|
+
RdKafkaMetric.new(:increment_counter, :root, 'messages_consumed', 'rxmsgs_d'),
|
42
|
+
RdKafkaMetric.new(:increment_counter, :root, 'messages_consumed_bytes', 'rxmsg_bytes'),
|
43
|
+
|
44
|
+
# Broker metrics
|
45
|
+
RdKafkaMetric.new(:increment_counter, :brokers, 'consume_attempts', 'txretries_d'),
|
46
|
+
RdKafkaMetric.new(:increment_counter, :brokers, 'consume_errors', 'txerrs_d'),
|
47
|
+
RdKafkaMetric.new(:increment_counter, :brokers, 'receive_errors', 'rxerrs_d'),
|
48
|
+
RdKafkaMetric.new(:increment_counter, :brokers, 'connection_connects', 'connects_d'),
|
49
|
+
RdKafkaMetric.new(:increment_counter, :brokers, 'connection_disconnects', 'disconnects_d'),
|
50
|
+
RdKafkaMetric.new(:gauge, :brokers, 'network_latency_avg', %w[rtt avg]),
|
51
|
+
RdKafkaMetric.new(:gauge, :brokers, 'network_latency_p95', %w[rtt p95]),
|
52
|
+
RdKafkaMetric.new(:gauge, :brokers, 'network_latency_p99', %w[rtt p99]),
|
53
|
+
|
54
|
+
# Topics metrics
|
55
|
+
RdKafkaMetric.new(:gauge, :topics, 'consumer_lags', 'consumer_lag_stored'),
|
56
|
+
RdKafkaMetric.new(:gauge, :topics, 'consumer_lags_delta', 'consumer_lag_stored_d')
|
57
|
+
].freeze
|
58
|
+
|
59
|
+
# Metrics that sum values on topics levels and not on partition levels
|
60
|
+
AGGREGATED_RD_KAFKA_METRICS = [
|
61
|
+
# Topic aggregated metrics
|
62
|
+
RdKafkaMetric.new(:gauge, :topics, 'consumer_aggregated_lag', 'consumer_lag_stored')
|
63
|
+
].freeze
|
64
|
+
|
65
|
+
def initialize
|
66
|
+
metric_source("karafka")
|
67
|
+
end
|
68
|
+
|
69
|
+
# Hooks up to Karafka instrumentation for emitted statistics
|
70
|
+
#
|
71
|
+
# @param event [Karafka::Core::Monitoring::Event]
|
72
|
+
def on_statistics_emitted(event)
|
73
|
+
if Honeybadger.config.load_plugin_insights_events?(:karafka)
|
74
|
+
Honeybadger.event("statistics_emitted.karafka", event.payload)
|
75
|
+
end
|
76
|
+
|
77
|
+
return unless Honeybadger.config.load_plugin_insights_metrics?(:karafka)
|
78
|
+
|
79
|
+
statistics = event[:statistics]
|
80
|
+
consumer_group_id = event[:consumer_group_id]
|
81
|
+
|
82
|
+
base_tags = { consumer_group: consumer_group_id }
|
83
|
+
|
84
|
+
RD_KAFKA_METRICS.each do |metric|
|
85
|
+
report_metric(metric, statistics, base_tags)
|
86
|
+
end
|
87
|
+
|
88
|
+
report_aggregated_topics_metrics(statistics, consumer_group_id)
|
89
|
+
end
|
90
|
+
|
91
|
+
# Publishes aggregated topic-level metrics that are sum of per partition metrics
|
92
|
+
#
|
93
|
+
# @param statistics [Hash] hash with all the statistics emitted
|
94
|
+
# @param consumer_group_id [String] cg in context which we operate
|
95
|
+
def report_aggregated_topics_metrics(statistics, consumer_group_id)
|
96
|
+
AGGREGATED_RD_KAFKA_METRICS.each do |metric|
|
97
|
+
statistics.fetch('topics').each do |topic_name, topic_values|
|
98
|
+
sum = 0
|
99
|
+
|
100
|
+
topic_values['partitions'].each do |partition_name, partition_statistics|
|
101
|
+
next if partition_name == '-1'
|
102
|
+
# Skip until lag info is available
|
103
|
+
next if partition_statistics['consumer_lag'] == -1
|
104
|
+
next if partition_statistics['consumer_lag_stored'] == -1
|
105
|
+
|
106
|
+
sum += partition_statistics.dig(*metric.key_location)
|
107
|
+
end
|
108
|
+
|
109
|
+
public_send(
|
110
|
+
metric.type,
|
111
|
+
metric.name,
|
112
|
+
value: sum,
|
113
|
+
consumer_group: consumer_group_id,
|
114
|
+
topic: topic_name
|
115
|
+
)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# Increases the errors count by 1
|
121
|
+
#
|
122
|
+
# @param event [Karafka::Core::Monitoring::Event]
|
123
|
+
def on_error_occurred(event)
|
124
|
+
extra_tags = { type: event[:type] }
|
125
|
+
|
126
|
+
if event.payload[:caller].respond_to?(:messages)
|
127
|
+
extra_tags.merge!(consumer_tags(event.payload[:caller]))
|
128
|
+
end
|
129
|
+
|
130
|
+
if Honeybadger.config.load_plugin_insights_events?(:karafka)
|
131
|
+
Honeybadger.event("error.occurred.karafka", error: event[:error], **extra_tags)
|
132
|
+
end
|
133
|
+
|
134
|
+
if Honeybadger.config.load_plugin_insights_metrics?(:karafka)
|
135
|
+
increment_counter('error_occurred', value: 1, **extra_tags)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# Reports how many messages we've polled and how much time did we spend on it
|
140
|
+
#
|
141
|
+
# @param event [Karafka::Core::Monitoring::Event]
|
142
|
+
def on_connection_listener_fetch_loop_received(event)
|
143
|
+
time_taken = event[:time]
|
144
|
+
messages_count = event[:messages_buffer].size
|
145
|
+
consumer_group_id = event[:subscription_group].consumer_group.id
|
146
|
+
extra_tags = { consumer_group: consumer_group_id }
|
147
|
+
|
148
|
+
if Honeybadger.config.load_plugin_insights_metrics?(:karafka)
|
149
|
+
histogram('listener_polling_time_taken', value: time_taken, **extra_tags)
|
150
|
+
histogram('listener_polling_messages', value: messages_count, **extra_tags)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
# Here we report majority of things related to processing as we have access to the
|
155
|
+
# consumer
|
156
|
+
# @param event [Karafka::Core::Monitoring::Event]
|
157
|
+
def on_consumer_consumed(event)
|
158
|
+
consumer = event.payload[:caller]
|
159
|
+
messages = consumer.messages
|
160
|
+
metadata = messages.metadata
|
161
|
+
|
162
|
+
tags = consumer_tags(consumer)
|
163
|
+
|
164
|
+
if Honeybadger.config.load_plugin_insights_events?(:karafka)
|
165
|
+
event_context = tags.merge({
|
166
|
+
consumer: consumer.class.name,
|
167
|
+
duration: event[:time],
|
168
|
+
processing_lag: metadata.processing_lag,
|
169
|
+
consumption_lag: metadata.consumption_lag,
|
170
|
+
processed: messages.count
|
171
|
+
})
|
172
|
+
Honeybadger.event("consumer.consumed.karafka", event_context)
|
173
|
+
end
|
174
|
+
|
175
|
+
if Honeybadger.config.load_plugin_insights_metrics?(:karafka)
|
176
|
+
increment_counter('consumer_messages', value: messages.count, **tags)
|
177
|
+
increment_counter('consumer_batches', value: 1, **tags)
|
178
|
+
gauge('consumer_offset', value: metadata.last_offset, **tags)
|
179
|
+
histogram('consumer_consumed_time_taken', value: event[:time], **tags)
|
180
|
+
histogram('consumer_batch_size', value: messages.count, **tags)
|
181
|
+
histogram('consumer_processing_lag', value: metadata.processing_lag, **tags)
|
182
|
+
histogram('consumer_consumption_lag', value: metadata.consumption_lag, **tags)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
{
|
187
|
+
revoked: :revoked,
|
188
|
+
shutdown: :shutdown,
|
189
|
+
ticked: :tick
|
190
|
+
}.each do |after, name|
|
191
|
+
class_eval <<~RUBY, __FILE__, __LINE__ + 1
|
192
|
+
# Keeps track of user code execution
|
193
|
+
#
|
194
|
+
# @param event [Karafka::Core::Monitoring::Event]
|
195
|
+
def on_consumer_#{after}(event)
|
196
|
+
if Honeybadger.config.load_plugin_insights_metrics?(:karafka)
|
197
|
+
tags = consumer_tags(event.payload[:caller])
|
198
|
+
increment_counter('consumer_#{name}', value: 1, **tags)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
RUBY
|
202
|
+
end
|
203
|
+
|
204
|
+
# Worker related metrics
|
205
|
+
# @param event [Karafka::Core::Monitoring::Event]
|
206
|
+
def on_worker_process(event)
|
207
|
+
jq_stats = event[:jobs_queue].statistics
|
208
|
+
|
209
|
+
if Honeybadger.config.load_plugin_insights_metrics?(:karafka)
|
210
|
+
gauge('worker_total_threads', value: ::Karafka::App.config.concurrency)
|
211
|
+
histogram('worker_processing', value: jq_stats[:busy])
|
212
|
+
histogram('worker_enqueued_jobs', value: jq_stats[:enqueued])
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
# We report this metric before and after processing for higher accuracy
|
217
|
+
# Without this, the utilization would not be fully reflected
|
218
|
+
# @param event [Karafka::Core::Monitoring::Event]
|
219
|
+
def on_worker_processed(event)
|
220
|
+
jq_stats = event[:jobs_queue].statistics
|
221
|
+
|
222
|
+
if Honeybadger.config.load_plugin_insights_metrics?(:karafka)
|
223
|
+
histogram('worker_processing', value: jq_stats[:busy])
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
private
|
228
|
+
|
229
|
+
# Reports a given metric statistics to Honeybadger
|
230
|
+
# @param metric [RdKafkaMetric] metric value object
|
231
|
+
# @param statistics [Hash] hash with all the statistics emitted
|
232
|
+
# @param base_tags [Array<String>] base tags we want to start with
|
233
|
+
def report_metric(metric, statistics, base_tags)
|
234
|
+
case metric.scope
|
235
|
+
when :root
|
236
|
+
public_send(
|
237
|
+
metric.type,
|
238
|
+
metric.name,
|
239
|
+
value: statistics.fetch(*metric.key_location),
|
240
|
+
**base_tags
|
241
|
+
)
|
242
|
+
when :brokers
|
243
|
+
statistics.fetch('brokers').each_value do |broker_statistics|
|
244
|
+
# Skip bootstrap nodes
|
245
|
+
# Bootstrap nodes have nodeid -1, other nodes have positive
|
246
|
+
# node ids
|
247
|
+
next if broker_statistics['nodeid'] == -1
|
248
|
+
|
249
|
+
public_send(
|
250
|
+
metric.type,
|
251
|
+
metric.name,
|
252
|
+
value: broker_statistics.dig(*metric.key_location),
|
253
|
+
**base_tags.merge(broker: broker_statistics['nodename'])
|
254
|
+
)
|
255
|
+
end
|
256
|
+
when :topics
|
257
|
+
statistics.fetch('topics').each do |topic_name, topic_values|
|
258
|
+
topic_values['partitions'].each do |partition_name, partition_statistics|
|
259
|
+
next if partition_name == '-1'
|
260
|
+
# Skip until lag info is available
|
261
|
+
next if partition_statistics['consumer_lag'] == -1
|
262
|
+
next if partition_statistics['consumer_lag_stored'] == -1
|
263
|
+
|
264
|
+
# Skip if we do not own the fetch assignment
|
265
|
+
next if partition_statistics['fetch_state'] == 'stopped'
|
266
|
+
next if partition_statistics['fetch_state'] == 'none'
|
267
|
+
|
268
|
+
public_send(
|
269
|
+
metric.type,
|
270
|
+
metric.name,
|
271
|
+
value: partition_statistics.dig(*metric.key_location),
|
272
|
+
**base_tags.merge({
|
273
|
+
topic: topic_name,
|
274
|
+
partition: partition_name
|
275
|
+
})
|
276
|
+
)
|
277
|
+
end
|
278
|
+
end
|
279
|
+
else
|
280
|
+
raise ArgumentError, metric.scope
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
# Builds basic per consumer tags for publication
|
285
|
+
#
|
286
|
+
# @param consumer [Karafka::BaseConsumer]
|
287
|
+
# @return [Array<String>]
|
288
|
+
def consumer_tags(consumer)
|
289
|
+
messages = consumer.messages
|
290
|
+
metadata = messages.metadata
|
291
|
+
consumer_group_id = consumer.topic.consumer_group.id
|
292
|
+
|
293
|
+
{
|
294
|
+
topic: metadata.topic,
|
295
|
+
partition: metadata.partition,
|
296
|
+
consumer_group: consumer_group_id
|
297
|
+
}
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
data/lib/honeybadger/notice.rb
CHANGED
@@ -144,6 +144,9 @@ module Honeybadger
|
|
144
144
|
# Custom details data
|
145
145
|
attr_accessor :details
|
146
146
|
|
147
|
+
# The ID of the request which caused this notice.
|
148
|
+
attr_accessor :request_id
|
149
|
+
|
147
150
|
# The parsed exception backtrace. Lines in this backtrace that are from installed gems
|
148
151
|
# have the base path for gem installs replaced by "[GEM_ROOT]", while those in the project
|
149
152
|
# have "[PROJECT_ROOT]".
|
@@ -213,13 +216,14 @@ module Honeybadger
|
|
213
216
|
self.api_key = opts[:api_key] || config[:api_key]
|
214
217
|
self.tags = construct_tags(opts[:tags]) | construct_tags(context[:tags])
|
215
218
|
|
216
|
-
self.url
|
217
|
-
self.action
|
218
|
-
self.component
|
219
|
-
self.params
|
220
|
-
self.session
|
221
|
-
self.cgi_data
|
222
|
-
self.details
|
219
|
+
self.url = opts[:url] || request_hash[:url] || nil
|
220
|
+
self.action = opts[:action] || request_hash[:action] || nil
|
221
|
+
self.component = opts[:controller] || opts[:component] || request_hash[:component] || nil
|
222
|
+
self.params = opts[:parameters] || opts[:params] || request_hash[:params] || {}
|
223
|
+
self.session = opts[:session] || request_hash[:session] || {}
|
224
|
+
self.cgi_data = opts[:cgi_data] || request_hash[:cgi_data] || {}
|
225
|
+
self.details = opts[:details] || {}
|
226
|
+
self.request_id = opts[:request_id] || nil
|
223
227
|
|
224
228
|
self.session = opts[:session][:data] if opts[:session] && opts[:session][:data]
|
225
229
|
|
@@ -261,6 +265,9 @@ module Honeybadger
|
|
261
265
|
stats: stats,
|
262
266
|
time: now,
|
263
267
|
pid: pid
|
268
|
+
},
|
269
|
+
correlation_context: {
|
270
|
+
request_id: s(request_id)
|
264
271
|
}
|
265
272
|
}
|
266
273
|
end
|
@@ -3,25 +3,48 @@ require 'honeybadger/util/sql'
|
|
3
3
|
|
4
4
|
module Honeybadger
|
5
5
|
class NotificationSubscriber
|
6
|
+
include Honeybadger::InstrumentationHelper
|
7
|
+
|
6
8
|
def start(name, id, payload)
|
7
|
-
|
9
|
+
payload[:_start_time] = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
8
10
|
end
|
9
11
|
|
10
12
|
def finish(name, id, payload)
|
11
|
-
|
12
|
-
|
13
|
+
finish_time = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
13
14
|
return unless process?(name, payload)
|
14
15
|
|
15
16
|
payload = {
|
16
17
|
instrumenter_id: id,
|
17
|
-
duration: ((
|
18
|
+
duration: ((finish_time - payload.delete(:_start_time)) * 1000).round(2)
|
18
19
|
}.merge(format_payload(payload).compact)
|
19
20
|
|
20
21
|
record(name, payload)
|
21
22
|
end
|
22
23
|
|
23
24
|
def record(name, payload)
|
24
|
-
Honeybadger.
|
25
|
+
if Honeybadger.config.load_plugin_insights_events?(:rails)
|
26
|
+
Honeybadger.event(name, payload)
|
27
|
+
end
|
28
|
+
|
29
|
+
if Honeybadger.config.load_plugin_insights_metrics?(:rails)
|
30
|
+
metric_source 'rails'
|
31
|
+
record_metrics(name, payload)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def record_metrics(name, payload)
|
36
|
+
case name
|
37
|
+
when 'sql.active_record'
|
38
|
+
gauge('duration.sql.active_record', value: payload[:duration], **payload.slice(:query))
|
39
|
+
when 'process_action.action_controller'
|
40
|
+
gauge('duration.process_action.action_controller', value: payload[:duration], **payload.slice(:method, :controller, :action, :format, :status))
|
41
|
+
gauge('db_runtime.process_action.action_controller', value: payload[:db_runtime], **payload.slice(:method, :controller, :action, :format, :status))
|
42
|
+
gauge('view_runtime.process_action.action_controller', value: payload[:view_runtime], **payload.slice(:method, :controller, :action, :format, :status))
|
43
|
+
when 'perform.active_job'
|
44
|
+
gauge('duration.perform.active_job', value: payload[:duration], **payload.slice(:job_class, :queue_name))
|
45
|
+
when /^cache_.*.active_support$/
|
46
|
+
gauge("duration.#{name}", value: payload[:duration], **payload.slice(:store, :key))
|
47
|
+
end
|
25
48
|
end
|
26
49
|
|
27
50
|
def process?(event, payload)
|
@@ -109,25 +132,22 @@ module Honeybadger
|
|
109
132
|
end
|
110
133
|
end
|
111
134
|
|
112
|
-
class
|
113
|
-
include Honeybadger::InstrumentationHelper
|
114
|
-
|
135
|
+
class ActionMailerSubscriber < NotificationSubscriber
|
115
136
|
def format_payload(payload)
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
137
|
+
# Don't include the mail object in the payload...
|
138
|
+
mail = payload.delete(:mail)
|
139
|
+
|
140
|
+
# ... but do include any attachment filenames
|
141
|
+
attachment_info = if mail&.attachments&.any?
|
142
|
+
{ attachments: mail.attachments.map { |a| { filename: a.filename } } }
|
143
|
+
else
|
144
|
+
{}
|
145
|
+
end
|
121
146
|
|
122
|
-
|
123
|
-
metric_source 'active_job'
|
124
|
-
histogram name, { bins: [30, 60, 120, 300, 1800, 3600, 21_600] }.merge(payload)
|
147
|
+
payload.merge(attachment_info)
|
125
148
|
end
|
126
149
|
end
|
127
150
|
|
128
|
-
class ActionMailerSubscriber < NotificationSubscriber
|
129
|
-
end
|
130
|
-
|
131
151
|
class ActiveStorageSubscriber < NotificationSubscriber
|
132
152
|
end
|
133
153
|
end
|
@@ -51,11 +51,10 @@ module Honeybadger
|
|
51
51
|
end
|
52
52
|
|
53
53
|
execution do
|
54
|
-
::ActiveJob::Base.set_callback(:perform, :around, &ActiveJob.method(:perform_around))
|
54
|
+
::ActiveJob::Base.set_callback(:perform, :around, &ActiveJob.method(:perform_around)) if Honeybadger.config[:'exceptions.enabled']
|
55
55
|
|
56
56
|
if config.load_plugin_insights?(:active_job)
|
57
57
|
::ActiveSupport::Notifications.subscribe(/(enqueue_at|enqueue|enqueue_retry|enqueue_all|perform|retry_stopped|discard)\.active_job/, Honeybadger::ActiveJobSubscriber.new)
|
58
|
-
::ActiveSupport::Notifications.subscribe('perform.active_job', Honeybadger::ActiveJobMetricsSubscriber.new)
|
59
58
|
end
|
60
59
|
end
|
61
60
|
end
|
@@ -10,17 +10,20 @@ module Honeybadger
|
|
10
10
|
execution do
|
11
11
|
singleton_class.include(Honeybadger::InstrumentationHelper)
|
12
12
|
|
13
|
-
::Autotuner.enabled = true
|
14
|
-
|
15
13
|
::Autotuner.reporter = proc do |report|
|
16
14
|
Honeybadger.event("report.autotuner", report: report.to_s)
|
17
15
|
end
|
18
16
|
|
19
|
-
metric_source 'autotuner'
|
20
|
-
|
21
17
|
::Autotuner.metrics_reporter = proc do |metrics|
|
22
|
-
|
23
|
-
|
18
|
+
if config.load_plugin_insights_events?(:autotuner)
|
19
|
+
Honeybadger.event('stats.autotuner', metrics)
|
20
|
+
end
|
21
|
+
|
22
|
+
if config.load_plugin_insights_metrics?(:autotuner)
|
23
|
+
metric_source 'autotuner'
|
24
|
+
metrics.each do |key, val|
|
25
|
+
gauge key, ->{ val }
|
26
|
+
end
|
24
27
|
end
|
25
28
|
end
|
26
29
|
end
|
@@ -6,25 +6,16 @@ module Honeybadger
|
|
6
6
|
requirement { defined?(::Karafka) && ::Karafka.respond_to?(:monitor) }
|
7
7
|
|
8
8
|
execution do
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
require 'honeybadger/karafka'
|
10
|
+
|
11
|
+
if Honeybadger.config[:'exceptions.enabled']
|
12
|
+
errors_listener = ::Honeybadger::Karafka::ErrorsListener.new
|
13
|
+
::Karafka.monitor.subscribe(errors_listener)
|
14
|
+
::Karafka.producer.monitor.subscribe(errors_listener) if ::Karafka.respond_to?(:producer)
|
12
15
|
end
|
13
16
|
|
14
17
|
if config.load_plugin_insights?(:karafka)
|
15
|
-
::Karafka.monitor.subscribe(
|
16
|
-
context = {
|
17
|
-
duration: event.payload[:time],
|
18
|
-
consumer: event.payload[:caller].class.to_s,
|
19
|
-
id: event.payload[:caller].id,
|
20
|
-
topic: event.payload[:caller].messages.metadata.topic,
|
21
|
-
messages_count: event.payload[:caller].messages.metadata.size,
|
22
|
-
processing_lag: event.payload[:caller].messages.metadata.processing_lag,
|
23
|
-
partition: event.payload[:caller].messages.metadata.partition
|
24
|
-
}
|
25
|
-
|
26
|
-
Honeybadger.event("consumer.consumed.karafka", context)
|
27
|
-
end
|
18
|
+
::Karafka.monitor.subscribe(::Honeybadger::Karafka::InsightsListener.new)
|
28
19
|
end
|
29
20
|
end
|
30
21
|
end
|
@@ -7,6 +7,12 @@ module Honeybadger
|
|
7
7
|
module Plugins
|
8
8
|
module Net
|
9
9
|
module HTTP
|
10
|
+
@@hb_config = ::Honeybadger.config
|
11
|
+
|
12
|
+
def self.set_hb_config(config)
|
13
|
+
@@hb_config = config
|
14
|
+
end
|
15
|
+
|
10
16
|
def request(request_data, body = nil, &block)
|
11
17
|
return super unless started?
|
12
18
|
return super if hb?
|
@@ -18,19 +24,26 @@ module Honeybadger
|
|
18
24
|
status: response_data.code.to_i
|
19
25
|
}.merge(parsed_uri_data(request_data))
|
20
26
|
|
21
|
-
|
27
|
+
if @@hb_config.load_plugin_insights_events?(:net_http)
|
28
|
+
Honeybadger.event('request.net_http', context)
|
29
|
+
end
|
30
|
+
|
31
|
+
if @@hb_config.load_plugin_insights_metrics?(:net_http)
|
32
|
+
context.delete(:url)
|
33
|
+
Honeybadger.gauge('duration.request', context.merge(metric_source: 'net_http'))
|
34
|
+
end
|
22
35
|
end[1] # return the response data only
|
23
36
|
end
|
24
37
|
|
25
38
|
def hb?
|
26
|
-
address.to_s[/#{
|
39
|
+
address.to_s[/#{@@hb_config[:'connection.host'].to_s}/]
|
27
40
|
end
|
28
41
|
|
29
42
|
def parsed_uri_data(request_data)
|
30
43
|
uri = request_data.uri || build_uri(request_data)
|
31
44
|
{}.tap do |uri_data|
|
32
45
|
uri_data[:host] = uri.host
|
33
|
-
uri_data[:url] = uri.to_s if
|
46
|
+
uri_data[:url] = uri.to_s if @@hb_config[:'net_http.insights.full_url']
|
34
47
|
end
|
35
48
|
end
|
36
49
|
|
@@ -43,6 +56,7 @@ module Honeybadger
|
|
43
56
|
requirement { config.load_plugin_insights?(:net_http) }
|
44
57
|
|
45
58
|
execution do
|
59
|
+
Honeybadger::Plugins::Net::HTTP.set_hb_config(config)
|
46
60
|
::Net::HTTP.send(:prepend, Honeybadger::Plugins::Net::HTTP)
|
47
61
|
end
|
48
62
|
end
|
@@ -64,7 +64,13 @@ module Honeybadger
|
|
64
64
|
::ActionDispatch::ShowExceptions.prepend(ExceptionsCatcher)
|
65
65
|
end
|
66
66
|
|
67
|
-
if defined?(::ActiveSupport::ErrorReporter) # Rails 7
|
67
|
+
if Honeybadger.config[:'exceptions.enabled'] && defined?(::ActiveSupport::ErrorReporter) # Rails 7
|
68
|
+
if defined?(::ActiveSupport::ExecutionContext)
|
69
|
+
::ActiveSupport::ExecutionContext.after_change do
|
70
|
+
Honeybadger.context(::ActiveSupport::ExecutionContext.to_h)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
68
74
|
::Rails.error.subscribe(ErrorSubscriber)
|
69
75
|
end
|
70
76
|
end
|