rails_error_dashboard 0.5.9 → 0.5.11
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/README.md +60 -7
- data/app/controllers/rails_error_dashboard/errors_controller.rb +41 -0
- data/app/controllers/rails_error_dashboard/webhooks_controller.rb +2 -1
- data/app/helpers/rails_error_dashboard/backtrace_helper.rb +12 -0
- data/app/jobs/rails_error_dashboard/scheduled_digest_job.rb +40 -0
- data/app/mailers/rails_error_dashboard/digest_mailer.rb +23 -0
- data/app/mailers/rails_error_dashboard/error_notification_mailer.rb +2 -1
- data/app/views/layouts/rails_error_dashboard.html.erb +10 -0
- data/app/views/rails_error_dashboard/digest_mailer/digest_summary.html.erb +172 -0
- data/app/views/rails_error_dashboard/digest_mailer/digest_summary.text.erb +49 -0
- data/app/views/rails_error_dashboard/errors/_sidebar_metadata.html.erb +14 -1
- data/app/views/rails_error_dashboard/errors/_source_code.html.erb +20 -7
- data/app/views/rails_error_dashboard/errors/releases.html.erb +284 -0
- data/app/views/rails_error_dashboard/errors/settings/_value_badge.html.erb +15 -0
- data/app/views/rails_error_dashboard/errors/settings.html.erb +37 -1
- data/app/views/rails_error_dashboard/errors/show.html.erb +21 -0
- data/app/views/rails_error_dashboard/errors/user_impact.html.erb +172 -0
- data/config/routes.rb +4 -0
- data/lib/generators/rails_error_dashboard/install/install_generator.rb +6 -0
- data/lib/generators/rails_error_dashboard/install/templates/README +9 -18
- data/lib/generators/rails_error_dashboard/install/templates/initializer.rb +32 -2
- data/lib/rails_error_dashboard/configuration.rb +55 -13
- data/lib/rails_error_dashboard/middleware/rate_limiter.rb +16 -12
- data/lib/rails_error_dashboard/plugins/jira_integration_plugin.rb +2 -1
- data/lib/rails_error_dashboard/queries/release_timeline.rb +181 -0
- data/lib/rails_error_dashboard/queries/user_impact_summary.rb +93 -0
- data/lib/rails_error_dashboard/services/coverage_tracker.rb +139 -0
- data/lib/rails_error_dashboard/services/digest_builder.rb +158 -0
- data/lib/rails_error_dashboard/services/notification_helpers.rb +2 -1
- data/lib/rails_error_dashboard/subscribers/issue_tracker_subscriber.rb +6 -7
- data/lib/rails_error_dashboard/version.rb +1 -1
- data/lib/rails_error_dashboard.rb +4 -0
- data/lib/tasks/error_dashboard.rake +23 -0
- metadata +35 -9
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RailsErrorDashboard
|
|
4
|
+
module Services
|
|
5
|
+
# Pure algorithm: Build a digest summary of error activity for a time period.
|
|
6
|
+
# Aggregates stats from existing queries into a single hash suitable for email templates.
|
|
7
|
+
#
|
|
8
|
+
# @example
|
|
9
|
+
# DigestBuilder.call(period: :daily)
|
|
10
|
+
# # => { period: :daily, stats: { new_errors: 12, ... }, top_errors: [...], ... }
|
|
11
|
+
class DigestBuilder
|
|
12
|
+
PERIODS = {
|
|
13
|
+
daily: { days: 1, label: "Last 24 hours" },
|
|
14
|
+
weekly: { days: 7, label: "Last 7 days" }
|
|
15
|
+
}.freeze
|
|
16
|
+
|
|
17
|
+
def self.call(period: :daily, application_id: nil)
|
|
18
|
+
new(period: period, application_id: application_id).call
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def initialize(period: :daily, application_id: nil)
|
|
22
|
+
@period = PERIODS.key?(period) ? period : :daily
|
|
23
|
+
@days = PERIODS[@period][:days]
|
|
24
|
+
@application_id = application_id
|
|
25
|
+
@start_date = @days.days.ago
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def call
|
|
29
|
+
{
|
|
30
|
+
period: @period,
|
|
31
|
+
period_label: PERIODS[@period][:label],
|
|
32
|
+
generated_at: Time.current,
|
|
33
|
+
stats: build_stats,
|
|
34
|
+
top_errors: top_errors,
|
|
35
|
+
critical_unresolved: critical_unresolved,
|
|
36
|
+
comparison: build_comparison
|
|
37
|
+
}
|
|
38
|
+
rescue => e
|
|
39
|
+
Rails.logger.error("[RailsErrorDashboard] DigestBuilder failed: #{e.class}: #{e.message}")
|
|
40
|
+
empty_result
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def base_scope
|
|
46
|
+
scope = ErrorLog.where("occurred_at >= ?", @start_date)
|
|
47
|
+
scope = scope.where(application_id: @application_id) if @application_id.present?
|
|
48
|
+
scope
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def build_stats
|
|
52
|
+
scope = base_scope
|
|
53
|
+
|
|
54
|
+
new_errors = scope.where("occurrence_count <= 1").count
|
|
55
|
+
total_occurrences = scope.sum(:occurrence_count)
|
|
56
|
+
resolved = scope.where(resolved: true).count
|
|
57
|
+
unresolved = scope.where(resolved: false).count
|
|
58
|
+
# Severity is computed from error_type via SeverityClassifier (not a DB column).
|
|
59
|
+
# Count critical+high by matching known error type patterns via SQL WHERE IN.
|
|
60
|
+
critical_types = Services::SeverityClassifier::CRITICAL_ERROR_TYPES +
|
|
61
|
+
Services::SeverityClassifier::HIGH_SEVERITY_ERROR_TYPES
|
|
62
|
+
critical_high = scope.where(error_type: critical_types).count
|
|
63
|
+
|
|
64
|
+
total = resolved + unresolved
|
|
65
|
+
resolution_rate = total > 0 ? (resolved.to_f / total * 100).round(1) : 0
|
|
66
|
+
|
|
67
|
+
{
|
|
68
|
+
new_errors: new_errors,
|
|
69
|
+
total_occurrences: total_occurrences,
|
|
70
|
+
resolved: resolved,
|
|
71
|
+
unresolved: unresolved,
|
|
72
|
+
critical_high: critical_high,
|
|
73
|
+
resolution_rate: resolution_rate
|
|
74
|
+
}
|
|
75
|
+
rescue => e
|
|
76
|
+
Rails.logger.error("[RailsErrorDashboard] DigestBuilder.build_stats failed: #{e.class}: #{e.message}")
|
|
77
|
+
{ new_errors: 0, total_occurrences: 0, resolved: 0, unresolved: 0, critical_high: 0, resolution_rate: 0 }
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def top_errors
|
|
81
|
+
base_scope
|
|
82
|
+
.where(resolved: false)
|
|
83
|
+
.group(:error_type)
|
|
84
|
+
.order("count_all DESC")
|
|
85
|
+
.limit(5)
|
|
86
|
+
.count
|
|
87
|
+
.map do |error_type, count|
|
|
88
|
+
sample = base_scope.where(error_type: error_type).order(occurred_at: :desc).first
|
|
89
|
+
{
|
|
90
|
+
error_type: error_type,
|
|
91
|
+
message: sample&.message.to_s.truncate(100),
|
|
92
|
+
count: count,
|
|
93
|
+
id: sample&.id
|
|
94
|
+
}
|
|
95
|
+
end
|
|
96
|
+
rescue => e
|
|
97
|
+
Rails.logger.error("[RailsErrorDashboard] DigestBuilder.top_errors failed: #{e.class}: #{e.message}")
|
|
98
|
+
[]
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def critical_unresolved
|
|
102
|
+
critical_types = Services::SeverityClassifier::CRITICAL_ERROR_TYPES +
|
|
103
|
+
Services::SeverityClassifier::HIGH_SEVERITY_ERROR_TYPES
|
|
104
|
+
base_scope
|
|
105
|
+
.where(resolved: false)
|
|
106
|
+
.where(error_type: critical_types)
|
|
107
|
+
.order(occurred_at: :desc)
|
|
108
|
+
.limit(5)
|
|
109
|
+
.map do |error|
|
|
110
|
+
{
|
|
111
|
+
error_type: error.error_type,
|
|
112
|
+
message: error.message.to_s.truncate(100),
|
|
113
|
+
severity: error.severity,
|
|
114
|
+
id: error.id
|
|
115
|
+
}
|
|
116
|
+
end
|
|
117
|
+
rescue => e
|
|
118
|
+
Rails.logger.error("[RailsErrorDashboard] DigestBuilder.critical_unresolved failed: #{e.class}: #{e.message}")
|
|
119
|
+
[]
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def build_comparison
|
|
123
|
+
previous_start = (@days * 2).days.ago
|
|
124
|
+
previous_end = @start_date
|
|
125
|
+
|
|
126
|
+
current_count = base_scope.count
|
|
127
|
+
previous_scope = ErrorLog.where("occurred_at >= ? AND occurred_at < ?", previous_start, previous_end)
|
|
128
|
+
previous_scope = previous_scope.where(application_id: @application_id) if @application_id.present?
|
|
129
|
+
previous_count = previous_scope.count
|
|
130
|
+
|
|
131
|
+
delta = current_count - previous_count
|
|
132
|
+
percentage = previous_count > 0 ? ((delta.to_f / previous_count) * 100).round(1) : nil
|
|
133
|
+
|
|
134
|
+
{
|
|
135
|
+
current_count: current_count,
|
|
136
|
+
previous_count: previous_count,
|
|
137
|
+
error_delta: delta,
|
|
138
|
+
error_delta_percentage: percentage
|
|
139
|
+
}
|
|
140
|
+
rescue => e
|
|
141
|
+
Rails.logger.error("[RailsErrorDashboard] DigestBuilder.build_comparison failed: #{e.class}: #{e.message}")
|
|
142
|
+
{ current_count: 0, previous_count: 0, error_delta: 0, error_delta_percentage: nil }
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def empty_result
|
|
146
|
+
{
|
|
147
|
+
period: @period,
|
|
148
|
+
period_label: PERIODS.dig(@period, :label) || "Unknown",
|
|
149
|
+
generated_at: Time.current,
|
|
150
|
+
stats: { new_errors: 0, total_occurrences: 0, resolved: 0, unresolved: 0, critical_high: 0, resolution_rate: 0 },
|
|
151
|
+
top_errors: [],
|
|
152
|
+
critical_unresolved: [],
|
|
153
|
+
comparison: { current_count: 0, previous_count: 0, error_delta: 0, error_delta_percentage: nil }
|
|
154
|
+
}
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
@@ -14,7 +14,8 @@ module RailsErrorDashboard
|
|
|
14
14
|
# @return [String] Full URL to the error detail page
|
|
15
15
|
def dashboard_url(error_log)
|
|
16
16
|
base_url = RailsErrorDashboard.configuration.dashboard_base_url || "http://localhost:3000"
|
|
17
|
-
|
|
17
|
+
mount_path = RailsErrorDashboard.configuration.engine_mount_path
|
|
18
|
+
"#{base_url}#{mount_path}/errors/#{error_log.id}"
|
|
18
19
|
end
|
|
19
20
|
|
|
20
21
|
# Truncate a message to a maximum length
|
|
@@ -13,7 +13,8 @@ module RailsErrorDashboard
|
|
|
13
13
|
# Called when a new error is first logged
|
|
14
14
|
def on_error_logged(error_log)
|
|
15
15
|
return unless should_auto_create?(error_log)
|
|
16
|
-
|
|
16
|
+
dashboard_url = Services::NotificationHelpers.dashboard_url(error_log)
|
|
17
|
+
CreateIssueJob.perform_later(error_log.id, dashboard_url: dashboard_url)
|
|
17
18
|
rescue => e
|
|
18
19
|
nil
|
|
19
20
|
end
|
|
@@ -49,17 +50,15 @@ module RailsErrorDashboard
|
|
|
49
50
|
|
|
50
51
|
def should_auto_create?(error_log)
|
|
51
52
|
config = RailsErrorDashboard.configuration
|
|
52
|
-
return false unless config.enable_issue_tracking
|
|
53
|
+
return false unless config.enable_issue_tracking
|
|
53
54
|
return false if error_log.external_issue_url.present?
|
|
54
55
|
|
|
55
|
-
# First occurrence
|
|
56
|
-
|
|
57
|
-
return true
|
|
58
|
-
end
|
|
56
|
+
# First occurrence — always auto-create
|
|
57
|
+
return true if error_log.occurrence_count == 1
|
|
59
58
|
|
|
60
59
|
# Severity threshold check
|
|
61
60
|
severity = error_log.severity&.to_sym
|
|
62
|
-
if config.
|
|
61
|
+
if config.issue_tracker_auto_create_severities&.include?(severity)
|
|
63
62
|
return true
|
|
64
63
|
end
|
|
65
64
|
|
|
@@ -67,6 +67,9 @@ require "rails_error_dashboard/services/local_variable_capturer"
|
|
|
67
67
|
require "rails_error_dashboard/services/swallowed_exception_tracker"
|
|
68
68
|
require "rails_error_dashboard/services/crash_capture"
|
|
69
69
|
require "rails_error_dashboard/services/diagnostic_dump_generator"
|
|
70
|
+
require "rails_error_dashboard/services/coverage_tracker"
|
|
71
|
+
require "rails_error_dashboard/services/digest_builder"
|
|
72
|
+
require "rails_error_dashboard/queries/user_impact_summary"
|
|
70
73
|
require "rails_error_dashboard/subscribers/breadcrumb_subscriber"
|
|
71
74
|
require "rails_error_dashboard/subscribers/rack_attack_subscriber"
|
|
72
75
|
require "rails_error_dashboard/subscribers/action_cable_subscriber"
|
|
@@ -119,6 +122,7 @@ require "rails_error_dashboard/queries/job_health_summary"
|
|
|
119
122
|
require "rails_error_dashboard/queries/database_health_summary"
|
|
120
123
|
require "rails_error_dashboard/queries/swallowed_exception_summary"
|
|
121
124
|
require "rails_error_dashboard/queries/rack_attack_summary"
|
|
125
|
+
require "rails_error_dashboard/queries/release_timeline"
|
|
122
126
|
require "rails_error_dashboard/error_reporter"
|
|
123
127
|
require "rails_error_dashboard/middleware/error_catcher"
|
|
124
128
|
require "rails_error_dashboard/middleware/rate_limiter"
|
|
@@ -525,4 +525,27 @@ namespace :error_dashboard do
|
|
|
525
525
|
|
|
526
526
|
puts "\n" + "=" * 80 + "\n"
|
|
527
527
|
end
|
|
528
|
+
|
|
529
|
+
desc "Send error digest email (PERIOD=daily|weekly, APP_ID=optional)"
|
|
530
|
+
task send_digest: :environment do
|
|
531
|
+
period = ENV.fetch("PERIOD", "daily")
|
|
532
|
+
app_id = ENV["APP_ID"]
|
|
533
|
+
|
|
534
|
+
unless RailsErrorDashboard.configuration.enable_scheduled_digests
|
|
535
|
+
puts "Scheduled digests are not enabled. Set config.enable_scheduled_digests = true"
|
|
536
|
+
next
|
|
537
|
+
end
|
|
538
|
+
|
|
539
|
+
recipients = RailsErrorDashboard.configuration.digest_recipients ||
|
|
540
|
+
RailsErrorDashboard.configuration.notification_email_recipients
|
|
541
|
+
|
|
542
|
+
if recipients.blank?
|
|
543
|
+
puts "No digest recipients configured. Set config.digest_recipients or config.notification_email_recipients"
|
|
544
|
+
next
|
|
545
|
+
end
|
|
546
|
+
|
|
547
|
+
puts "Sending #{period} error digest to #{recipients.join(', ')}..."
|
|
548
|
+
RailsErrorDashboard::ScheduledDigestJob.perform_later(period: period, application_id: app_id)
|
|
549
|
+
puts "Digest job enqueued."
|
|
550
|
+
end
|
|
528
551
|
end
|
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.5.
|
|
4
|
+
version: 0.5.11
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Anjan Jagirdar
|
|
@@ -260,10 +260,12 @@ files:
|
|
|
260
260
|
- app/jobs/rails_error_dashboard/pagerduty_error_notification_job.rb
|
|
261
261
|
- app/jobs/rails_error_dashboard/reopen_linked_issue_job.rb
|
|
262
262
|
- app/jobs/rails_error_dashboard/retention_cleanup_job.rb
|
|
263
|
+
- app/jobs/rails_error_dashboard/scheduled_digest_job.rb
|
|
263
264
|
- app/jobs/rails_error_dashboard/slack_error_notification_job.rb
|
|
264
265
|
- app/jobs/rails_error_dashboard/swallowed_exception_flush_job.rb
|
|
265
266
|
- app/jobs/rails_error_dashboard/webhook_error_notification_job.rb
|
|
266
267
|
- app/mailers/rails_error_dashboard/application_mailer.rb
|
|
268
|
+
- app/mailers/rails_error_dashboard/digest_mailer.rb
|
|
267
269
|
- app/mailers/rails_error_dashboard/error_notification_mailer.rb
|
|
268
270
|
- app/models/rails_error_dashboard/application.rb
|
|
269
271
|
- app/models/rails_error_dashboard/cascade_pattern.rb
|
|
@@ -275,6 +277,8 @@ files:
|
|
|
275
277
|
- app/models/rails_error_dashboard/error_occurrence.rb
|
|
276
278
|
- app/models/rails_error_dashboard/swallowed_exception.rb
|
|
277
279
|
- app/views/layouts/rails_error_dashboard.html.erb
|
|
280
|
+
- app/views/rails_error_dashboard/digest_mailer/digest_summary.html.erb
|
|
281
|
+
- app/views/rails_error_dashboard/digest_mailer/digest_summary.text.erb
|
|
278
282
|
- app/views/rails_error_dashboard/error_notification_mailer/error_alert.html.erb
|
|
279
283
|
- app/views/rails_error_dashboard/error_notification_mailer/error_alert.text.erb
|
|
280
284
|
- app/views/rails_error_dashboard/errors/_breadcrumbs_group.html.erb
|
|
@@ -310,10 +314,12 @@ files:
|
|
|
310
314
|
- app/views/rails_error_dashboard/errors/overview.html.erb
|
|
311
315
|
- app/views/rails_error_dashboard/errors/platform_comparison.html.erb
|
|
312
316
|
- app/views/rails_error_dashboard/errors/rack_attack_summary.html.erb
|
|
317
|
+
- app/views/rails_error_dashboard/errors/releases.html.erb
|
|
313
318
|
- app/views/rails_error_dashboard/errors/settings.html.erb
|
|
314
319
|
- app/views/rails_error_dashboard/errors/settings/_value_badge.html.erb
|
|
315
320
|
- app/views/rails_error_dashboard/errors/show.html.erb
|
|
316
321
|
- app/views/rails_error_dashboard/errors/swallowed_exceptions.html.erb
|
|
322
|
+
- app/views/rails_error_dashboard/errors/user_impact.html.erb
|
|
317
323
|
- config/routes.rb
|
|
318
324
|
- db/development.sqlite3
|
|
319
325
|
- db/migrate/20251223000000_create_rails_error_dashboard_complete_schema.rb
|
|
@@ -414,8 +420,10 @@ files:
|
|
|
414
420
|
- lib/rails_error_dashboard/queries/platform_comparison.rb
|
|
415
421
|
- lib/rails_error_dashboard/queries/rack_attack_summary.rb
|
|
416
422
|
- lib/rails_error_dashboard/queries/recurring_issues.rb
|
|
423
|
+
- lib/rails_error_dashboard/queries/release_timeline.rb
|
|
417
424
|
- lib/rails_error_dashboard/queries/similar_errors.rb
|
|
418
425
|
- lib/rails_error_dashboard/queries/swallowed_exception_summary.rb
|
|
426
|
+
- lib/rails_error_dashboard/queries/user_impact_summary.rb
|
|
419
427
|
- lib/rails_error_dashboard/services/analytics_cache_manager.rb
|
|
420
428
|
- lib/rails_error_dashboard/services/backtrace_parser.rb
|
|
421
429
|
- lib/rails_error_dashboard/services/backtrace_processor.rb
|
|
@@ -427,10 +435,12 @@ files:
|
|
|
427
435
|
- lib/rails_error_dashboard/services/cascade_detector.rb
|
|
428
436
|
- lib/rails_error_dashboard/services/cause_chain_extractor.rb
|
|
429
437
|
- lib/rails_error_dashboard/services/codeberg_issue_client.rb
|
|
438
|
+
- lib/rails_error_dashboard/services/coverage_tracker.rb
|
|
430
439
|
- lib/rails_error_dashboard/services/crash_capture.rb
|
|
431
440
|
- lib/rails_error_dashboard/services/curl_generator.rb
|
|
432
441
|
- lib/rails_error_dashboard/services/database_health_inspector.rb
|
|
433
442
|
- lib/rails_error_dashboard/services/diagnostic_dump_generator.rb
|
|
443
|
+
- lib/rails_error_dashboard/services/digest_builder.rb
|
|
434
444
|
- lib/rails_error_dashboard/services/discord_payload_builder.rb
|
|
435
445
|
- lib/rails_error_dashboard/services/environment_snapshot.rb
|
|
436
446
|
- lib/rails_error_dashboard/services/error_broadcaster.rb
|
|
@@ -484,14 +494,30 @@ metadata:
|
|
|
484
494
|
documentation_uri: https://AnjanJ.github.io/rails_error_dashboard
|
|
485
495
|
bug_tracker_uri: https://github.com/AnjanJ/rails_error_dashboard/issues
|
|
486
496
|
funding_uri: https://github.com/sponsors/AnjanJ
|
|
487
|
-
post_install_message:
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
497
|
+
post_install_message: |
|
|
498
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
499
|
+
RED (Rails Error Dashboard) v0.5.11
|
|
500
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
501
|
+
|
|
502
|
+
First install:
|
|
503
|
+
rails generate rails_error_dashboard:install
|
|
504
|
+
rails db:migrate
|
|
505
|
+
# Route and config are set up automatically by the generator.
|
|
506
|
+
|
|
507
|
+
Upgrading from a previous version:
|
|
508
|
+
rails generate rails_error_dashboard:install
|
|
509
|
+
rails db:migrate
|
|
510
|
+
# The generator detects your existing config and only adds new migrations.
|
|
511
|
+
|
|
512
|
+
Separate database users:
|
|
513
|
+
rails generate rails_error_dashboard:install
|
|
514
|
+
rails db:migrate:error_dashboard
|
|
515
|
+
# See docs for full separate-DB setup.
|
|
516
|
+
|
|
517
|
+
Live demo: https://rails-error-dashboard.anjan.dev
|
|
518
|
+
Full docs: https://github.com/AnjanJ/rails_error_dashboard
|
|
519
|
+
Changelog: https://github.com/AnjanJ/rails_error_dashboard/blob/main/CHANGELOG.md
|
|
520
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
495
521
|
rdoc_options: []
|
|
496
522
|
require_paths:
|
|
497
523
|
- lib
|