honeybadger 5.10.2 → 5.11.1

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.
@@ -1,3 +1,4 @@
1
+ require 'honeybadger/instrumentation_helper'
1
2
  require 'honeybadger/plugin'
2
3
  require 'honeybadger/ruby'
3
4
 
@@ -11,7 +12,58 @@ module Honeybadger
11
12
  end
12
13
  end
13
14
 
14
- Plugin.register do
15
+ class ServerMiddlewareInstrumentation
16
+ include Honeybadger::InstrumentationHelper
17
+
18
+ def call(worker, msg, queue, &block)
19
+ if msg["wrapped"]
20
+ context = {
21
+ jid: msg["jid"],
22
+ worker: msg["wrapped"],
23
+ queue: queue
24
+ }
25
+ else
26
+ context = {
27
+ jid: msg["jid"],
28
+ worker: msg["class"],
29
+ queue: queue
30
+ }
31
+ end
32
+
33
+ begin
34
+ duration = Honeybadger.instrumentation.monotonic_timer { block.call }[0]
35
+ status = 'success'
36
+ rescue Exception => e
37
+ status = 'failure'
38
+ raise
39
+ ensure
40
+ context.merge!(duration: duration, status: status)
41
+ Honeybadger.event('perform.sidekiq', context)
42
+
43
+ metric_source 'sidekiq'
44
+ histogram 'perform', { bins: [30, 60, 120, 300, 1800, 3600, 21_600] }.merge(context.slice(:worker, :queue, :duration))
45
+ end
46
+ end
47
+ end
48
+
49
+ class ClientMiddlewareInstrumentation
50
+ include Honeybadger::InstrumentationHelper
51
+
52
+ def call(worker, msg, queue, _redis)
53
+ context = {
54
+ worker: msg["wrapped"] || msg["class"],
55
+ queue: queue
56
+ }
57
+
58
+ Honeybadger.event('enqueue.sidekiq', context)
59
+
60
+ yield
61
+ end
62
+ end
63
+
64
+ Plugin.register :sidekiq do
65
+ leader_checker = nil
66
+
15
67
  requirement { defined?(::Sidekiq) }
16
68
 
17
69
  execution do
@@ -71,6 +123,81 @@ module Honeybadger
71
123
  }
72
124
  end
73
125
  end
126
+
127
+ if config.load_plugin_insights?(:sidekiq)
128
+ require "sidekiq"
129
+ require "sidekiq/api"
130
+ require "sidekiq/component"
131
+
132
+ class SidekiqClusterCollectionChecker
133
+ include ::Sidekiq::Component
134
+ def initialize(config)
135
+ @config = config
136
+ end
137
+
138
+ def collect?
139
+ return true unless defined?(::Sidekiq::Enterprise)
140
+ leader?
141
+ end
142
+ end
143
+
144
+ ::Sidekiq.configure_server do |config|
145
+ config.server_middleware { |chain| chain.add(ServerMiddlewareInstrumentation) }
146
+ config.client_middleware { |chain| chain.add(ClientMiddlewareInstrumentation) }
147
+ config.on(:startup) do
148
+ leader_checker = SidekiqClusterCollectionChecker.new(config)
149
+ end
150
+ end
151
+
152
+ ::Sidekiq.configure_client do |config|
153
+ config.client_middleware { |chain| chain.add(ClientMiddlewareInstrumentation) }
154
+ end
155
+ end
156
+ end
157
+
158
+ collect do
159
+ if config.cluster_collection?(:sidekiq) && (leader_checker.nil? || leader_checker.collect?)
160
+ metric_source 'sidekiq'
161
+
162
+ stats = ::Sidekiq::Stats.new
163
+
164
+ gauge 'active_workers', ->{ stats.workers_size }
165
+ gauge 'active_processes', ->{ stats.processes_size }
166
+ gauge 'jobs_processed', ->{ stats.processed }
167
+ gauge 'jobs_failed', ->{ stats.failed }
168
+ gauge 'jobs_scheduled', ->{ stats.scheduled_size }
169
+ gauge 'jobs_enqueued', ->{ stats.enqueued }
170
+ gauge 'jobs_dead', ->{ stats.dead_size }
171
+ gauge 'jobs_retry', ->{ stats.retry_size }
172
+
173
+ ::Sidekiq::Queue.all.each do |queue|
174
+ gauge 'queue_latency', { queue: queue.name }, ->{ (queue.latency * 1000).ceil }
175
+ gauge 'queue_depth', { queue: queue.name }, ->{ queue.size }
176
+ end
177
+
178
+ Hash.new(0).tap do |busy_counts|
179
+ ::Sidekiq::Workers.new.each do |_pid, _tid, work|
180
+ payload = work.respond_to?(:payload) ? work.payload : work["payload"]
181
+ payload = JSON.parse(payload) if payload.is_a?(String)
182
+ busy_counts[payload["queue"]] += 1
183
+ end
184
+ end.each do |queue_name, busy_count|
185
+ gauge 'queue_busy', { queue: queue_name }, ->{ busy_count }
186
+ end
187
+
188
+ processes = ::Sidekiq::ProcessSet.new.to_enum(:each).to_a
189
+ gauge 'capacity', ->{ processes.map { |process| process["concurrency"] }.sum }
190
+
191
+ process_utilizations = processes.map do |process|
192
+ next unless process["concurrency"].to_f > 0
193
+ process["busy"] / process["concurrency"].to_f
194
+ end.compact
195
+
196
+ if process_utilizations.any?
197
+ utilization = process_utilizations.sum / process_utilizations.length.to_f
198
+ gauge 'utilization', ->{ utilization }
199
+ end
200
+ end
74
201
  end
75
202
  end
76
203
  end
@@ -0,0 +1,27 @@
1
+ module Honeybadger
2
+ module Plugins
3
+ module SolidQueue
4
+ Plugin.register :solid_queue do
5
+ requirement { defined?(::SolidQueue) }
6
+
7
+ collect do
8
+ if config.cluster_collection?(:solid_queue)
9
+ metric_source 'solid_queue'
10
+
11
+ gauge 'jobs_in_progress', ->{ ::SolidQueue::ClaimedExecution.count }
12
+ gauge 'jobs_blocked', ->{ ::SolidQueue::BlockedExecution.count }
13
+ gauge 'jobs_failed', ->{ ::SolidQueue::FailedExecution.count }
14
+ gauge 'jobs_scheduled', ->{ ::SolidQueue::ScheduledExecution.count }
15
+ gauge 'jobs_processed', ->{ ::SolidQueue::Job.where.not(finished_at: nil).count }
16
+ gauge 'active_workers', ->{ ::SolidQueue::Process.where(kind: "Worker").count }
17
+ gauge 'active_dispatchers', ->{ ::SolidQueue::Process.where(kind: "Dispatcher").count }
18
+
19
+ ::SolidQueue::Queue.all.each do |queue|
20
+ gauge 'queue_depth', { queue: queue.name }, ->{ queue.size }
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,16 @@
1
+ require 'honeybadger/util/stats'
2
+ require 'honeybadger/plugin'
3
+
4
+ module Honeybadger
5
+ module Plugins
6
+ module System
7
+ Plugin.register :system do
8
+ requirement { Util::Stats::HAS_MEM || Util::Stats::HAS_LOAD }
9
+
10
+ collect do
11
+ Honeybadger.event('report.system', Util::Stats.all)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,32 @@
1
+ module Honeybadger
2
+ class Registry
3
+ def initialize
4
+ @mutex = Mutex.new
5
+ @metrics = Hash.new
6
+ end
7
+
8
+ def register(metric)
9
+ @mutex.synchronize do
10
+ @metrics[metric.signature] = metric
11
+ end
12
+ end
13
+
14
+ def get(metric_type, name, attributes)
15
+ @mutex.synchronize do
16
+ @metrics[Honeybadger::Metric.signature(metric_type, name, attributes)]
17
+ end
18
+ end
19
+
20
+ def flush
21
+ @mutex.synchronize do
22
+ @metrics = Hash.new
23
+ end
24
+ end
25
+
26
+ def metrics
27
+ @mutex.synchronize do
28
+ @metrics.values
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,28 @@
1
+ module Honeybadger
2
+ class RegistryExecution
3
+ def initialize(registry, config, options)
4
+ @registry = registry
5
+ @config = config
6
+ @options = options
7
+ @interval = config[:'insights.registry_flush_interval'] || options.fetch(:interval, 60)
8
+ @end_time = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC) + @interval
9
+ end
10
+
11
+ def tick
12
+ @end_time - ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
13
+ end
14
+
15
+ def reset
16
+ @end_time = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC) + @interval
17
+ @registry.flush
18
+ end
19
+
20
+ def call
21
+ @registry.metrics.each do |metric|
22
+ metric.event_payloads.each do |payload|
23
+ Honeybadger.event(payload.merge(interval: @interval))
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -39,6 +39,14 @@ module Honeybadger
39
39
  def_delegator :'Honeybadger::Agent.instance', :clear!
40
40
  def_delegator :'Honeybadger::Agent.instance', :track_deployment
41
41
  def_delegator :'Honeybadger::Agent.instance', :event
42
+ def_delegator :'Honeybadger::Agent.instance', :collect
43
+ def_delegator :'Honeybadger::Agent.instance', :registry
44
+ def_delegator :'Honeybadger::Agent.instance', :instrumentation
45
+ def_delegator :'Honeybadger::Agent.instance', :time
46
+ def_delegator :'Honeybadger::Agent.instance', :histogram
47
+ def_delegator :'Honeybadger::Agent.instance', :gauge
48
+ def_delegator :'Honeybadger::Agent.instance', :increment_counter
49
+ def_delegator :'Honeybadger::Agent.instance', :decrement_counter
42
50
 
43
51
  # @!macro [attach] def_delegator
44
52
  # @!method $2(...)
@@ -0,0 +1,6 @@
1
+ require 'honeybadger/gauge'
2
+
3
+ module Honeybadger
4
+ class Timer < Gauge
5
+ end
6
+ end
@@ -1,4 +1,4 @@
1
1
  module Honeybadger
2
2
  # The current String Honeybadger version.
3
- VERSION = '5.10.2'.freeze
3
+ VERSION = '5.11.1'.freeze
4
4
  end
@@ -0,0 +1,43 @@
1
+ require 'honeybadger/instrumentation_helper'
2
+
3
+ module Honeybadger
4
+ class PumaPlugin
5
+ include Honeybadger::InstrumentationHelper
6
+
7
+ STATS_KEYS = %i(pool_capacity max_threads requests_count backlog running).freeze
8
+
9
+ ::Puma::Plugin.create do
10
+ def start(launcher)
11
+ puma_plugin = ::Honeybadger::PumaPlugin.new
12
+ in_background do
13
+ loop do
14
+ puma_plugin.record
15
+ sleep 1
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ def record
22
+ metric_source 'puma'
23
+
24
+ stats = ::Puma.stats rescue {}
25
+ stats = stats.is_a?(Hash) ? stats : JSON.parse(stats, symbolize_names: true)
26
+
27
+ if stats[:worker_status].is_a?(Array)
28
+ stats[:worker_status].each do |worker_data|
29
+ context = { worker: worker_data[:index] }
30
+ record_puma_stats(worker_data[:last_status], context)
31
+ end
32
+ else
33
+ record_puma_stats(stats)
34
+ end
35
+ end
36
+
37
+ def record_puma_stats(stats, context={})
38
+ STATS_KEYS.each do |stat|
39
+ gauge stat, context, ->{ stats[stat] } if stats[stat]
40
+ end
41
+ end
42
+ end
43
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: honeybadger
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.10.2
4
+ version: 5.11.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Honeybadger Industries LLC
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-05-24 00:00:00.000000000 Z
11
+ date: 2024-06-07 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Make managing application errors a more pleasant experience.
14
14
  email:
@@ -55,16 +55,25 @@ files:
55
55
  - lib/honeybadger/const.rb
56
56
  - lib/honeybadger/context_manager.rb
57
57
  - lib/honeybadger/conversions.rb
58
+ - lib/honeybadger/counter.rb
58
59
  - lib/honeybadger/events_worker.rb
60
+ - lib/honeybadger/gauge.rb
61
+ - lib/honeybadger/histogram.rb
59
62
  - lib/honeybadger/init/hanami.rb
60
63
  - lib/honeybadger/init/rails.rb
61
64
  - lib/honeybadger/init/rake.rb
62
65
  - lib/honeybadger/init/ruby.rb
63
66
  - lib/honeybadger/init/sinatra.rb
67
+ - lib/honeybadger/instrumentation.rb
68
+ - lib/honeybadger/instrumentation_helper.rb
64
69
  - lib/honeybadger/logging.rb
70
+ - lib/honeybadger/metric.rb
71
+ - lib/honeybadger/metrics_worker.rb
65
72
  - lib/honeybadger/notice.rb
73
+ - lib/honeybadger/notification_subscriber.rb
66
74
  - lib/honeybadger/plugin.rb
67
75
  - lib/honeybadger/plugins/active_job.rb
76
+ - lib/honeybadger/plugins/autotuner.rb
68
77
  - lib/honeybadger/plugins/breadcrumbs.rb
69
78
  - lib/honeybadger/plugins/delayed_job.rb
70
79
  - lib/honeybadger/plugins/delayed_job/plugin.rb
@@ -72,21 +81,27 @@ files:
72
81
  - lib/honeybadger/plugins/karafka.rb
73
82
  - lib/honeybadger/plugins/lambda.rb
74
83
  - lib/honeybadger/plugins/local_variables.rb
84
+ - lib/honeybadger/plugins/net_http.rb
75
85
  - lib/honeybadger/plugins/passenger.rb
76
86
  - lib/honeybadger/plugins/rails.rb
77
87
  - lib/honeybadger/plugins/resque.rb
78
88
  - lib/honeybadger/plugins/shoryuken.rb
79
89
  - lib/honeybadger/plugins/sidekiq.rb
90
+ - lib/honeybadger/plugins/solid_queue.rb
80
91
  - lib/honeybadger/plugins/sucker_punch.rb
92
+ - lib/honeybadger/plugins/system.rb
81
93
  - lib/honeybadger/plugins/thor.rb
82
94
  - lib/honeybadger/plugins/warden.rb
83
95
  - lib/honeybadger/rack/error_notifier.rb
84
96
  - lib/honeybadger/rack/user_feedback.rb
85
97
  - lib/honeybadger/rack/user_informer.rb
98
+ - lib/honeybadger/registry.rb
99
+ - lib/honeybadger/registry_execution.rb
86
100
  - lib/honeybadger/ruby.rb
87
101
  - lib/honeybadger/singleton.rb
88
102
  - lib/honeybadger/tasks.rb
89
103
  - lib/honeybadger/templates/feedback_form.erb
104
+ - lib/honeybadger/timer.rb
90
105
  - lib/honeybadger/util/http.rb
91
106
  - lib/honeybadger/util/lambda.rb
92
107
  - lib/honeybadger/util/request_hash.rb
@@ -97,6 +112,7 @@ files:
97
112
  - lib/honeybadger/util/stats.rb
98
113
  - lib/honeybadger/version.rb
99
114
  - lib/honeybadger/worker.rb
115
+ - lib/puma/plugin/honeybadger.rb
100
116
  - resources/ca-bundle.crt
101
117
  - vendor/capistrano-honeybadger/lib/capistrano/honeybadger.rb
102
118
  - vendor/capistrano-honeybadger/lib/capistrano/tasks/deploy.cap