Skip to content

Commit 1762fc4

Browse files
authored
feat: add Rails.event subscriber (#734)
1 parent ff6ed11 commit 1762fc4

File tree

14 files changed

+226
-44
lines changed

14 files changed

+226
-44
lines changed

.standard.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
ruby_version: 3.0
1+
ruby_version: 3.4
22
fix: true
33
parallel: true

.tool-versions

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
ruby 3.5-dev
1+
ruby 3.4.5

lib/honeybadger/config.rb

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ def load!(framework: {}, env: ENV)
6666
self.env = Env.new(env).freeze
6767
load_config_from_disk { |yaml| self.yaml = yaml.freeze }
6868
detect_revision!
69+
process_deprecations!
6970
@loaded = true
7071
self
7172
end
@@ -301,24 +302,10 @@ def collection_interval(name)
301302
self[:"#{name}.insights.collection_interval"]
302303
end
303304

304-
def load_plugin_insights?(name)
305+
def load_plugin_insights?(name, feature: nil)
305306
return false unless insights_enabled?
306-
return true if self[:"#{name}.insights.enabled"].nil?
307-
!!self[:"#{name}.insights.enabled"]
308-
end
309-
310-
def load_plugin_insights_events?(name)
311-
return false unless insights_enabled?
312-
return false unless load_plugin_insights?(name)
313-
return true if self[:"#{name}.insights.events"].nil?
314-
!!self[:"#{name}.insights.events"]
315-
end
316-
317-
def load_plugin_insights_metrics?(name)
318-
return false unless insights_enabled?
319-
return false unless load_plugin_insights?(name)
320-
return true if self[:"#{name}.insights.metrics"].nil?
321-
!!self[:"#{name}.insights.metrics"]
307+
return false unless self[:"#{name}.insights.enabled"]
308+
feature.nil? || self[:"#{name}.insights.#{feature}"]
322309
end
323310

324311
def root_regexp
@@ -365,6 +352,42 @@ def detect_revision!
365352
set(:revision, Util::Revision.detect(self[:root]))
366353
end
367354

355+
# When an option includes the `deprecated` property, warn the logger with
356+
# the provided message (or a default message if `true`). If the
357+
# `deprecated_by` property is present, automatically rename the option,
358+
# removing the old key from the source.
359+
def process_deprecations!
360+
IVARS.each do |var|
361+
source = instance_variable_get(var)
362+
363+
# We don't need to update the source unless there are deprecated_by options.
364+
updated_source = nil
365+
366+
source.each_pair do |deprecated_key, value|
367+
next unless (deprecated = OPTIONS.dig(deprecated_key, :deprecated))
368+
deprecated_by = OPTIONS.dig(deprecated_key, :deprecated_by)
369+
370+
msg = if deprecated.is_a?(String)
371+
deprecated
372+
elsif deprecated_by
373+
"The `#{deprecated_key}` option is deprecated. Use `#{deprecated_by}` instead."
374+
else
375+
"The `#{deprecated_key}` option is deprecated and has no effect."
376+
end
377+
378+
warn("DEPRECATED: #{msg} config_source=#{var.to_s.delete_prefix("@")}")
379+
380+
if deprecated_by
381+
updated_source ||= source.dup
382+
updated_source[deprecated_by] = value unless updated_source.key?(deprecated_by)
383+
updated_source.delete(deprecated_key)
384+
end
385+
end
386+
387+
instance_variable_set(var, updated_source.freeze) if updated_source
388+
end
389+
end
390+
368391
def log_path
369392
return if log_stdout?
370393
return if !self[:"logging.path"]

lib/honeybadger/config/defaults.rb

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,11 @@ class Boolean; end
330330
default: 0,
331331
type: Integer
332332
},
333+
"active_job.insights.enabled": {
334+
description: "Enable automatic data collection for Active Job.",
335+
default: true,
336+
type: Boolean
337+
},
333338
"delayed_job.attempt_threshold": {
334339
description: "The number of attempts before notifications will be sent.",
335340
default: 0,
@@ -413,6 +418,18 @@ class Boolean; end
413418
"rails.insights.events": {
414419
description: "Enable automatic event capturing for Ruby on Rails.",
415420
default: true,
421+
type: Boolean,
422+
deprecated: true,
423+
deprecated_by: :"rails.insights.active_support_events"
424+
},
425+
"rails.insights.active_support_events": {
426+
description: "Enable automatic ActiveSupport::Notifications event capturing for Ruby on Rails.",
427+
default: true,
428+
type: Boolean
429+
},
430+
"rails.insights.structured_events": {
431+
description: "Enable capturing of custom Rails.event events in Rails 8.1 and later.",
432+
default: true,
416433
type: Boolean
417434
},
418435
"rails.insights.metrics": {
@@ -503,6 +520,11 @@ class Boolean; end
503520
default: 60,
504521
type: Integer
505522
},
523+
"puma.insights.enabled": {
524+
description: "Enable automatic data collection for Puma.",
525+
default: true,
526+
type: Boolean
527+
},
506528
"puma.insights.events": {
507529
description: "Enable automatic event capturing for Puma stats.",
508530
default: true,
@@ -518,6 +540,11 @@ class Boolean; end
518540
default: 1,
519541
type: Integer
520542
},
543+
"autotuner.insights.enabled": {
544+
description: "Enable automatic data collection for Autotuner.",
545+
default: true,
546+
type: Boolean
547+
},
521548
"autotuner.insights.events": {
522549
description: "Enable automatic event capturing for Autotuner stats.",
523550
default: true,

lib/honeybadger/karafka.rb

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,11 @@ def initialize
6969
#
7070
# @param event [Karafka::Core::Monitoring::Event]
7171
def on_statistics_emitted(event)
72-
if Honeybadger.config.load_plugin_insights_events?(:karafka)
72+
if Honeybadger.config.load_plugin_insights?(:karafka, feature: :events)
7373
Honeybadger.event("statistics_emitted.karafka", event.payload)
7474
end
7575

76-
return unless Honeybadger.config.load_plugin_insights_metrics?(:karafka)
76+
return unless Honeybadger.config.load_plugin_insights?(:karafka, feature: :metrics)
7777

7878
statistics = event[:statistics]
7979
consumer_group_id = event[:consumer_group_id]
@@ -126,11 +126,11 @@ def on_error_occurred(event)
126126
extra_tags.merge!(consumer_tags(event.payload[:caller]))
127127
end
128128

129-
if Honeybadger.config.load_plugin_insights_events?(:karafka)
129+
if Honeybadger.config.load_plugin_insights?(:karafka, feature: :events)
130130
Honeybadger.event("error.occurred.karafka", error: event[:error], **extra_tags)
131131
end
132132

133-
if Honeybadger.config.load_plugin_insights_metrics?(:karafka)
133+
if Honeybadger.config.load_plugin_insights?(:karafka, feature: :metrics)
134134
increment_counter("error_occurred", value: 1, **extra_tags)
135135
end
136136
end
@@ -144,7 +144,7 @@ def on_connection_listener_fetch_loop_received(event)
144144
consumer_group_id = event[:subscription_group].consumer_group.id
145145
extra_tags = {consumer_group: consumer_group_id}
146146

147-
if Honeybadger.config.load_plugin_insights_metrics?(:karafka)
147+
if Honeybadger.config.load_plugin_insights?(:karafka, feature: :metrics)
148148
histogram("listener_polling_time_taken", value: time_taken, **extra_tags)
149149
histogram("listener_polling_messages", value: messages_count, **extra_tags)
150150
end
@@ -160,7 +160,7 @@ def on_consumer_consumed(event)
160160

161161
tags = consumer_tags(consumer)
162162

163-
if Honeybadger.config.load_plugin_insights_events?(:karafka)
163+
if Honeybadger.config.load_plugin_insights?(:karafka, feature: :events)
164164
event_context = tags.merge({
165165
consumer: consumer.class.name,
166166
duration: event[:time],
@@ -171,7 +171,7 @@ def on_consumer_consumed(event)
171171
Honeybadger.event("consumer.consumed.karafka", event_context)
172172
end
173173

174-
if Honeybadger.config.load_plugin_insights_metrics?(:karafka)
174+
if Honeybadger.config.load_plugin_insights?(:karafka, feature: :metrics)
175175
increment_counter("consumer_messages", value: messages.count, **tags)
176176
increment_counter("consumer_batches", value: 1, **tags)
177177
gauge("consumer_offset", value: metadata.last_offset, **tags)
@@ -192,7 +192,7 @@ def on_consumer_consumed(event)
192192
#
193193
# @param event [Karafka::Core::Monitoring::Event]
194194
def on_consumer_#{after}(event)
195-
if Honeybadger.config.load_plugin_insights_metrics?(:karafka)
195+
if Honeybadger.config.load_plugin_insights?(:karafka, feature: :metrics)
196196
tags = consumer_tags(event.payload[:caller])
197197
increment_counter('consumer_#{name}', value: 1, **tags)
198198
end
@@ -205,7 +205,7 @@ def on_consumer_#{after}(event)
205205
def on_worker_process(event)
206206
jq_stats = event[:jobs_queue].statistics
207207

208-
if Honeybadger.config.load_plugin_insights_metrics?(:karafka)
208+
if Honeybadger.config.load_plugin_insights?(:karafka, feature: :metrics)
209209
gauge("worker_total_threads", value: ::Karafka::App.config.concurrency)
210210
histogram("worker_processing", value: jq_stats[:busy])
211211
histogram("worker_enqueued_jobs", value: jq_stats[:enqueued])
@@ -218,7 +218,7 @@ def on_worker_process(event)
218218
def on_worker_processed(event)
219219
jq_stats = event[:jobs_queue].statistics
220220

221-
if Honeybadger.config.load_plugin_insights_metrics?(:karafka)
221+
if Honeybadger.config.load_plugin_insights?(:karafka, feature: :metrics)
222222
histogram("worker_processing", value: jq_stats[:busy])
223223
end
224224
end

lib/honeybadger/notification_subscriber.rb

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ def finish(name, id, payload)
2222
end
2323

2424
def record(name, payload)
25-
if Honeybadger.config.load_plugin_insights_events?(:rails)
25+
if Honeybadger.config.load_plugin_insights?(:rails, feature: :active_support_events)
2626
Honeybadger.event(name, payload)
2727
end
2828

29-
if Honeybadger.config.load_plugin_insights_metrics?(:rails)
29+
if Honeybadger.config.load_plugin_insights?(:rails, feature: :metrics)
3030
metric_source "rails"
3131
record_metrics(name, payload)
3232
end
@@ -164,4 +164,12 @@ def format_payload(payload)
164164

165165
class ActiveStorageSubscriber < NotificationSubscriber
166166
end
167+
168+
class RailsEventSubscriber
169+
def emit(event)
170+
return unless Honeybadger.config.load_plugin_insights?(:rails, feature: :structured_events)
171+
172+
Honeybadger.event(event[:name], event.except(:name, :timestamp))
173+
end
174+
end
167175
end

lib/honeybadger/plugins/autotuner.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ module Autotuner
1515
end
1616

1717
::Autotuner.metrics_reporter = proc do |metrics|
18-
if config.load_plugin_insights_events?(:autotuner)
18+
if config.load_plugin_insights?(:autotuner, feature: :events)
1919
Honeybadger.event("stats.autotuner", metrics)
2020
end
2121

22-
if config.load_plugin_insights_metrics?(:autotuner)
22+
if config.load_plugin_insights?(:autotuner, feature: :metrics)
2323
metric_source "autotuner"
2424
metrics.each do |key, val|
2525
gauge key, -> { val }

lib/honeybadger/plugins/net_http.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@ def request(request_data, body = nil, &block)
2424
status: response_data.code.to_i
2525
}.merge(parsed_uri_data(request_data))
2626

27-
if @@hb_config.load_plugin_insights_events?(:net_http)
27+
if @@hb_config.load_plugin_insights?(:net_http, feature: :events)
2828
Honeybadger.event("request.net_http", context)
2929
end
3030

31-
if @@hb_config.load_plugin_insights_metrics?(:net_http)
31+
if @@hb_config.load_plugin_insights?(:net_http, feature: :metrics)
3232
context.delete(:url)
3333
Honeybadger.gauge("duration.request", context.merge(metric_source: "net_http"))
3434
end

lib/honeybadger/plugins/rails.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,11 @@ def self.source_ignored?(source)
9393
::ActiveSupport::Notifications.subscribe("sql.active_record", Honeybadger::ActiveRecordSubscriber.new)
9494
::ActiveSupport::Notifications.subscribe("process.action_mailer", Honeybadger::ActionMailerSubscriber.new)
9595
::ActiveSupport::Notifications.subscribe(/(service_upload|service_download)\.active_storage/, Honeybadger::ActiveStorageSubscriber.new)
96+
97+
# Subscribe to Rails.event for structured event logging (Rails 8.1+)
98+
if defined?(::Rails.event) && config.load_plugin_insights?(:rails, feature: :structured_events)
99+
::Rails.event.subscribe(Honeybadger::RailsEventSubscriber.new)
100+
end
96101
end
97102
end
98103
end

lib/honeybadger/plugins/sidekiq.rb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,11 @@ def call(worker, msg, queue, &block)
3939
ensure
4040
context[:duration] = duration
4141
context[:status] = status
42-
if Honeybadger.config.load_plugin_insights_events?(:sidekiq)
42+
if Honeybadger.config.load_plugin_insights?(:sidekiq, feature: :events)
4343
Honeybadger.event("perform.sidekiq", context)
4444
end
4545

46-
if Honeybadger.config.load_plugin_insights_metrics?(:sidekiq)
46+
if Honeybadger.config.load_plugin_insights?(:sidekiq, feature: :metrics)
4747
metric_source "sidekiq"
4848
gauge "perform", context.slice(:worker, :queue, :duration)
4949
end
@@ -60,7 +60,7 @@ def call(worker, msg, queue, _redis)
6060
queue: queue
6161
}
6262

63-
if Honeybadger.config.load_plugin_insights_events?(:sidekiq)
63+
if Honeybadger.config.load_plugin_insights?(:sidekiq, feature: :events)
6464
Honeybadger.event("enqueue.sidekiq", context)
6565
end
6666

@@ -225,11 +225,11 @@ def collect?
225225
if config.cluster_collection?(:sidekiq) && (leader_checker.nil? || leader_checker.collect?)
226226
stats = collect_sidekiq_stats.call
227227

228-
if Honeybadger.config.load_plugin_insights_events?(:sidekiq)
228+
if Honeybadger.config.load_plugin_insights?(:sidekiq, feature: :events)
229229
Honeybadger.event("stats.sidekiq", stats.except(:stats).merge(stats[:stats]))
230230
end
231231

232-
if Honeybadger.config.load_plugin_insights_metrics?(:sidekiq)
232+
if Honeybadger.config.load_plugin_insights?(:sidekiq, feature: :metrics)
233233
metric_source "sidekiq"
234234

235235
stats[:stats].each do |name, value|

0 commit comments

Comments
 (0)