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.
- checksums.yaml +4 -4
- data/README.md +257 -700
- data/app/controllers/rails_error_dashboard/application_controller.rb +18 -0
- data/app/controllers/rails_error_dashboard/errors_controller.rb +47 -4
- data/app/helpers/rails_error_dashboard/application_helper.rb +17 -0
- data/app/jobs/rails_error_dashboard/application_job.rb +19 -0
- data/app/jobs/rails_error_dashboard/async_error_logging_job.rb +48 -0
- data/app/jobs/rails_error_dashboard/baseline_alert_job.rb +263 -0
- data/app/jobs/rails_error_dashboard/discord_error_notification_job.rb +4 -8
- data/app/jobs/rails_error_dashboard/email_error_notification_job.rb +2 -1
- data/app/jobs/rails_error_dashboard/pagerduty_error_notification_job.rb +5 -5
- data/app/jobs/rails_error_dashboard/slack_error_notification_job.rb +10 -6
- data/app/jobs/rails_error_dashboard/webhook_error_notification_job.rb +5 -6
- data/app/mailers/rails_error_dashboard/application_mailer.rb +1 -1
- data/app/mailers/rails_error_dashboard/error_notification_mailer.rb +1 -1
- data/app/models/rails_error_dashboard/cascade_pattern.rb +74 -0
- data/app/models/rails_error_dashboard/error_baseline.rb +100 -0
- data/app/models/rails_error_dashboard/error_log.rb +326 -3
- data/app/models/rails_error_dashboard/error_occurrence.rb +49 -0
- data/app/views/layouts/rails_error_dashboard.html.erb +150 -9
- data/app/views/rails_error_dashboard/error_notification_mailer/error_alert.html.erb +3 -10
- data/app/views/rails_error_dashboard/error_notification_mailer/error_alert.text.erb +1 -2
- data/app/views/rails_error_dashboard/errors/_error_row.html.erb +76 -0
- data/app/views/rails_error_dashboard/errors/_pattern_insights.html.erb +209 -0
- data/app/views/rails_error_dashboard/errors/_stats.html.erb +34 -0
- data/app/views/rails_error_dashboard/errors/analytics.html.erb +19 -39
- data/app/views/rails_error_dashboard/errors/correlation.html.erb +373 -0
- data/app/views/rails_error_dashboard/errors/index.html.erb +215 -138
- data/app/views/rails_error_dashboard/errors/platform_comparison.html.erb +388 -0
- data/app/views/rails_error_dashboard/errors/show.html.erb +428 -11
- data/config/routes.rb +2 -0
- data/db/migrate/20251225071314_add_optimized_indexes_to_error_logs.rb +66 -0
- data/db/migrate/20251225074653_remove_environment_from_error_logs.rb +26 -0
- data/db/migrate/20251225085859_add_enhanced_metrics_to_error_logs.rb +12 -0
- data/db/migrate/20251225093603_add_similarity_tracking_to_error_logs.rb +9 -0
- data/db/migrate/20251225100236_create_error_occurrences.rb +31 -0
- data/db/migrate/20251225101920_create_cascade_patterns.rb +33 -0
- data/db/migrate/20251225102500_create_error_baselines.rb +38 -0
- data/lib/generators/rails_error_dashboard/install/install_generator.rb +270 -1
- data/lib/generators/rails_error_dashboard/install/templates/initializer.rb +251 -37
- data/lib/generators/rails_error_dashboard/solid_queue/solid_queue_generator.rb +36 -0
- data/lib/generators/rails_error_dashboard/solid_queue/templates/queue.yml +55 -0
- data/lib/rails_error_dashboard/commands/log_error.rb +234 -7
- data/lib/rails_error_dashboard/commands/resolve_error.rb +16 -0
- data/lib/rails_error_dashboard/configuration.rb +82 -5
- data/lib/rails_error_dashboard/error_reporter.rb +15 -7
- data/lib/rails_error_dashboard/middleware/error_catcher.rb +17 -10
- data/lib/rails_error_dashboard/plugin.rb +6 -3
- data/lib/rails_error_dashboard/plugins/audit_log_plugin.rb +0 -1
- data/lib/rails_error_dashboard/plugins/jira_integration_plugin.rb +2 -3
- data/lib/rails_error_dashboard/plugins/metrics_plugin.rb +0 -2
- data/lib/rails_error_dashboard/queries/analytics_stats.rb +44 -6
- data/lib/rails_error_dashboard/queries/baseline_stats.rb +107 -0
- data/lib/rails_error_dashboard/queries/co_occurring_errors.rb +86 -0
- data/lib/rails_error_dashboard/queries/dashboard_stats.rb +134 -2
- data/lib/rails_error_dashboard/queries/error_cascades.rb +74 -0
- data/lib/rails_error_dashboard/queries/error_correlation.rb +375 -0
- data/lib/rails_error_dashboard/queries/errors_list.rb +52 -11
- data/lib/rails_error_dashboard/queries/filter_options.rb +0 -1
- data/lib/rails_error_dashboard/queries/platform_comparison.rb +254 -0
- data/lib/rails_error_dashboard/queries/similar_errors.rb +93 -0
- data/lib/rails_error_dashboard/services/baseline_alert_throttler.rb +88 -0
- data/lib/rails_error_dashboard/services/baseline_calculator.rb +269 -0
- data/lib/rails_error_dashboard/services/cascade_detector.rb +95 -0
- data/lib/rails_error_dashboard/services/pattern_detector.rb +268 -0
- data/lib/rails_error_dashboard/services/similarity_calculator.rb +144 -0
- data/lib/rails_error_dashboard/value_objects/error_context.rb +27 -1
- data/lib/rails_error_dashboard/version.rb +1 -1
- data/lib/rails_error_dashboard.rb +55 -7
- metadata +52 -9
- data/app/models/rails_error_dashboard/application_record.rb +0 -5
- data/lib/rails_error_dashboard/queries/developer_insights.rb +0 -277
- 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-
|
|
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-
|
|
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-
|
|
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
|
-
|
|
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
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
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
|
-
|
|
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>
|