rails_error_dashboard 0.4.2 → 0.5.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e514a83af22b8b3938befb45429a46617ee0f547a6831d98cdb44e435f3e3a1c
4
- data.tar.gz: 8329f6c148cfdd9c2d5fb9cd87e89e77f93c7a45beb55ec278218bb5f12e2dde
3
+ metadata.gz: af41ac0baefaf436b68c2db7ac1598a15f409cb76efbbf2eb8fb2daa9ceaab92
4
+ data.tar.gz: 22073a8675b855c06622dc34ae649608af129f57f5c391c9562c20bd95db53ec
5
5
  SHA512:
6
- metadata.gz: 8bfe23263da657c250f8c982ec9271e1ad6158f28041db817a3fc9ee529a0dbdadc8045f30f7633a771265ae0592cc2e0903af215b63f447f449ed0dc478039c
7
- data.tar.gz: 889dac2f878d6d31afa91c4efbd20be4432452046bcb5a1071f507e23b41d7b5bcdb07ae67468bf3f678917084dc5149492fa01733276918fc52c4daf6f0a766
6
+ metadata.gz: badaacf9fb78a5d93ee3d545d93877cc59c8685f8800567ad6f84979cec365baebd3f3193b905bbf73b67f99c70308c2480043bfb78c38f0a1b149637f1595c4
7
+ data.tar.gz: 548db884ddfcb084293083c3e8b787bdc50d0fd2128b8f68bdc315f578199ce9c36ef805a038657d437864055ee45e9f5bfc41ef6386be6e5b3c750be40ed238
data/README.md CHANGED
@@ -116,7 +116,7 @@ Requires breadcrumbs to be enabled.
116
116
  </details>
117
117
 
118
118
  <details>
119
- <summary><strong>Operational Health Panels — Jobs, Database, Cache</strong></summary>
119
+ <summary><strong>Operational Health Panels — Jobs, Database, Cache, ActionCable</strong></summary>
120
120
 
121
121
  **Job Health** — Auto-detects Sidekiq, SolidQueue, or GoodJob. Per-error table with adapter badge, failed count (color-coded), sorted worst-first.
122
122
 
@@ -130,6 +130,12 @@ Requires breadcrumbs to be enabled.
130
130
 
131
131
  ![Cache Health](docs/images/cache-health.png)
132
132
 
133
+ **ActionCable Health** — Track WebSocket channel actions, transmissions, subscription confirmations, and rejections. Dashboard page at `/errors/actioncable_health_summary` with channel breakdown sorted by rejections. System health snapshot captures live connection count and adapter. No error tracker surfaces this alongside HTTP errors.
134
+
135
+ ```ruby
136
+ config.enable_actioncable_tracking = true # requires enable_breadcrumbs = true
137
+ ```
138
+
133
139
  [Complete documentation →](docs/FEATURES.md#job-health-page)
134
140
  </details>
135
141
 
@@ -409,6 +409,27 @@ module RailsErrorDashboard
409
409
  @pagy, @events = pagy(:offset, all_events, limit: params[:per_page] || 25)
410
410
  end
411
411
 
412
+ def actioncable_health_summary
413
+ unless RailsErrorDashboard.configuration.enable_actioncable_tracking &&
414
+ RailsErrorDashboard.configuration.enable_breadcrumbs
415
+ flash[:alert] = "ActionCable tracking is not enabled. Enable enable_actioncable_tracking and enable_breadcrumbs in config/initializers/rails_error_dashboard.rb"
416
+ redirect_to errors_path
417
+ return
418
+ end
419
+
420
+ days = (params[:days] || 30).to_i
421
+ @days = days
422
+ result = Queries::ActionCableSummary.call(days, application_id: @current_application_id)
423
+ all_channels = result[:channels]
424
+
425
+ # Summary stats (computed before pagination)
426
+ @unique_channels = all_channels.size
427
+ @total_events = all_channels.sum { |c| c[:total_events] }
428
+ @total_rejections = all_channels.sum { |c| c[:rejection_count] }
429
+
430
+ @pagy, @channels = pagy(:offset, all_channels, limit: params[:per_page] || 25)
431
+ end
432
+
412
433
  def diagnostic_dumps
413
434
  unless RailsErrorDashboard.configuration.enable_diagnostic_dump
414
435
  flash[:alert] = "Diagnostic dumps are not enabled. Enable them in config/initializers/rails_error_dashboard.rb"
@@ -0,0 +1,132 @@
1
+ <% content_for :page_title, "ActionCable Health" %>
2
+
3
+ <div class="container-fluid py-4">
4
+ <div class="d-flex justify-content-between align-items-center mb-4">
5
+ <h1 class="h3 mb-0">
6
+ <i class="bi bi-broadcast me-2"></i>
7
+ ActionCable Health
8
+ </h1>
9
+
10
+ <div class="btn-group" role="group">
11
+ <%= link_to actioncable_health_summary_errors_path(days: 7), class: "btn btn-sm #{@days == 7 ? 'btn-primary' : 'btn-outline-primary'}" do %>
12
+ 7 Days
13
+ <% end %>
14
+ <%= link_to actioncable_health_summary_errors_path(days: 30), class: "btn btn-sm #{@days == 30 ? 'btn-primary' : 'btn-outline-primary'}" do %>
15
+ 30 Days
16
+ <% end %>
17
+ <%= link_to actioncable_health_summary_errors_path(days: 90), class: "btn btn-sm #{@days == 90 ? 'btn-primary' : 'btn-outline-primary'}" do %>
18
+ 90 Days
19
+ <% end %>
20
+ </div>
21
+ </div>
22
+
23
+ <% if @unique_channels == 0 %>
24
+ <div class="text-center py-5">
25
+ <i class="bi bi-broadcast display-1 text-success mb-3"></i>
26
+ <h4 class="text-muted">No ActionCable Events Found</h4>
27
+ <p class="text-muted">
28
+ No ActionCable channel actions, transmissions, or subscription events were detected in error breadcrumbs over the last <%= @days %> days.
29
+ </p>
30
+ <div class="card mx-auto" style="max-width: 500px;">
31
+ <div class="card-body text-start">
32
+ <h6>How ActionCable tracking works:</h6>
33
+ <ul class="mb-0">
34
+ <li>Breadcrumbs must be enabled (<code>enable_breadcrumbs = true</code>)</li>
35
+ <li>ActionCable tracking must be enabled (<code>enable_actioncable_tracking = true</code>)</li>
36
+ <li>ActionCable must be configured in your app</li>
37
+ <li>Channel actions, transmissions, and subscription events are captured as breadcrumbs during requests that produce errors</li>
38
+ </ul>
39
+ </div>
40
+ </div>
41
+ </div>
42
+ <% else %>
43
+ <div class="row mb-4">
44
+ <div class="col-md-4">
45
+ <div class="card text-center">
46
+ <div class="card-body">
47
+ <div class="display-6 text-primary"><%= @unique_channels %></div>
48
+ <small class="text-muted">Active Channels</small>
49
+ </div>
50
+ </div>
51
+ </div>
52
+ <div class="col-md-4">
53
+ <div class="card text-center">
54
+ <div class="card-body">
55
+ <div class="display-6 text-info"><%= @total_events %></div>
56
+ <small class="text-muted">Total Events</small>
57
+ </div>
58
+ </div>
59
+ </div>
60
+ <div class="col-md-4">
61
+ <div class="card text-center">
62
+ <div class="card-body">
63
+ <div class="display-6 <%= @total_rejections > 0 ? 'text-danger' : 'text-success' %>"><%= @total_rejections %></div>
64
+ <small class="text-muted">Subscription Rejections</small>
65
+ </div>
66
+ </div>
67
+ </div>
68
+ </div>
69
+
70
+ <div class="card mb-4">
71
+ <div class="card-header bg-white d-flex justify-content-between align-items-center">
72
+ <h5 class="mb-0">
73
+ <i class="bi bi-broadcast text-primary me-2"></i>
74
+ ActionCable Events by Channel
75
+ <span class="badge bg-primary"><%= @unique_channels %></span>
76
+ </h5>
77
+ <small class="text-muted"><%== @pagy.info_tag %></small>
78
+ </div>
79
+ <div class="card-body p-0">
80
+ <div class="table-responsive">
81
+ <table class="table table-hover mb-0">
82
+ <thead class="table-light">
83
+ <tr>
84
+ <th>Channel</th>
85
+ <th width="100">Actions</th>
86
+ <th width="120">Transmissions</th>
87
+ <th width="120">Subscriptions</th>
88
+ <th width="100">Rejections</th>
89
+ <th width="80">Errors</th>
90
+ <th width="140">Last Seen</th>
91
+ </tr>
92
+ </thead>
93
+ <tbody>
94
+ <% @channels.each do |channel| %>
95
+ <tr>
96
+ <td><code><%= channel[:channel] %></code></td>
97
+ <td><%= channel[:perform_count] %></td>
98
+ <td><%= channel[:transmit_count] %></td>
99
+ <td><span class="text-success"><%= channel[:subscription_count] %></span></td>
100
+ <td>
101
+ <% if channel[:rejection_count] > 0 %>
102
+ <span class="badge bg-danger"><%= channel[:rejection_count] %></span>
103
+ <% else %>
104
+ <span class="text-muted">0</span>
105
+ <% end %>
106
+ </td>
107
+ <td><%= channel[:error_count] %></td>
108
+ <td><%= local_time_ago(channel[:last_seen]) %></td>
109
+ </tr>
110
+ <% end %>
111
+ </tbody>
112
+ </table>
113
+ </div>
114
+ </div>
115
+ <div class="card-footer bg-white border-top d-flex justify-content-between align-items-center">
116
+ <div>
117
+ <small class="text-muted">
118
+ <i class="bi bi-lightbulb text-warning"></i> ActionCable events are captured when they coincide with errors. High rejection counts may indicate authentication or authorization issues.
119
+ </small>
120
+ <small class="ms-3">
121
+ <a href="https://guides.rubyonrails.org/action_cable_overview.html" target="_blank" rel="noopener" class="text-decoration-none">
122
+ <i class="bi bi-book"></i> ActionCable Guide <i class="bi bi-box-arrow-up-right" style="font-size: 0.7em;"></i>
123
+ </a>
124
+ </small>
125
+ </div>
126
+ <div>
127
+ <%== @pagy.series_nav(:bootstrap) if @pagy.pages > 1 %>
128
+ </div>
129
+ </div>
130
+ </div>
131
+ <% end %>
132
+ </div>
data/config/routes.rb CHANGED
@@ -31,6 +31,7 @@ RailsErrorDashboard::Engine.routes.draw do
31
31
  get :database_health_summary
32
32
  get :swallowed_exceptions
33
33
  get :rack_attack_summary
34
+ get :actioncable_health_summary
34
35
  get :diagnostic_dumps
35
36
  post :create_diagnostic_dump
36
37
  post :batch_action
@@ -158,6 +158,9 @@ module RailsErrorDashboard
158
158
  # Rack Attack event tracking (requires enable_breadcrumbs = true)
159
159
  attr_accessor :enable_rack_attack_tracking # Master switch (default: false)
160
160
 
161
+ # ActionCable event tracking (requires enable_breadcrumbs = true)
162
+ attr_accessor :enable_actioncable_tracking # Master switch (default: false)
163
+
161
164
  # Notification callbacks (managed via helper methods, not set directly)
162
165
  attr_reader :notification_callbacks
163
166
 
@@ -300,6 +303,9 @@ module RailsErrorDashboard
300
303
  # Rack Attack event tracking defaults - OFF by default (opt-in, requires breadcrumbs)
301
304
  @enable_rack_attack_tracking = false
302
305
 
306
+ # ActionCable event tracking defaults - OFF by default (opt-in, requires breadcrumbs)
307
+ @enable_actioncable_tracking = false
308
+
303
309
  # Internal logging defaults - SILENT by default
304
310
  @enable_internal_logging = false # Opt-in for debugging
305
311
  @log_level = :silent # Silent by default, use :debug, :info, :warn, :error, or :silent
@@ -440,6 +446,13 @@ module RailsErrorDashboard
440
446
  @enable_rack_attack_tracking = false
441
447
  end
442
448
 
449
+ # Validate actioncable tracking requires breadcrumbs
450
+ if enable_actioncable_tracking && !enable_breadcrumbs
451
+ warnings << "enable_actioncable_tracking requires enable_breadcrumbs = true. " \
452
+ "ActionCable tracking has been auto-disabled."
453
+ @enable_actioncable_tracking = false
454
+ end
455
+
443
456
  # Validate crash capture path (must exist if custom path specified)
444
457
  if enable_crash_capture && crash_capture_path
445
458
  unless Dir.exist?(crash_capture_path)
@@ -77,6 +77,13 @@ module RailsErrorDashboard
77
77
  RailsErrorDashboard::Subscribers::RackAttackSubscriber.subscribe!
78
78
  end
79
79
 
80
+ # Subscribe to ActionCable AS::Notifications events (requires breadcrumbs + ActionCable)
81
+ if RailsErrorDashboard.configuration.enable_actioncable_tracking &&
82
+ RailsErrorDashboard.configuration.enable_breadcrumbs &&
83
+ defined?(ActionCable)
84
+ RailsErrorDashboard::Subscribers::ActionCableSubscriber.subscribe!
85
+ end
86
+
80
87
  # Enable TracePoint(:raise) for local variable and/or instance variable capture
81
88
  if RailsErrorDashboard.configuration.enable_local_variables ||
82
89
  RailsErrorDashboard.configuration.enable_instance_variables
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsErrorDashboard
4
+ module Queries
5
+ # Query: Aggregate ActionCable events from breadcrumbs across all errors
6
+ # Scans error_logs breadcrumbs JSON, filters for "action_cable" category crumbs,
7
+ # and groups by channel name with counts by event type.
8
+ class ActionCableSummary
9
+ def self.call(days = 30, application_id: nil)
10
+ new(days, application_id: application_id).call
11
+ end
12
+
13
+ def initialize(days = 30, application_id: nil)
14
+ @days = days
15
+ @application_id = application_id
16
+ @start_date = days.days.ago
17
+ end
18
+
19
+ def call
20
+ {
21
+ channels: aggregated_channels
22
+ }
23
+ end
24
+
25
+ private
26
+
27
+ def base_query
28
+ scope = ErrorLog.where("occurred_at >= ?", @start_date)
29
+ .where.not(breadcrumbs: nil)
30
+ scope = scope.where(application_id: @application_id) if @application_id.present?
31
+ scope
32
+ end
33
+
34
+ def aggregated_channels
35
+ results = {}
36
+
37
+ base_query.select(:id, :breadcrumbs, :occurred_at).find_each(batch_size: 500) do |error_log|
38
+ crumbs = parse_breadcrumbs(error_log.breadcrumbs)
39
+ next if crumbs.empty?
40
+
41
+ ac_crumbs = crumbs.select { |c| c["c"] == "action_cable" }
42
+ next if ac_crumbs.empty?
43
+
44
+ ac_crumbs.each do |crumb|
45
+ meta = crumb["meta"] || {}
46
+ channel = meta["channel"].to_s.presence || "Unknown"
47
+ event_type = meta["event_type"].to_s
48
+
49
+ results[channel] ||= {
50
+ channel: channel,
51
+ perform_count: 0,
52
+ transmit_count: 0,
53
+ subscription_count: 0,
54
+ rejection_count: 0,
55
+ error_ids: [],
56
+ last_seen: nil
57
+ }
58
+
59
+ entry = results[channel]
60
+
61
+ case event_type
62
+ when "perform_action"
63
+ entry[:perform_count] += 1
64
+ when "transmit"
65
+ entry[:transmit_count] += 1
66
+ when "transmit_subscription_confirmation"
67
+ entry[:subscription_count] += 1
68
+ when "transmit_subscription_rejection"
69
+ entry[:rejection_count] += 1
70
+ end
71
+
72
+ entry[:error_ids] << error_log.id
73
+ entry[:last_seen] = [ entry[:last_seen], error_log.occurred_at ].compact.max
74
+ end
75
+ end
76
+
77
+ results.values.each do |r|
78
+ r[:error_ids] = r[:error_ids].uniq
79
+ r[:error_count] = r[:error_ids].size
80
+ r[:total_events] = r[:perform_count] + r[:transmit_count] + r[:subscription_count] + r[:rejection_count]
81
+ end
82
+ results.values.sort_by { |r| [ -r[:rejection_count], -r[:total_events] ] }
83
+ rescue => e
84
+ Rails.logger.error("[RailsErrorDashboard] ActionCableSummary query failed: #{e.class}: #{e.message}")
85
+ []
86
+ end
87
+
88
+ def parse_breadcrumbs(raw)
89
+ return [] if raw.blank?
90
+ JSON.parse(raw)
91
+ rescue JSON::ParserError
92
+ []
93
+ end
94
+ end
95
+ end
96
+ end
@@ -36,6 +36,7 @@ module RailsErrorDashboard
36
36
  job_queue: job_queue_stats,
37
37
  ruby_vm: ruby_vm_stats,
38
38
  yjit: yjit_stats,
39
+ actioncable: actioncable_stats,
39
40
  captured_at: Time.current.iso8601
40
41
  }
41
42
  end
@@ -154,6 +155,18 @@ module RailsErrorDashboard
154
155
  nil
155
156
  end
156
157
 
158
+ # ActionCable connection stats — read-only, <0.1ms
159
+ def actioncable_stats
160
+ return nil unless defined?(ActionCable) && defined?(ActionCable::Server)
161
+ server = ActionCable.server
162
+ {
163
+ connections: server.connections.count,
164
+ adapter: server.pubsub&.class&.name&.demodulize
165
+ }
166
+ rescue => e
167
+ nil
168
+ end
169
+
157
170
  # RubyVM::YJIT.runtime_stats — JIT compilation health
158
171
  # Cherry-picks diagnostic keys (full hash has 30+ entries)
159
172
  def yjit_stats
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsErrorDashboard
4
+ module Subscribers
5
+ # Registers ActiveSupport::Notifications subscribers for ActionCable events.
6
+ #
7
+ # ActionCable emits:
8
+ # - perform_action.action_cable — channel action executed
9
+ # - transmit.action_cable — data transmitted to subscriber
10
+ # - transmit_subscription_confirmation.action_cable — subscription confirmed
11
+ # - transmit_subscription_rejection.action_cable — subscription rejected
12
+ #
13
+ # Each event is captured as a breadcrumb with category "action_cable",
14
+ # allowing correlation between WebSocket events and error spikes.
15
+ #
16
+ # SAFETY RULES (HOST_APP_SAFETY.md):
17
+ # - Every subscriber wrapped in rescue => e; nil
18
+ # - Never raise from subscriber callbacks
19
+ # - Skip if buffer is nil (not in a request context)
20
+ class ActionCableSubscriber
21
+ EVENTS = %w[
22
+ perform_action.action_cable
23
+ transmit.action_cable
24
+ transmit_subscription_confirmation.action_cable
25
+ transmit_subscription_rejection.action_cable
26
+ ].freeze
27
+
28
+ # Event subscriptions managed by this class
29
+ @subscriptions = []
30
+
31
+ class << self
32
+ attr_reader :subscriptions
33
+
34
+ # Register all ActionCable event subscribers
35
+ # @return [Array] Array of subscription objects
36
+ def subscribe!
37
+ @subscriptions = []
38
+
39
+ EVENTS.each do |event_name|
40
+ @subscriptions << subscribe_event(event_name)
41
+ end
42
+
43
+ @subscriptions
44
+ end
45
+
46
+ # Remove all ActionCable subscribers
47
+ def unsubscribe!
48
+ @subscriptions.each do |sub|
49
+ ActiveSupport::Notifications.unsubscribe(sub) if sub
50
+ rescue => e
51
+ nil
52
+ end
53
+ @subscriptions = []
54
+ end
55
+
56
+ private
57
+
58
+ def subscribe_event(event_name)
59
+ ActiveSupport::Notifications.subscribe(event_name) do |*args|
60
+ event = ActiveSupport::Notifications::Event.new(*args)
61
+ handle_action_cable(event, event_name)
62
+ rescue => e
63
+ nil
64
+ end
65
+ end
66
+
67
+ def handle_action_cable(event, event_name)
68
+ return unless Services::BreadcrumbCollector.current_buffer
69
+
70
+ payload = event.payload || {}
71
+ channel = payload[:channel_class] || payload[:channel] || "Unknown"
72
+ channel = channel.to_s
73
+
74
+ event_type = event_name.split(".").first # "perform_action", "transmit", etc.
75
+ action = payload[:action].to_s
76
+
77
+ message = build_message(event_type, channel, action)
78
+
79
+ metadata = {
80
+ channel: channel,
81
+ event_type: event_type
82
+ }
83
+ metadata[:action] = action if action.present?
84
+
85
+ duration_ms = event.duration if event.respond_to?(:duration)
86
+
87
+ Services::BreadcrumbCollector.add("action_cable", message, duration_ms: duration_ms, metadata: metadata)
88
+ end
89
+
90
+ def build_message(event_type, channel, action)
91
+ case event_type
92
+ when "perform_action"
93
+ action.present? ? "perform: #{channel}##{action}" : "perform: #{channel}"
94
+ when "transmit"
95
+ "transmit: #{channel}"
96
+ when "transmit_subscription_confirmation"
97
+ "subscribed: #{channel}"
98
+ when "transmit_subscription_rejection"
99
+ "rejected: #{channel}"
100
+ else
101
+ "#{event_type}: #{channel}"
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
@@ -1,3 +1,3 @@
1
1
  module RailsErrorDashboard
2
- VERSION = "0.4.2"
2
+ VERSION = "0.5.0"
3
3
  end
@@ -64,7 +64,9 @@ require "rails_error_dashboard/services/crash_capture"
64
64
  require "rails_error_dashboard/services/diagnostic_dump_generator"
65
65
  require "rails_error_dashboard/subscribers/breadcrumb_subscriber"
66
66
  require "rails_error_dashboard/subscribers/rack_attack_subscriber"
67
+ require "rails_error_dashboard/subscribers/action_cable_subscriber"
67
68
  require "rails_error_dashboard/queries/co_occurring_errors"
69
+ require "rails_error_dashboard/queries/action_cable_summary"
68
70
  require "rails_error_dashboard/queries/error_cascades"
69
71
  require "rails_error_dashboard/queries/baseline_stats"
70
72
  require "rails_error_dashboard/queries/platform_comparison"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_error_dashboard
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anjan Jagirdar
@@ -290,6 +290,7 @@ files:
290
290
  - app/views/rails_error_dashboard/errors/_stats.html.erb
291
291
  - app/views/rails_error_dashboard/errors/_timeline.html.erb
292
292
  - app/views/rails_error_dashboard/errors/_user_errors_table.html.erb
293
+ - app/views/rails_error_dashboard/errors/actioncable_health_summary.html.erb
293
294
  - app/views/rails_error_dashboard/errors/analytics.html.erb
294
295
  - app/views/rails_error_dashboard/errors/cache_health_summary.html.erb
295
296
  - app/views/rails_error_dashboard/errors/correlation.html.erb
@@ -382,6 +383,7 @@ files:
382
383
  - lib/rails_error_dashboard/plugins/audit_log_plugin.rb
383
384
  - lib/rails_error_dashboard/plugins/jira_integration_plugin.rb
384
385
  - lib/rails_error_dashboard/plugins/metrics_plugin.rb
386
+ - lib/rails_error_dashboard/queries/action_cable_summary.rb
385
387
  - lib/rails_error_dashboard/queries/analytics_stats.rb
386
388
  - lib/rails_error_dashboard/queries/baseline_stats.rb
387
389
  - lib/rails_error_dashboard/queries/cache_health_summary.rb
@@ -445,6 +447,7 @@ files:
445
447
  - lib/rails_error_dashboard/services/system_health_snapshot.rb
446
448
  - lib/rails_error_dashboard/services/variable_serializer.rb
447
449
  - lib/rails_error_dashboard/services/webhook_payload_builder.rb
450
+ - lib/rails_error_dashboard/subscribers/action_cable_subscriber.rb
448
451
  - lib/rails_error_dashboard/subscribers/breadcrumb_subscriber.rb
449
452
  - lib/rails_error_dashboard/subscribers/rack_attack_subscriber.rb
450
453
  - lib/rails_error_dashboard/value_objects/error_context.rb
@@ -462,7 +465,7 @@ metadata:
462
465
  bug_tracker_uri: https://github.com/AnjanJ/rails_error_dashboard/issues
463
466
  funding_uri: https://buymeacoffee.com/anjanj
464
467
  post_install_message: "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n
465
- \ Rails Error Dashboard v0.4.2\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n\U0001F195
468
+ \ Rails Error Dashboard v0.5.0\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n\U0001F195
466
469
  First time? Quick start:\n rails generate rails_error_dashboard:install\n rails
467
470
  db:migrate\n # Add to config/routes.rb:\n mount RailsErrorDashboard::Engine
468
471
  => '/error_dashboard'\n\n\U0001F504 Upgrading from v0.1.x?\n rails db:migrate\n