rails_error_dashboard 0.2.4 → 0.3.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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +67 -14
  3. data/app/controllers/rails_error_dashboard/errors_controller.rb +88 -1
  4. data/app/helpers/rails_error_dashboard/application_helper.rb +25 -0
  5. data/app/jobs/rails_error_dashboard/retention_cleanup_job.rb +18 -6
  6. data/app/views/layouts/rails_error_dashboard.html.erb +145 -1
  7. data/app/views/rails_error_dashboard/errors/_breadcrumbs_group.html.erb +236 -0
  8. data/app/views/rails_error_dashboard/errors/_co_occurring_errors.html.erb +70 -0
  9. data/app/views/rails_error_dashboard/errors/_discussion.html.erb +107 -0
  10. data/app/views/rails_error_dashboard/errors/_error_cascades.html.erb +138 -0
  11. data/app/views/rails_error_dashboard/errors/_error_info.html.erb +190 -0
  12. data/app/views/rails_error_dashboard/errors/_modals.html.erb +139 -0
  13. data/app/views/rails_error_dashboard/errors/_pattern_insights.html.erb +1 -1
  14. data/app/views/rails_error_dashboard/errors/_request_context.html.erb +97 -0
  15. data/app/views/rails_error_dashboard/errors/_show_scripts.html.erb +156 -0
  16. data/app/views/rails_error_dashboard/errors/_sidebar_metadata.html.erb +352 -0
  17. data/app/views/rails_error_dashboard/errors/_similar_errors.html.erb +75 -0
  18. data/app/views/rails_error_dashboard/errors/_timeline.html.erb +1 -1
  19. data/app/views/rails_error_dashboard/errors/cache_health_summary.html.erb +143 -0
  20. data/app/views/rails_error_dashboard/errors/deprecations.html.erb +129 -0
  21. data/app/views/rails_error_dashboard/errors/n_plus_one_summary.html.erb +134 -0
  22. data/app/views/rails_error_dashboard/errors/settings.html.erb +17 -0
  23. data/app/views/rails_error_dashboard/errors/show.html.erb +20 -1132
  24. data/config/routes.rb +3 -0
  25. data/db/migrate/20251223000000_create_rails_error_dashboard_complete_schema.rb +6 -0
  26. data/db/migrate/20260303000001_add_breadcrumbs_to_error_logs.rb +9 -0
  27. data/db/migrate/20260304000001_add_system_health_to_error_logs.rb +12 -0
  28. data/lib/generators/rails_error_dashboard/install/install_generator.rb +31 -3
  29. data/lib/generators/rails_error_dashboard/install/templates/initializer.rb +67 -5
  30. data/lib/rails_error_dashboard/commands/log_error.rb +33 -0
  31. data/lib/rails_error_dashboard/configuration.rb +45 -3
  32. data/lib/rails_error_dashboard/engine.rb +6 -1
  33. data/lib/rails_error_dashboard/middleware/error_catcher.rb +8 -0
  34. data/lib/rails_error_dashboard/queries/cache_health_summary.rb +72 -0
  35. data/lib/rails_error_dashboard/queries/deprecation_warnings.rb +80 -0
  36. data/lib/rails_error_dashboard/queries/n_plus_one_summary.rb +83 -0
  37. data/lib/rails_error_dashboard/services/breadcrumb_collector.rb +182 -0
  38. data/lib/rails_error_dashboard/services/cache_analyzer.rb +76 -0
  39. data/lib/rails_error_dashboard/services/curl_generator.rb +80 -0
  40. data/lib/rails_error_dashboard/services/n_plus_one_detector.rb +74 -0
  41. data/lib/rails_error_dashboard/services/system_health_snapshot.rb +145 -0
  42. data/lib/rails_error_dashboard/subscribers/breadcrumb_subscriber.rb +210 -0
  43. data/lib/rails_error_dashboard/version.rb +1 -1
  44. data/lib/rails_error_dashboard.rb +20 -0
  45. data/lib/tasks/error_dashboard.rake +68 -2
  46. metadata +27 -2
@@ -0,0 +1,129 @@
1
+ <% content_for :page_title, "Deprecation Warnings" %>
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-exclamation-triangle me-2"></i>
7
+ Deprecation Warnings
8
+ </h1>
9
+
10
+ <div class="btn-group" role="group">
11
+ <%= link_to deprecations_errors_path(days: 7), class: "btn btn-sm #{@days == 7 ? 'btn-primary' : 'btn-outline-primary'}" do %>
12
+ 7 Days
13
+ <% end %>
14
+ <%= link_to deprecations_errors_path(days: 30), class: "btn btn-sm #{@days == 30 ? 'btn-primary' : 'btn-outline-primary'}" do %>
15
+ 30 Days
16
+ <% end %>
17
+ <%= link_to deprecations_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_count == 0 %>
24
+ <div class="text-center py-5">
25
+ <i class="bi bi-check-circle display-1 text-success mb-3"></i>
26
+ <h4 class="text-muted">No Deprecation Warnings Found</h4>
27
+ <p class="text-muted">
28
+ No deprecation warnings 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 deprecations are captured:</h6>
33
+ <ul class="mb-0">
34
+ <li>Breadcrumbs must be enabled (<code>enable_breadcrumbs = true</code>)</li>
35
+ <li>Rails deprecation warnings are automatically captured as breadcrumbs</li>
36
+ <li>Deprecations appear here when an error occurs during a request with deprecation warnings</li>
37
+ </ul>
38
+ </div>
39
+ </div>
40
+ </div>
41
+ <% else %>
42
+ <div class="row mb-4">
43
+ <div class="col-md-4">
44
+ <div class="card text-center">
45
+ <div class="card-body">
46
+ <div class="display-6 text-danger"><%= @unique_count %></div>
47
+ <small class="text-muted">Unique Warnings</small>
48
+ </div>
49
+ </div>
50
+ </div>
51
+ <div class="col-md-4">
52
+ <div class="card text-center">
53
+ <div class="card-body">
54
+ <div class="display-6 text-warning"><%= @total_count %></div>
55
+ <small class="text-muted">Total Occurrences</small>
56
+ </div>
57
+ </div>
58
+ </div>
59
+ <div class="col-md-4">
60
+ <div class="card text-center">
61
+ <div class="card-body">
62
+ <div class="display-6 text-info"><%= @affected_count %></div>
63
+ <small class="text-muted">Affected Errors</small>
64
+ </div>
65
+ </div>
66
+ </div>
67
+ </div>
68
+
69
+ <div class="card mb-4">
70
+ <div class="card-header bg-white d-flex justify-content-between align-items-center">
71
+ <h5 class="mb-0">
72
+ <i class="bi bi-exclamation-triangle text-danger me-2"></i>
73
+ All Deprecation Warnings
74
+ <span class="badge bg-danger"><%= @unique_count %></span>
75
+ </h5>
76
+ <small class="text-muted"><%== @pagy.info_tag %></small>
77
+ </div>
78
+ <div class="card-body p-0">
79
+ <div class="table-responsive">
80
+ <table class="table table-hover mb-0">
81
+ <thead class="table-light">
82
+ <tr>
83
+ <th>Warning</th>
84
+ <th width="250">Source</th>
85
+ <th width="120">Occurrences</th>
86
+ <th width="250">Errors</th>
87
+ <th width="140">Last Seen</th>
88
+ </tr>
89
+ </thead>
90
+ <tbody>
91
+ <% @deprecations.each do |dep| %>
92
+ <tr>
93
+ <td><code style="font-size: 0.85em;"><%= dep[:message] %></code></td>
94
+ <td><small class="text-muted"><%= dep[:source] %></small></td>
95
+ <td><span class="badge bg-warning text-dark"><%= dep[:count] %></span></td>
96
+ <td>
97
+ <% shown_ids = dep[:error_ids].first(5) %>
98
+ <% shown_ids.each_with_index do |eid, i| %>
99
+ <%= link_to "##{eid}", error_path(eid), class: "text-decoration-none" %><%= "," unless i == shown_ids.size - 1 %>
100
+ <% end %>
101
+ <% if dep[:error_ids].size > 5 %>
102
+ <small class="text-muted">+<%= dep[:error_ids].size - 5 %> more</small>
103
+ <% end %>
104
+ </td>
105
+ <td><%= local_time_ago(dep[:last_seen]) %></td>
106
+ </tr>
107
+ <% end %>
108
+ </tbody>
109
+ </table>
110
+ </div>
111
+ </div>
112
+ <div class="card-footer bg-white border-top d-flex justify-content-between align-items-center">
113
+ <div>
114
+ <small class="text-muted">
115
+ <i class="bi bi-lightbulb text-warning"></i> Fix deprecations before upgrading Rails to avoid breaking changes.
116
+ </small>
117
+ <small class="ms-3">
118
+ <a href="https://guides.rubyonrails.org/upgrading_ruby_on_rails.html" target="_blank" rel="noopener" class="text-decoration-none">
119
+ <i class="bi bi-book"></i> Rails Upgrade Guide <i class="bi bi-box-arrow-up-right" style="font-size: 0.7em;"></i>
120
+ </a>
121
+ </small>
122
+ </div>
123
+ <div>
124
+ <%== @pagy.series_nav(:bootstrap) if @pagy.pages > 1 %>
125
+ </div>
126
+ </div>
127
+ </div>
128
+ <% end %>
129
+ </div>
@@ -0,0 +1,134 @@
1
+ <% content_for :page_title, "N+1 Query Patterns" %>
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-arrow-repeat me-2"></i>
7
+ N+1 Query Patterns
8
+ </h1>
9
+
10
+ <div class="btn-group" role="group">
11
+ <%= link_to n_plus_one_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 n_plus_one_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 n_plus_one_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_count == 0 %>
24
+ <div class="text-center py-5">
25
+ <i class="bi bi-check-circle display-1 text-success mb-3"></i>
26
+ <h4 class="text-muted">No N+1 Query Patterns Found</h4>
27
+ <p class="text-muted">
28
+ No N+1 query patterns 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 N+1 detection works:</h6>
33
+ <ul class="mb-0">
34
+ <li>Breadcrumbs must be enabled (<code>enable_breadcrumbs = true</code>)</li>
35
+ <li>SQL queries are captured as breadcrumbs during requests that produce errors</li>
36
+ <li>Queries with the same shape appearing >= <code>n_plus_one_threshold</code> times are flagged</li>
37
+ <li>Default threshold is 3 repetitions</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-danger"><%= @unique_count %></div>
48
+ <small class="text-muted">Unique Patterns</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-warning"><%= @total_count %></div>
56
+ <small class="text-muted">Total Occurrences</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 text-info"><%= @affected_count %></div>
64
+ <small class="text-muted">Affected Errors</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-arrow-repeat text-danger me-2"></i>
74
+ All N+1 Query Patterns
75
+ <span class="badge bg-danger"><%= @unique_count %></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>Query Pattern</th>
85
+ <th width="120">Occurrences</th>
86
+ <th width="250">Errors</th>
87
+ <th width="120">Total Time</th>
88
+ <th width="140">Last Seen</th>
89
+ </tr>
90
+ </thead>
91
+ <tbody>
92
+ <% @patterns.each do |pattern| %>
93
+ <tr>
94
+ <td><code style="font-size: 0.85em;"><%= truncate(pattern[:sample_query], length: 200) %></code></td>
95
+ <td><span class="badge bg-warning text-dark"><%= pattern[:count] %></span></td>
96
+ <td>
97
+ <% shown_ids = pattern[:error_ids].first(5) %>
98
+ <% shown_ids.each_with_index do |eid, i| %>
99
+ <%= link_to "##{eid}", error_path(eid), class: "text-decoration-none" %><%= "," unless i == shown_ids.size - 1 %>
100
+ <% end %>
101
+ <% if pattern[:error_ids].size > 5 %>
102
+ <small class="text-muted">+<%= pattern[:error_ids].size - 5 %> more</small>
103
+ <% end %>
104
+ </td>
105
+ <td>
106
+ <span class="<%= pattern[:total_duration_ms] > 100 ? 'text-danger fw-bold' : '' %>">
107
+ <%= pattern[:total_duration_ms] %> ms
108
+ </span>
109
+ </td>
110
+ <td><%= local_time_ago(pattern[:last_seen]) %></td>
111
+ </tr>
112
+ <% end %>
113
+ </tbody>
114
+ </table>
115
+ </div>
116
+ </div>
117
+ <div class="card-footer bg-white border-top d-flex justify-content-between align-items-center">
118
+ <div>
119
+ <small class="text-muted">
120
+ <i class="bi bi-lightbulb text-warning"></i> Use <code>includes</code>, <code>preload</code>, or <code>eager_load</code> to fix N+1 queries.
121
+ </small>
122
+ <small class="ms-3">
123
+ <a href="https://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations" target="_blank" rel="noopener" class="text-decoration-none">
124
+ <i class="bi bi-book"></i> Rails Eager Loading Guide <i class="bi bi-box-arrow-up-right" style="font-size: 0.7em;"></i>
125
+ </a>
126
+ </small>
127
+ </div>
128
+ <div>
129
+ <%== @pagy.series_nav(:bootstrap) if @pagy.pages > 1 %>
130
+ </div>
131
+ </div>
132
+ </div>
133
+ <% end %>
134
+ </div>
@@ -86,6 +86,23 @@
86
86
  git_branch_strategy: { label: "Git Branch Strategy", description: "Branch resolution strategy", type: :symbol, show_if: :enable_source_code_integration }
87
87
  }
88
88
  },
89
+ "Breadcrumbs" => {
90
+ icon: "bi-signpost-2",
91
+ color: "warning",
92
+ settings: {
93
+ enable_breadcrumbs: { label: "Breadcrumbs", description: "Capture request activity trail", type: :boolean },
94
+ breadcrumb_buffer_size: { label: "Buffer Size", description: "Max breadcrumbs per request", type: :integer, show_if: :enable_breadcrumbs, unit: "events" },
95
+ enable_n_plus_one_detection: { label: "N+1 Detection", description: "Detect repeated query patterns in breadcrumbs", type: :boolean, show_if: :enable_breadcrumbs },
96
+ n_plus_one_threshold: { label: "N+1 Threshold", description: "Min repetitions to flag as N+1", type: :integer, show_if: :enable_n_plus_one_detection, unit: "queries" }
97
+ }
98
+ },
99
+ "System Health" => {
100
+ icon: "bi-heart-pulse",
101
+ color: "danger",
102
+ settings: {
103
+ enable_system_health: { label: "System Health Snapshot", description: "Capture GC, memory, threads, connection pool at error time", type: :boolean }
104
+ }
105
+ },
89
106
  "Enhanced Metrics" => {
90
107
  icon: "bi-speedometer",
91
108
  color: "secondary",