rails_error_dashboard 0.1.0 → 0.1.1

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 (73) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +257 -700
  3. data/app/controllers/rails_error_dashboard/application_controller.rb +18 -0
  4. data/app/controllers/rails_error_dashboard/errors_controller.rb +47 -4
  5. data/app/helpers/rails_error_dashboard/application_helper.rb +17 -0
  6. data/app/jobs/rails_error_dashboard/application_job.rb +19 -0
  7. data/app/jobs/rails_error_dashboard/async_error_logging_job.rb +48 -0
  8. data/app/jobs/rails_error_dashboard/baseline_alert_job.rb +263 -0
  9. data/app/jobs/rails_error_dashboard/discord_error_notification_job.rb +4 -8
  10. data/app/jobs/rails_error_dashboard/email_error_notification_job.rb +2 -1
  11. data/app/jobs/rails_error_dashboard/pagerduty_error_notification_job.rb +5 -5
  12. data/app/jobs/rails_error_dashboard/slack_error_notification_job.rb +10 -6
  13. data/app/jobs/rails_error_dashboard/webhook_error_notification_job.rb +5 -6
  14. data/app/mailers/rails_error_dashboard/application_mailer.rb +1 -1
  15. data/app/mailers/rails_error_dashboard/error_notification_mailer.rb +1 -1
  16. data/app/models/rails_error_dashboard/cascade_pattern.rb +74 -0
  17. data/app/models/rails_error_dashboard/error_baseline.rb +100 -0
  18. data/app/models/rails_error_dashboard/error_log.rb +326 -3
  19. data/app/models/rails_error_dashboard/error_occurrence.rb +49 -0
  20. data/app/views/layouts/rails_error_dashboard.html.erb +150 -9
  21. data/app/views/rails_error_dashboard/error_notification_mailer/error_alert.html.erb +3 -10
  22. data/app/views/rails_error_dashboard/error_notification_mailer/error_alert.text.erb +1 -2
  23. data/app/views/rails_error_dashboard/errors/_error_row.html.erb +76 -0
  24. data/app/views/rails_error_dashboard/errors/_pattern_insights.html.erb +209 -0
  25. data/app/views/rails_error_dashboard/errors/_stats.html.erb +34 -0
  26. data/app/views/rails_error_dashboard/errors/analytics.html.erb +19 -39
  27. data/app/views/rails_error_dashboard/errors/correlation.html.erb +373 -0
  28. data/app/views/rails_error_dashboard/errors/index.html.erb +215 -138
  29. data/app/views/rails_error_dashboard/errors/platform_comparison.html.erb +388 -0
  30. data/app/views/rails_error_dashboard/errors/show.html.erb +428 -11
  31. data/config/routes.rb +2 -0
  32. data/db/migrate/20251225071314_add_optimized_indexes_to_error_logs.rb +66 -0
  33. data/db/migrate/20251225074653_remove_environment_from_error_logs.rb +26 -0
  34. data/db/migrate/20251225085859_add_enhanced_metrics_to_error_logs.rb +12 -0
  35. data/db/migrate/20251225093603_add_similarity_tracking_to_error_logs.rb +9 -0
  36. data/db/migrate/20251225100236_create_error_occurrences.rb +31 -0
  37. data/db/migrate/20251225101920_create_cascade_patterns.rb +33 -0
  38. data/db/migrate/20251225102500_create_error_baselines.rb +38 -0
  39. data/lib/generators/rails_error_dashboard/install/install_generator.rb +270 -1
  40. data/lib/generators/rails_error_dashboard/install/templates/initializer.rb +251 -37
  41. data/lib/generators/rails_error_dashboard/solid_queue/solid_queue_generator.rb +36 -0
  42. data/lib/generators/rails_error_dashboard/solid_queue/templates/queue.yml +55 -0
  43. data/lib/rails_error_dashboard/commands/log_error.rb +234 -7
  44. data/lib/rails_error_dashboard/commands/resolve_error.rb +16 -0
  45. data/lib/rails_error_dashboard/configuration.rb +82 -5
  46. data/lib/rails_error_dashboard/error_reporter.rb +15 -7
  47. data/lib/rails_error_dashboard/middleware/error_catcher.rb +17 -10
  48. data/lib/rails_error_dashboard/plugin.rb +6 -3
  49. data/lib/rails_error_dashboard/plugins/audit_log_plugin.rb +0 -1
  50. data/lib/rails_error_dashboard/plugins/jira_integration_plugin.rb +2 -3
  51. data/lib/rails_error_dashboard/plugins/metrics_plugin.rb +0 -2
  52. data/lib/rails_error_dashboard/queries/analytics_stats.rb +44 -6
  53. data/lib/rails_error_dashboard/queries/baseline_stats.rb +107 -0
  54. data/lib/rails_error_dashboard/queries/co_occurring_errors.rb +86 -0
  55. data/lib/rails_error_dashboard/queries/dashboard_stats.rb +134 -2
  56. data/lib/rails_error_dashboard/queries/error_cascades.rb +74 -0
  57. data/lib/rails_error_dashboard/queries/error_correlation.rb +375 -0
  58. data/lib/rails_error_dashboard/queries/errors_list.rb +52 -11
  59. data/lib/rails_error_dashboard/queries/filter_options.rb +0 -1
  60. data/lib/rails_error_dashboard/queries/platform_comparison.rb +254 -0
  61. data/lib/rails_error_dashboard/queries/similar_errors.rb +93 -0
  62. data/lib/rails_error_dashboard/services/baseline_alert_throttler.rb +88 -0
  63. data/lib/rails_error_dashboard/services/baseline_calculator.rb +269 -0
  64. data/lib/rails_error_dashboard/services/cascade_detector.rb +95 -0
  65. data/lib/rails_error_dashboard/services/pattern_detector.rb +268 -0
  66. data/lib/rails_error_dashboard/services/similarity_calculator.rb +144 -0
  67. data/lib/rails_error_dashboard/value_objects/error_context.rb +27 -1
  68. data/lib/rails_error_dashboard/version.rb +1 -1
  69. data/lib/rails_error_dashboard.rb +55 -7
  70. metadata +52 -9
  71. data/app/models/rails_error_dashboard/application_record.rb +0 -5
  72. data/lib/rails_error_dashboard/queries/developer_insights.rb +0 -277
  73. data/lib/rails_error_dashboard/queries/errors_list_v2.rb +0 -149
@@ -16,7 +16,7 @@
16
16
 
17
17
  <!-- Summary Stats -->
18
18
  <div class="row g-4 mb-4">
19
- <div class="col-md-3">
19
+ <div class="col-md-4">
20
20
  <div class="card stat-card border-primary">
21
21
  <div class="card-body">
22
22
  <div class="stat-label mb-2 text-primary">Total Errors</div>
@@ -24,7 +24,7 @@
24
24
  </div>
25
25
  </div>
26
26
  </div>
27
- <div class="col-md-3">
27
+ <div class="col-md-4">
28
28
  <div class="card stat-card border-danger">
29
29
  <div class="card-body">
30
30
  <div class="stat-label mb-2 text-danger">Unresolved</div>
@@ -32,7 +32,7 @@
32
32
  </div>
33
33
  </div>
34
34
  </div>
35
- <div class="col-md-3">
35
+ <div class="col-md-4">
36
36
  <div class="card stat-card border-success">
37
37
  <div class="card-body">
38
38
  <div class="stat-label mb-2 text-success">Resolution Rate</div>
@@ -40,15 +40,6 @@
40
40
  </div>
41
41
  </div>
42
42
  </div>
43
- <div class="col-md-3">
44
- <div class="card stat-card border-info">
45
- <div class="card-body">
46
- <div class="stat-label mb-2 text-info">Mobile Errors</div>
47
- <div class="stat-value text-info"><%= @mobile_errors %></div>
48
- <small class="text-muted">vs <%= @api_errors %> API</small>
49
- </div>
50
- </div>
51
- </div>
52
43
  </div>
53
44
 
54
45
  <!-- Error Trend Chart -->
@@ -68,37 +59,26 @@
68
59
  </div>
69
60
 
70
61
  <!-- Charts Row 1 -->
71
- <div class="row g-4 mb-4">
72
- <div class="col-md-6">
73
- <div class="card">
74
- <div class="card-header bg-white">
75
- <h5 class="mb-0"><i class="bi bi-phone"></i> Errors by Platform</h5>
76
- </div>
77
- <div class="card-body">
78
- <%= pie_chart @errors_by_platform,
79
- colors: ["#000000", "#3DDC84", "#3B82F6"],
80
- height: "300px",
81
- legend: "bottom",
82
- donut: true %>
83
- </div>
84
- </div>
85
- </div>
62
+ <% show_platform_chart = @errors_by_platform.size > 1 %>
86
63
 
87
- <div class="col-md-6">
88
- <div class="card">
89
- <div class="card-header bg-white">
90
- <h5 class="mb-0"><i class="bi bi-server"></i> Errors by Environment</h5>
91
- </div>
92
- <div class="card-body">
93
- <%= pie_chart @errors_by_environment,
94
- colors: ["#10B981", "#EF4444", "#F59E0B"],
95
- height: "300px",
96
- legend: "bottom",
97
- donut: true %>
64
+ <% if show_platform_chart %>
65
+ <div class="row g-4 mb-4">
66
+ <div class="col-md-12">
67
+ <div class="card">
68
+ <div class="card-header bg-white">
69
+ <h5 class="mb-0"><i class="bi bi-phone"></i> Errors by Platform</h5>
70
+ </div>
71
+ <div class="card-body">
72
+ <%= pie_chart @errors_by_platform,
73
+ colors: ["#000000", "#3DDC84", "#3B82F6"],
74
+ height: "300px",
75
+ legend: "bottom",
76
+ donut: true %>
77
+ </div>
98
78
  </div>
99
79
  </div>
100
80
  </div>
101
- </div>
81
+ <% end %>
102
82
 
103
83
  <!-- Charts Row 2 -->
104
84
  <div class="row g-4 mb-4">
@@ -0,0 +1,373 @@
1
+ <div class="container-fluid py-4">
2
+ <div class="d-flex justify-content-between align-items-center mb-4">
3
+ <h1 class="h3 mb-0">
4
+ <i class="bi bi-diagram-3 me-2"></i>
5
+ Error Correlation Analysis
6
+ </h1>
7
+
8
+ <div class="btn-group" role="group">
9
+ <%= link_to correlation_errors_path(days: 7), class: "btn btn-sm #{@days == 7 ? 'btn-primary' : 'btn-outline-primary'}" do %>
10
+ 7 Days
11
+ <% end %>
12
+ <%= link_to correlation_errors_path(days: 30), class: "btn btn-sm #{@days == 30 ? 'btn-primary' : 'btn-outline-primary'}" do %>
13
+ 30 Days
14
+ <% end %>
15
+ <%= link_to correlation_errors_path(days: 90), class: "btn btn-sm #{@days == 90 ? 'btn-primary' : 'btn-outline-primary'}" do %>
16
+ 90 Days
17
+ <% end %>
18
+ </div>
19
+ </div>
20
+
21
+ <!-- Period Comparison -->
22
+ <% if @period_comparison.present? %>
23
+ <div class="card mb-4">
24
+ <div class="card-header bg-white">
25
+ <h5 class="mb-0">
26
+ <i class="bi bi-graph-up-arrow me-2"></i>
27
+ Trend Analysis
28
+ </h5>
29
+ </div>
30
+ <div class="card-body">
31
+ <div class="row">
32
+ <div class="col-md-4">
33
+ <h6 class="text-muted">Current Period</h6>
34
+ <div class="display-6"><%= @period_comparison[:current_period][:count] %></div>
35
+ <small class="text-muted">
36
+ <%= @period_comparison[:current_period][:start].strftime("%b %d") %> - <%= @period_comparison[:current_period][:end].strftime("%b %d") %>
37
+ </small>
38
+ </div>
39
+ <div class="col-md-4">
40
+ <h6 class="text-muted">Previous Period</h6>
41
+ <div class="display-6"><%= @period_comparison[:previous_period][:count] %></div>
42
+ <small class="text-muted">
43
+ <%= @period_comparison[:previous_period][:start].strftime("%b %d") %> - <%= @period_comparison[:previous_period][:end].strftime("%b %d") %>
44
+ </small>
45
+ </div>
46
+ <div class="col-md-4">
47
+ <h6 class="text-muted">Change</h6>
48
+ <div class="display-6 <%= @period_comparison[:change] > 0 ? 'text-danger' : 'text-success' %>">
49
+ <%= @period_comparison[:change] > 0 ? '+' : '' %><%= @period_comparison[:change] %>
50
+ </div>
51
+ <div>
52
+ <span class="badge bg-<%= @period_comparison[:change] > 0 ? 'danger' : 'success' %> fs-6">
53
+ <%= @period_comparison[:change_percentage] > 0 ? '+' : '' %><%= @period_comparison[:change_percentage] %>%
54
+ </span>
55
+ <span class="ms-2 text-muted text-capitalize"><%= @period_comparison[:trend].to_s.gsub('_', ' ') %></span>
56
+ </div>
57
+ </div>
58
+ </div>
59
+ </div>
60
+ </div>
61
+ <% end %>
62
+
63
+ <!-- Problematic Releases -->
64
+ <% if @problematic_releases.present? && @problematic_releases.any? %>
65
+ <div class="card mb-4 border-danger">
66
+ <div class="card-header bg-danger text-white">
67
+ <h5 class="mb-0">
68
+ <i class="bi bi-exclamation-triangle-fill me-2"></i>
69
+ Problematic Releases
70
+ <span class="badge bg-white text-danger"><%= @problematic_releases.count %></span>
71
+ </h5>
72
+ <small>Versions with more than 2x the average error rate</small>
73
+ </div>
74
+ <div class="card-body">
75
+ <div class="table-responsive">
76
+ <table class="table table-hover">
77
+ <thead>
78
+ <tr>
79
+ <th>Version</th>
80
+ <th>Error Count</th>
81
+ <th>Deviation from Avg</th>
82
+ <th>Critical Errors</th>
83
+ <th>Unique Error Types</th>
84
+ <th>Platforms</th>
85
+ </tr>
86
+ </thead>
87
+ <tbody>
88
+ <% @problematic_releases.each do |release| %>
89
+ <tr>
90
+ <td><code><%= release[:version] %></code></td>
91
+ <td><strong class="text-danger"><%= release[:error_count] %></strong></td>
92
+ <td>
93
+ <span class="badge bg-danger">
94
+ +<%= release[:deviation_from_avg] %>%
95
+ </span>
96
+ </td>
97
+ <td><%= release[:critical_count] %></td>
98
+ <td><%= release[:error_types] %></td>
99
+ <td>
100
+ <% release[:platforms].each do |platform| %>
101
+ <span class="badge bg-secondary text-capitalize me-1"><%= platform %></span>
102
+ <% end %>
103
+ </td>
104
+ </tr>
105
+ <% end %>
106
+ </tbody>
107
+ </table>
108
+ </div>
109
+ </div>
110
+ </div>
111
+ <% end %>
112
+
113
+ <div class="row mb-4">
114
+ <!-- Errors by Version -->
115
+ <% if @errors_by_version.present? && @errors_by_version.any? %>
116
+ <div class="col-lg-6 mb-4">
117
+ <div class="card h-100">
118
+ <div class="card-header bg-white">
119
+ <h5 class="mb-0">
120
+ <i class="bi bi-tag me-2"></i>
121
+ Errors by App Version
122
+ </h5>
123
+ </div>
124
+ <div class="card-body">
125
+ <div class="table-responsive">
126
+ <table class="table table-sm table-hover">
127
+ <thead>
128
+ <tr>
129
+ <th>Version</th>
130
+ <th>Errors</th>
131
+ <th>Types</th>
132
+ <th>Critical</th>
133
+ </tr>
134
+ </thead>
135
+ <tbody>
136
+ <% @errors_by_version.sort_by { |_, v| -v[:count] }.first(10).each do |version, data| %>
137
+ <tr>
138
+ <td><code><%= version %></code></td>
139
+ <td><%= data[:count] %></td>
140
+ <td><%= data[:error_types] %></td>
141
+ <td>
142
+ <% if data[:critical_count] > 0 %>
143
+ <span class="badge bg-danger"><%= data[:critical_count] %></span>
144
+ <% else %>
145
+ <span class="text-muted">0</span>
146
+ <% end %>
147
+ </td>
148
+ </tr>
149
+ <% end %>
150
+ </tbody>
151
+ </table>
152
+ </div>
153
+ </div>
154
+ </div>
155
+ </div>
156
+ <% end %>
157
+
158
+ <!-- Errors by Git SHA -->
159
+ <% if @errors_by_git_sha.present? && @errors_by_git_sha.any? %>
160
+ <div class="col-lg-6 mb-4">
161
+ <div class="card h-100">
162
+ <div class="card-header bg-white">
163
+ <h5 class="mb-0">
164
+ <i class="bi bi-git me-2"></i>
165
+ Errors by Git SHA
166
+ </h5>
167
+ </div>
168
+ <div class="card-body">
169
+ <div class="table-responsive">
170
+ <table class="table table-sm table-hover">
171
+ <thead>
172
+ <tr>
173
+ <th>SHA</th>
174
+ <th>Errors</th>
175
+ <th>Types</th>
176
+ <th>Versions</th>
177
+ </tr>
178
+ </thead>
179
+ <tbody>
180
+ <% @errors_by_git_sha.sort_by { |_, v| -v[:count] }.first(10).each do |sha, data| %>
181
+ <tr>
182
+ <td><code class="small"><%= sha[0..7] %></code></td>
183
+ <td><%= data[:count] %></td>
184
+ <td><%= data[:error_types] %></td>
185
+ <td>
186
+ <% data[:app_versions].each do |version| %>
187
+ <code class="small"><%= version %></code>
188
+ <% end %>
189
+ </td>
190
+ </tr>
191
+ <% end %>
192
+ </tbody>
193
+ </table>
194
+ </div>
195
+ </div>
196
+ </div>
197
+ </div>
198
+ <% end %>
199
+ </div>
200
+
201
+ <!-- Multi-Error Users -->
202
+ <% if @multi_error_users.present? && @multi_error_users.any? %>
203
+ <div class="card mb-4">
204
+ <div class="card-header bg-white">
205
+ <h5 class="mb-0">
206
+ <i class="bi bi-people-fill me-2"></i>
207
+ Users Affected by Multiple Error Types
208
+ <span class="badge bg-info"><%= @multi_error_users.count %></span>
209
+ </h5>
210
+ <small class="text-muted">Users experiencing 2+ different error types</small>
211
+ </div>
212
+ <div class="card-body">
213
+ <div class="table-responsive">
214
+ <table class="table table-hover">
215
+ <thead>
216
+ <tr>
217
+ <th>User</th>
218
+ <th>Different Error Types</th>
219
+ <th>Total Errors</th>
220
+ <th>Error Types</th>
221
+ </tr>
222
+ </thead>
223
+ <tbody>
224
+ <% @multi_error_users.first(20).each do |user_data| %>
225
+ <tr>
226
+ <td><%= user_data[:user_email] %></td>
227
+ <td>
228
+ <span class="badge bg-warning text-dark">
229
+ <%= user_data[:error_type_count] %> types
230
+ </span>
231
+ </td>
232
+ <td><%= user_data[:total_errors] %></td>
233
+ <td>
234
+ <% user_data[:error_types].first(3).each do |error_type| %>
235
+ <code class="small me-1"><%= error_type %></code>
236
+ <% end %>
237
+ <% if user_data[:error_types].count > 3 %>
238
+ <span class="text-muted small">+<%= user_data[:error_types].count - 3 %> more</span>
239
+ <% end %>
240
+ </td>
241
+ </tr>
242
+ <% end %>
243
+ </tbody>
244
+ </table>
245
+ </div>
246
+ <% if @multi_error_users.count > 20 %>
247
+ <p class="text-muted small mb-0">
248
+ Showing 20 of <%= @multi_error_users.count %> users
249
+ </p>
250
+ <% end %>
251
+ </div>
252
+ </div>
253
+ <% end %>
254
+
255
+ <!-- Time-Correlated Errors -->
256
+ <% if @time_correlated_errors.present? && @time_correlated_errors.any? %>
257
+ <div class="card mb-4">
258
+ <div class="card-header bg-white">
259
+ <h5 class="mb-0">
260
+ <i class="bi bi-clock-history me-2"></i>
261
+ Time-Correlated Errors
262
+ <span class="badge bg-info"><%= @time_correlated_errors.count %></span>
263
+ </h5>
264
+ <small class="text-muted">Error types that occur at similar times of day</small>
265
+ </div>
266
+ <div class="card-body">
267
+ <div class="table-responsive">
268
+ <table class="table table-hover">
269
+ <thead>
270
+ <tr>
271
+ <th>Error Type A</th>
272
+ <th></th>
273
+ <th>Error Type B</th>
274
+ <th>Correlation</th>
275
+ <th>Strength</th>
276
+ </tr>
277
+ </thead>
278
+ <tbody>
279
+ <% @time_correlated_errors.first(15).each do |_, data| %>
280
+ <tr>
281
+ <td><code><%= data[:error_type_a] %></code></td>
282
+ <td class="text-center"><i class="bi bi-arrow-left-right"></i></td>
283
+ <td><code><%= data[:error_type_b] %></code></td>
284
+ <td>
285
+ <div class="progress" style="width: 100px; height: 20px;">
286
+ <div class="progress-bar bg-info" role="progressbar"
287
+ style="width: <%= (data[:correlation] * 100).round %>%">
288
+ <%= (data[:correlation] * 100).round %>%
289
+ </div>
290
+ </div>
291
+ </td>
292
+ <td>
293
+ <% case data[:strength] %>
294
+ <% when :strong %>
295
+ <span class="badge bg-success">Strong</span>
296
+ <% when :moderate %>
297
+ <span class="badge bg-info">Moderate</span>
298
+ <% else %>
299
+ <span class="badge bg-secondary">Weak</span>
300
+ <% end %>
301
+ </td>
302
+ </tr>
303
+ <% end %>
304
+ </tbody>
305
+ </table>
306
+ </div>
307
+ <% if @time_correlated_errors.count > 15 %>
308
+ <p class="text-muted small mb-0">
309
+ Showing 15 of <%= @time_correlated_errors.count %> correlated error pairs
310
+ </p>
311
+ <% end %>
312
+ </div>
313
+ </div>
314
+ <% end %>
315
+
316
+ <!-- Platform-Specific Errors -->
317
+ <% if @platform_specific_errors.present? && @platform_specific_errors.any? %>
318
+ <div class="card mb-4">
319
+ <div class="card-header bg-white">
320
+ <h5 class="mb-0">
321
+ <i class="bi bi-phone me-2"></i>
322
+ Platform-Specific vs Cross-Platform Errors
323
+ </h5>
324
+ </div>
325
+ <div class="card-body">
326
+ <div class="row">
327
+ <% @platform_specific_errors.each do |platform, errors| %>
328
+ <div class="col-md-6 mb-3">
329
+ <h6 class="text-capitalize"><%= platform %></h6>
330
+ <div class="list-group">
331
+ <% errors.each do |error_data| %>
332
+ <div class="list-group-item">
333
+ <div class="d-flex justify-content-between align-items-start">
334
+ <div>
335
+ <code class="small"><%= error_data[:error_type] %></code>
336
+ <div class="small text-muted mt-1">
337
+ <%= error_data[:count] %> occurrences
338
+ </div>
339
+ </div>
340
+ <div>
341
+ <% if error_data[:platform_specific] %>
342
+ <span class="badge bg-primary">Platform-Specific</span>
343
+ <% else %>
344
+ <span class="badge bg-secondary">Cross-Platform</span>
345
+ <div class="small text-muted mt-1">
346
+ Also on: <%= error_data[:also_on].join(', ') %>
347
+ </div>
348
+ <% end %>
349
+ </div>
350
+ </div>
351
+ </div>
352
+ <% end %>
353
+ </div>
354
+ </div>
355
+ <% end %>
356
+ </div>
357
+ </div>
358
+ </div>
359
+ <% end %>
360
+
361
+ <!-- Empty State -->
362
+ <% if @errors_by_version.blank? && @multi_error_users.blank? && @time_correlated_errors.blank? %>
363
+ <div class="alert alert-info">
364
+ <i class="bi bi-info-circle me-2"></i>
365
+ Not enough data available for correlation analysis. Correlation analysis requires:
366
+ <ul class="mb-0 mt-2">
367
+ <li>App version tracking for release correlation</li>
368
+ <li>User tracking for user correlation</li>
369
+ <li>Multiple error types for time correlation</li>
370
+ </ul>
371
+ </div>
372
+ <% end %>
373
+ </div>