honeybadger 5.10.2 → 5.11.0

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