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
@@ -38,10 +38,14 @@ module Honeybadger
|
|
38
38
|
raise
|
39
39
|
ensure
|
40
40
|
context.merge!(duration: duration, status: status)
|
41
|
-
Honeybadger.
|
41
|
+
if Honeybadger.config.load_plugin_insights_events?(:sidekiq)
|
42
|
+
Honeybadger.event('perform.sidekiq', context)
|
43
|
+
end
|
42
44
|
|
43
|
-
|
44
|
-
|
45
|
+
if Honeybadger.config.load_plugin_insights_metrics?(:sidekiq)
|
46
|
+
metric_source 'sidekiq'
|
47
|
+
gauge 'perform', context.slice(:worker, :queue, :duration)
|
48
|
+
end
|
45
49
|
end
|
46
50
|
end
|
47
51
|
end
|
@@ -55,7 +59,9 @@ module Honeybadger
|
|
55
59
|
queue: queue
|
56
60
|
}
|
57
61
|
|
58
|
-
Honeybadger.
|
62
|
+
if Honeybadger.config.load_plugin_insights_events?(:sidekiq)
|
63
|
+
Honeybadger.event('enqueue.sidekiq', context)
|
64
|
+
end
|
59
65
|
|
60
66
|
yield
|
61
67
|
end
|
@@ -67,60 +73,62 @@ module Honeybadger
|
|
67
73
|
requirement { defined?(::Sidekiq) }
|
68
74
|
|
69
75
|
execution do
|
70
|
-
|
71
|
-
|
72
|
-
|
76
|
+
if Honeybadger.config[:'exceptions.enabled']
|
77
|
+
::Sidekiq.configure_server do |sidekiq|
|
78
|
+
sidekiq.server_middleware do |chain|
|
79
|
+
chain.prepend Middleware
|
80
|
+
end
|
73
81
|
end
|
74
|
-
end
|
75
82
|
|
76
|
-
|
77
|
-
|
83
|
+
if defined?(::Sidekiq::VERSION) && ::Sidekiq::VERSION > '3'
|
84
|
+
::Sidekiq.configure_server do |sidekiq|
|
78
85
|
|
79
|
-
|
80
|
-
|
86
|
+
sidekiq_default_configuration = (::Sidekiq::VERSION > '7') ?
|
87
|
+
::Sidekiq.default_configuration : Class.new
|
81
88
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
+
sidekiq.error_handlers << lambda { |ex, sidekiq_params, sidekiq_config = sidekiq_default_configuration|
|
90
|
+
params = sidekiq_params.dup
|
91
|
+
if defined?(::Sidekiq::Config)
|
92
|
+
if params[:_config].is_a?(::Sidekiq::Config) # Sidekiq > 6 and < 7.1.5
|
93
|
+
params[:_config] = params[:_config].instance_variable_get(:@options)
|
94
|
+
else # Sidekiq >= 7.1.5
|
95
|
+
params[:_config] = sidekiq_config.instance_variable_get(:@options)
|
96
|
+
end
|
89
97
|
end
|
90
|
-
end
|
91
98
|
|
92
|
-
|
99
|
+
job = params[:job] || params
|
93
100
|
|
94
|
-
|
101
|
+
job_retry = job['retry'.freeze]
|
95
102
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
103
|
+
if (threshold = config[:'sidekiq.attempt_threshold'].to_i) > 0 && job_retry
|
104
|
+
# We calculate the job attempts to determine the need to
|
105
|
+
# skip. Sidekiq's first job execution will have nil for the
|
106
|
+
# 'retry_count' job key. The first retry will have 0 set for
|
107
|
+
# the 'retry_count' key, incrementing on each execution
|
108
|
+
# afterwards.
|
109
|
+
retry_count = job['retry_count'.freeze]
|
110
|
+
attempt = retry_count ? retry_count + 1 : 0
|
104
111
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
112
|
+
max_retries = (::Sidekiq::VERSION > '7') ?
|
113
|
+
::Sidekiq.default_configuration[:max_retries] : sidekiq.options[:max_retries]
|
114
|
+
# Ensure we account for modified max_retries setting
|
115
|
+
default_max_retry_attempts = defined?(::Sidekiq::JobRetry::DEFAULT_MAX_RETRY_ATTEMPTS) ? ::Sidekiq::JobRetry::DEFAULT_MAX_RETRY_ATTEMPTS : 25
|
116
|
+
retry_limit = job_retry == true ? (max_retries || default_max_retry_attempts) : job_retry.to_i
|
110
117
|
|
111
|
-
|
118
|
+
limit = [retry_limit, threshold].min
|
112
119
|
|
113
|
-
|
114
|
-
|
120
|
+
return if attempt < limit
|
121
|
+
end
|
115
122
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
123
|
+
opts = { parameters: params }
|
124
|
+
if config[:'sidekiq.use_component']
|
125
|
+
opts[:component] = job['wrapped'.freeze] || job['class'.freeze]
|
126
|
+
opts[:action] = 'perform' if opts[:component]
|
127
|
+
end
|
121
128
|
|
122
|
-
|
123
|
-
|
129
|
+
Honeybadger.notify(ex, opts)
|
130
|
+
}
|
131
|
+
end
|
124
132
|
end
|
125
133
|
end
|
126
134
|
|
@@ -161,47 +169,67 @@ module Honeybadger
|
|
161
169
|
end
|
162
170
|
end
|
163
171
|
|
172
|
+
collect_sidekiq_stats = -> do
|
173
|
+
stats = ::Sidekiq::Stats.new
|
174
|
+
data = stats.as_json
|
175
|
+
data[:queues] = {}
|
176
|
+
|
177
|
+
::Sidekiq::Queue.all.each do |queue|
|
178
|
+
data[:queues][queue.name] ||= {}
|
179
|
+
data[:queues][queue.name][:latency] = (queue.latency * 1000).ceil
|
180
|
+
data[:queues][queue.name][:depth] = queue.size
|
181
|
+
end
|
182
|
+
|
183
|
+
Hash.new(0).tap do |busy_counts|
|
184
|
+
::Sidekiq::Workers.new.each do |_pid, _tid, work|
|
185
|
+
payload = work.respond_to?(:payload) ? work.payload : work["payload"]
|
186
|
+
payload = JSON.parse(payload) if payload.is_a?(String)
|
187
|
+
busy_counts[payload["queue"]] += 1
|
188
|
+
end
|
189
|
+
end.each do |queue_name, busy_count|
|
190
|
+
data[:queues][queue_name] ||= {}
|
191
|
+
data[:queues][queue_name][:busy] = busy_count
|
192
|
+
end
|
193
|
+
|
194
|
+
processes = ::Sidekiq::ProcessSet.new.to_enum(:each).to_a
|
195
|
+
data[:capacity] = processes.map { |process| process["concurrency"] }.sum
|
196
|
+
|
197
|
+
process_utilizations = processes.map do |process|
|
198
|
+
next unless process["concurrency"].to_f > 0
|
199
|
+
process["busy"] / process["concurrency"].to_f
|
200
|
+
end.compact
|
201
|
+
|
202
|
+
if process_utilizations.any?
|
203
|
+
utilization = process_utilizations.sum / process_utilizations.length.to_f
|
204
|
+
data[:utilization] = utilization
|
205
|
+
end
|
206
|
+
|
207
|
+
data
|
208
|
+
end
|
209
|
+
|
164
210
|
collect do
|
165
211
|
if config.cluster_collection?(:sidekiq) && (leader_checker.nil? || leader_checker.collect?)
|
166
|
-
|
167
|
-
|
168
|
-
stats = ::Sidekiq::Stats.new
|
169
|
-
|
170
|
-
gauge 'active_workers', ->{ stats.workers_size }
|
171
|
-
gauge 'active_processes', ->{ stats.processes_size }
|
172
|
-
gauge 'jobs_processed', ->{ stats.processed }
|
173
|
-
gauge 'jobs_failed', ->{ stats.failed }
|
174
|
-
gauge 'jobs_scheduled', ->{ stats.scheduled_size }
|
175
|
-
gauge 'jobs_enqueued', ->{ stats.enqueued }
|
176
|
-
gauge 'jobs_dead', ->{ stats.dead_size }
|
177
|
-
gauge 'jobs_retry', ->{ stats.retry_size }
|
178
|
-
|
179
|
-
::Sidekiq::Queue.all.each do |queue|
|
180
|
-
gauge 'queue_latency', { queue: queue.name }, ->{ (queue.latency * 1000).ceil }
|
181
|
-
gauge 'queue_depth', { queue: queue.name }, ->{ queue.size }
|
182
|
-
end
|
212
|
+
stats = collect_sidekiq_stats.call
|
183
213
|
|
184
|
-
|
185
|
-
|
186
|
-
payload = work.respond_to?(:payload) ? work.payload : work["payload"]
|
187
|
-
payload = JSON.parse(payload) if payload.is_a?(String)
|
188
|
-
busy_counts[payload["queue"]] += 1
|
189
|
-
end
|
190
|
-
end.each do |queue_name, busy_count|
|
191
|
-
gauge 'queue_busy', { queue: queue_name }, ->{ busy_count }
|
214
|
+
if Honeybadger.config.load_plugin_insights_events?(:sidekiq)
|
215
|
+
Honeybadger.event('stats.sidekiq', stats.except('stats').merge(stats['stats']))
|
192
216
|
end
|
193
217
|
|
194
|
-
|
195
|
-
|
218
|
+
if Honeybadger.config.load_plugin_insights_metrics?(:sidekiq)
|
219
|
+
metric_source 'sidekiq'
|
196
220
|
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
221
|
+
stats['stats'].each do |name, value|
|
222
|
+
gauge name, value: value
|
223
|
+
end
|
224
|
+
|
225
|
+
stats[:queues].each do |queue_name, data|
|
226
|
+
data.each do |key, value|
|
227
|
+
gauge "queue_#{key}", queue: queue_name, value: value
|
228
|
+
end
|
229
|
+
end
|
201
230
|
|
202
|
-
|
203
|
-
utilization
|
204
|
-
gauge 'utilization', ->{ utilization }
|
231
|
+
gauge 'capacity', value: stats[:capacity] if stats[:capacity]
|
232
|
+
gauge 'utilization', value: stats[:utilization] if stats[:utilization]
|
205
233
|
end
|
206
234
|
end
|
207
235
|
end
|
@@ -4,20 +4,46 @@ module Honeybadger
|
|
4
4
|
Plugin.register :solid_queue do
|
5
5
|
requirement { config.load_plugin_insights?(:solid_queue) && defined?(::SolidQueue) }
|
6
6
|
|
7
|
+
collect_solid_queue_stats = -> do
|
8
|
+
data = {}
|
9
|
+
data[:stats] = {
|
10
|
+
jobs_in_progress: ::SolidQueue::ClaimedExecution.count,
|
11
|
+
jobs_blocked: ::SolidQueue::BlockedExecution.count,
|
12
|
+
jobs_failed: ::SolidQueue::FailedExecution.count,
|
13
|
+
jobs_scheduled: ::SolidQueue::ScheduledExecution.count,
|
14
|
+
jobs_processed: ::SolidQueue::Job.where.not(finished_at: nil).count,
|
15
|
+
active_workers: ::SolidQueue::Process.where(kind: "Worker").count,
|
16
|
+
active_dispatchers: ::SolidQueue::Process.where(kind: "Dispatcher").count
|
17
|
+
}
|
18
|
+
|
19
|
+
data[:queues] = {}
|
20
|
+
|
21
|
+
::SolidQueue::Queue.all.each do |queue|
|
22
|
+
data[:queues][queue.name] = { depth: queue.size }
|
23
|
+
end
|
24
|
+
|
25
|
+
data
|
26
|
+
end
|
27
|
+
|
7
28
|
collect do
|
29
|
+
stats = collect_solid_queue_stats.call
|
30
|
+
|
8
31
|
if config.cluster_collection?(:solid_queue)
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
32
|
+
if Honeybadger.config.load_plugin_insights_events?(:solid_queue)
|
33
|
+
Honeybadger.event('stats.solid_queue', stats.except(:stats).merge(stats[:stats]))
|
34
|
+
end
|
35
|
+
|
36
|
+
if Honeybadger.config.load_plugin_insights_metrics?(:solid_queue)
|
37
|
+
metric_source 'solid_queue'
|
38
|
+
stats[:stats].each do |stat_name, value|
|
39
|
+
gauge stat_name, value: value
|
40
|
+
end
|
41
|
+
|
42
|
+
stats[:queues].each do |queue_name, data|
|
43
|
+
data.each do |key, value|
|
44
|
+
gauge "queue_#{key}", queue: queue_name, value: value
|
45
|
+
end
|
46
|
+
end
|
21
47
|
end
|
22
48
|
end
|
23
49
|
end
|
@@ -6,6 +6,7 @@ module Honeybadger
|
|
6
6
|
requirement { defined?(::SuckerPunch) }
|
7
7
|
|
8
8
|
execution do
|
9
|
+
return unless Honeybadger.config[:'exceptions.enabled']
|
9
10
|
if SuckerPunch.respond_to?(:exception_handler=) # >= v2
|
10
11
|
SuckerPunch.exception_handler = ->(ex, klass, args) { Honeybadger.notify(ex, { :component => klass, :parameters => args }) }
|
11
12
|
else
|
data/lib/honeybadger/version.rb
CHANGED
@@ -12,7 +12,7 @@ module Honeybadger
|
|
12
12
|
in_background do
|
13
13
|
loop do
|
14
14
|
puma_plugin.record
|
15
|
-
sleep 1
|
15
|
+
sleep [::Honeybadger.config.collection_interval(:puma).to_i, 1].max
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|
@@ -35,8 +35,14 @@ module Honeybadger
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def record_puma_stats(stats, context={})
|
38
|
-
|
39
|
-
|
38
|
+
if Honeybadger.config.load_plugin_insights_events?(:puma)
|
39
|
+
Honeybadger.event('stats.puma', context.merge(stats))
|
40
|
+
end
|
41
|
+
|
42
|
+
if Honeybadger.config.load_plugin_insights_metrics?(:puma)
|
43
|
+
STATS_KEYS.each do |stat|
|
44
|
+
gauge stat, context, ->{ stats[stat] } if stats[stat]
|
45
|
+
end
|
40
46
|
end
|
41
47
|
end
|
42
48
|
end
|
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: honeybadger
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.26.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Honeybadger Industries LLC
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 2025-02-18 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: logger
|
@@ -24,6 +23,20 @@ dependencies:
|
|
24
23
|
- - ">="
|
25
24
|
- !ruby/object:Gem::Version
|
26
25
|
version: '0'
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: ostruct
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
27
40
|
description: Make managing application errors a more pleasant experience.
|
28
41
|
email:
|
29
42
|
- support@honeybadger.io
|
@@ -81,6 +94,7 @@ files:
|
|
81
94
|
- lib/honeybadger/init/sinatra.rb
|
82
95
|
- lib/honeybadger/instrumentation.rb
|
83
96
|
- lib/honeybadger/instrumentation_helper.rb
|
97
|
+
- lib/honeybadger/karafka.rb
|
84
98
|
- lib/honeybadger/logging.rb
|
85
99
|
- lib/honeybadger/metric.rb
|
86
100
|
- lib/honeybadger/metrics_worker.rb
|
@@ -175,7 +189,6 @@ metadata:
|
|
175
189
|
documentation_uri: https://docs.honeybadger.io/lib/ruby/
|
176
190
|
homepage_uri: https://www.honeybadger.io/for/ruby/
|
177
191
|
source_code_uri: https://github.com/honeybadger-io/honeybadger-ruby
|
178
|
-
post_install_message:
|
179
192
|
rdoc_options:
|
180
193
|
- "--markup=tomdoc"
|
181
194
|
- "--main=README.md"
|
@@ -193,8 +206,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
193
206
|
- !ruby/object:Gem::Version
|
194
207
|
version: '0'
|
195
208
|
requirements: []
|
196
|
-
rubygems_version: 3.
|
197
|
-
signing_key:
|
209
|
+
rubygems_version: 3.7.0.dev
|
198
210
|
specification_version: 4
|
199
211
|
summary: Error reports you can be happy about.
|
200
212
|
test_files: []
|