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
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.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anjan Jagirdar
@@ -79,6 +79,20 @@ dependencies:
79
79
  - - "~>"
80
80
  - !ruby/object:Gem::Version
81
81
  version: '0.21'
82
+ - !ruby/object:Gem::Dependency
83
+ name: turbo-rails
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '2.0'
89
+ type: :runtime
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '2.0'
82
96
  - !ruby/object:Gem::Dependency
83
97
  name: concurrent-ruby
84
98
  requirement: !ruby/object:Gem::Requirement
@@ -225,10 +239,11 @@ dependencies:
225
239
  - - "~>"
226
240
  - !ruby/object:Gem::Version
227
241
  version: '2.5'
228
- description: "⚠️ BETA: Rails Error Dashboard provides error tracking with a beautiful
229
- UI, multi-channel notifications (Slack, Email, Discord, PagerDuty), platform detection
230
- (iOS/Android/Web/API), analytics, and optional separate database support. Works
231
- with Rails 7.0-8.0. API may change before v1.0.0."
242
+ description: 'Own your errors. Own your stack. A fully open-source, self-hosted error
243
+ dashboard for solo founders, indie hackers, and small teams. Professional error
244
+ tracking with beautiful UI, multi-channel notifications (Slack, Email, Discord,
245
+ PagerDuty), platform detection (iOS/Android/Web/API), and analytics. 5-minute setup,
246
+ works out-of-the-box. Rails 7.0-8.1 compatible. ⚠️ BETA: API may change before v1.0.0.'
232
247
  email:
233
248
  - anjan.jagirdar@gmail.com
234
249
  executables: []
@@ -243,6 +258,8 @@ files:
243
258
  - app/controllers/rails_error_dashboard/errors_controller.rb
244
259
  - app/helpers/rails_error_dashboard/application_helper.rb
245
260
  - app/jobs/rails_error_dashboard/application_job.rb
261
+ - app/jobs/rails_error_dashboard/async_error_logging_job.rb
262
+ - app/jobs/rails_error_dashboard/baseline_alert_job.rb
246
263
  - app/jobs/rails_error_dashboard/discord_error_notification_job.rb
247
264
  - app/jobs/rails_error_dashboard/email_error_notification_job.rb
248
265
  - app/jobs/rails_error_dashboard/pagerduty_error_notification_job.rb
@@ -250,23 +267,39 @@ files:
250
267
  - app/jobs/rails_error_dashboard/webhook_error_notification_job.rb
251
268
  - app/mailers/rails_error_dashboard/application_mailer.rb
252
269
  - app/mailers/rails_error_dashboard/error_notification_mailer.rb
253
- - app/models/rails_error_dashboard/application_record.rb
270
+ - app/models/rails_error_dashboard/cascade_pattern.rb
271
+ - app/models/rails_error_dashboard/error_baseline.rb
254
272
  - app/models/rails_error_dashboard/error_log.rb
255
273
  - app/models/rails_error_dashboard/error_logs_record.rb
274
+ - app/models/rails_error_dashboard/error_occurrence.rb
256
275
  - app/views/layouts/rails_error_dashboard.html.erb
257
276
  - app/views/layouts/rails_error_dashboard/application.html.erb
258
277
  - app/views/rails_error_dashboard/error_notification_mailer/error_alert.html.erb
259
278
  - app/views/rails_error_dashboard/error_notification_mailer/error_alert.text.erb
279
+ - app/views/rails_error_dashboard/errors/_error_row.html.erb
280
+ - app/views/rails_error_dashboard/errors/_pattern_insights.html.erb
281
+ - app/views/rails_error_dashboard/errors/_stats.html.erb
260
282
  - app/views/rails_error_dashboard/errors/analytics.html.erb
283
+ - app/views/rails_error_dashboard/errors/correlation.html.erb
261
284
  - app/views/rails_error_dashboard/errors/index.html.erb
285
+ - app/views/rails_error_dashboard/errors/platform_comparison.html.erb
262
286
  - app/views/rails_error_dashboard/errors/show.html.erb
263
287
  - config/routes.rb
264
288
  - db/migrate/20251224000001_create_rails_error_dashboard_error_logs.rb
265
289
  - db/migrate/20251224081522_add_better_tracking_to_error_logs.rb
266
290
  - db/migrate/20251224101217_add_controller_action_to_error_logs.rb
291
+ - db/migrate/20251225071314_add_optimized_indexes_to_error_logs.rb
292
+ - db/migrate/20251225074653_remove_environment_from_error_logs.rb
293
+ - db/migrate/20251225085859_add_enhanced_metrics_to_error_logs.rb
294
+ - db/migrate/20251225093603_add_similarity_tracking_to_error_logs.rb
295
+ - db/migrate/20251225100236_create_error_occurrences.rb
296
+ - db/migrate/20251225101920_create_cascade_patterns.rb
297
+ - db/migrate/20251225102500_create_error_baselines.rb
267
298
  - lib/generators/rails_error_dashboard/install/install_generator.rb
268
299
  - lib/generators/rails_error_dashboard/install/templates/README
269
300
  - lib/generators/rails_error_dashboard/install/templates/initializer.rb
301
+ - lib/generators/rails_error_dashboard/solid_queue/solid_queue_generator.rb
302
+ - lib/generators/rails_error_dashboard/solid_queue/templates/queue.yml
270
303
  - lib/rails_error_dashboard.rb
271
304
  - lib/rails_error_dashboard/commands/batch_delete_errors.rb
272
305
  - lib/rails_error_dashboard/commands/batch_resolve_errors.rb
@@ -282,12 +315,21 @@ files:
282
315
  - lib/rails_error_dashboard/plugins/jira_integration_plugin.rb
283
316
  - lib/rails_error_dashboard/plugins/metrics_plugin.rb
284
317
  - lib/rails_error_dashboard/queries/analytics_stats.rb
318
+ - lib/rails_error_dashboard/queries/baseline_stats.rb
319
+ - lib/rails_error_dashboard/queries/co_occurring_errors.rb
285
320
  - lib/rails_error_dashboard/queries/dashboard_stats.rb
286
- - lib/rails_error_dashboard/queries/developer_insights.rb
321
+ - lib/rails_error_dashboard/queries/error_cascades.rb
322
+ - lib/rails_error_dashboard/queries/error_correlation.rb
287
323
  - lib/rails_error_dashboard/queries/errors_list.rb
288
- - lib/rails_error_dashboard/queries/errors_list_v2.rb
289
324
  - lib/rails_error_dashboard/queries/filter_options.rb
325
+ - lib/rails_error_dashboard/queries/platform_comparison.rb
326
+ - lib/rails_error_dashboard/queries/similar_errors.rb
327
+ - lib/rails_error_dashboard/services/baseline_alert_throttler.rb
328
+ - lib/rails_error_dashboard/services/baseline_calculator.rb
329
+ - lib/rails_error_dashboard/services/cascade_detector.rb
330
+ - lib/rails_error_dashboard/services/pattern_detector.rb
290
331
  - lib/rails_error_dashboard/services/platform_detector.rb
332
+ - lib/rails_error_dashboard/services/similarity_calculator.rb
291
333
  - lib/rails_error_dashboard/value_objects/error_context.rb
292
334
  - lib/rails_error_dashboard/version.rb
293
335
  - lib/tasks/rails_error_dashboard_tasks.rake
@@ -314,5 +356,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
314
356
  requirements: []
315
357
  rubygems_version: 3.7.2
316
358
  specification_version: 4
317
- summary: Beautiful error tracking dashboard for Rails applications (BETA)
359
+ summary: Self-hosted Rails error monitoring free, forever. Zero SaaS fees, zero
360
+ lock-in.
318
361
  test_files: []
@@ -1,5 +0,0 @@
1
- module RailsErrorDashboard
2
- class ApplicationRecord < ActiveRecord::Base
3
- self.abstract_class = true
4
- end
5
- end
@@ -1,277 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RailsErrorDashboard
4
- module Queries
5
- # Query: Developer-focused insights
6
- # Provides actionable metrics instead of environment breakdowns
7
- class DeveloperInsights
8
- def self.call(days = 7)
9
- new(days).call
10
- end
11
-
12
- def initialize(days = 7)
13
- @days = days
14
- @start_date = days.days.ago
15
- end
16
-
17
- def call
18
- {
19
- critical_metrics: critical_metrics,
20
- error_trends: error_trends,
21
- hot_spots: hot_spots,
22
- platform_health: platform_health,
23
- resolution_metrics: resolution_metrics,
24
- error_velocity: error_velocity,
25
- top_impacted_users: top_impacted_users,
26
- recurring_issues: recurring_issues
27
- }
28
- end
29
-
30
- private
31
-
32
- def base_query
33
- @base_query ||= ErrorLog.where("occurred_at >= ?", @start_date)
34
- end
35
-
36
- # Critical metrics developers care about
37
- def critical_metrics
38
- {
39
- total_errors: base_query.count,
40
- unresolved_count: base_query.unresolved.count,
41
- critical_unresolved: base_query.unresolved.where(
42
- error_type: critical_error_types
43
- ).count,
44
- new_error_types: new_error_types_count,
45
- recurring_errors: base_query.where("occurrence_count > ?", 5).count,
46
- errors_last_hour: ErrorLog.where("occurred_at >= ?", 1.hour.ago).count,
47
- errors_trending_up: errors_trending_up?
48
- }
49
- end
50
-
51
- # Error trends over time
52
- def error_trends
53
- {
54
- hourly: hourly_distribution,
55
- daily: daily_distribution,
56
- by_type_over_time: type_trends
57
- }
58
- end
59
-
60
- # Hot spots - where errors are concentrated
61
- def hot_spots
62
- {
63
- top_error_types: base_query.group(:error_type)
64
- .order("count_id DESC")
65
- .limit(10)
66
- .count,
67
- most_frequent: base_query.order(occurrence_count: :desc)
68
- .limit(10)
69
- .pluck(:error_type, :message, :occurrence_count)
70
- .map { |type, msg, count|
71
- { error_type: type, message: msg.truncate(100), count: count }
72
- },
73
- recent_spikes: detect_spikes
74
- }
75
- end
76
-
77
- # Platform health breakdown
78
- def platform_health
79
- platforms = base_query.group(:platform).count
80
-
81
- {
82
- by_platform: platforms,
83
- ios_stability: calculate_stability("iOS"),
84
- android_stability: calculate_stability("Android"),
85
- api_stability: calculate_stability("API")
86
- }
87
- end
88
-
89
- # Resolution metrics
90
- def resolution_metrics
91
- total = base_query.count
92
- resolved = base_query.resolved.count
93
-
94
- {
95
- resolution_rate: total.zero? ? 0 : (resolved.to_f / total * 100).round(2),
96
- average_resolution_time: average_resolution_time,
97
- unresolved_age: unresolved_age_distribution,
98
- resolved_today: ErrorLog.resolved
99
- .where("resolved_at >= ?", Time.current.beginning_of_day)
100
- .count
101
- }
102
- end
103
-
104
- # Error velocity - how fast errors are being introduced
105
- def error_velocity
106
- current_period = base_query.count
107
- previous_period = ErrorLog.where(
108
- "occurred_at >= ? AND occurred_at < ?",
109
- (@days * 2).days.ago,
110
- @start_date
111
- ).count
112
-
113
- change = current_period - previous_period
114
- change_percent = previous_period.zero? ? 0 : (change.to_f / previous_period * 100).round(2)
115
-
116
- {
117
- current_period_count: current_period,
118
- previous_period_count: previous_period,
119
- change: change,
120
- change_percent: change_percent,
121
- trend: change >= 0 ? "increasing" : "decreasing"
122
- }
123
- end
124
-
125
- # Users most impacted by errors
126
- def top_impacted_users
127
- base_query.where.not(user_id: nil)
128
- .group(:user_id)
129
- .order("count_id DESC")
130
- .limit(10)
131
- .count
132
- .transform_keys { |user_id| user_id || "Guest" }
133
- end
134
-
135
- # Recurring issues that keep coming back
136
- def recurring_issues
137
- base_query.where("occurrence_count > ?", 3)
138
- .where("(last_seen_at - first_seen_at) > ?", 1.day.to_i)
139
- .order(occurrence_count: :desc)
140
- .limit(10)
141
- .pluck(:error_type, :message, :occurrence_count, :first_seen_at, :last_seen_at)
142
- .map { |type, msg, count, first, last|
143
- {
144
- error_type: type,
145
- message: msg.truncate(100),
146
- occurrence_count: count,
147
- duration_days: ((last - first) / 1.day).round(1),
148
- first_seen: first,
149
- last_seen: last
150
- }
151
- }
152
- end
153
-
154
- # Helper methods
155
-
156
- def critical_error_types
157
- %w[
158
- SecurityError
159
- NoMemoryError
160
- SystemStackError
161
- SignalException
162
- ActiveRecord::StatementInvalid
163
- ]
164
- end
165
-
166
- def new_error_types_count
167
- # Error types that first appeared in this period
168
- current_types = base_query.distinct.pluck(:error_type)
169
- all_time_types = ErrorLog.where("occurred_at < ?", @start_date)
170
- .distinct
171
- .pluck(:error_type)
172
-
173
- (current_types - all_time_types).count
174
- end
175
-
176
- def errors_trending_up?
177
- last_24h = ErrorLog.where("occurred_at >= ?", 24.hours.ago).count
178
- prev_24h = ErrorLog.where("occurred_at >= ? AND occurred_at < ?",
179
- 48.hours.ago, 24.hours.ago).count
180
-
181
- last_24h > prev_24h
182
- end
183
-
184
- def hourly_distribution
185
- base_query.group("EXTRACT(HOUR FROM occurred_at)")
186
- .order("EXTRACT(HOUR FROM occurred_at)")
187
- .count
188
- end
189
-
190
- def daily_distribution
191
- base_query.group("DATE(occurred_at)")
192
- .order("DATE(occurred_at)")
193
- .count
194
- end
195
-
196
- def type_trends
197
- # Get top 5 error types and their trend over days
198
- top_types = base_query.group(:error_type)
199
- .order("count_id DESC")
200
- .limit(5)
201
- .pluck(:error_type)
202
-
203
- trends = {}
204
- top_types.each do |error_type|
205
- trends[error_type] = base_query.where(error_type: error_type)
206
- .group("DATE(occurred_at)")
207
- .count
208
- end
209
-
210
- trends
211
- end
212
-
213
- def calculate_stability(platform)
214
- total = base_query.where(platform: platform).count
215
- return 100.0 if total.zero?
216
-
217
- # Stability = 100 - (errors per 1000 requests ratio)
218
- # Simplified: just show error rate
219
- 100.0 - [ (total.to_f / 10), 100.0 ].min
220
- end
221
-
222
- def average_resolution_time
223
- resolved_errors = base_query.resolved
224
- .where.not(resolved_at: nil)
225
-
226
- return 0 if resolved_errors.count.zero?
227
-
228
- total_time = resolved_errors.sum { |error|
229
- (error.resolved_at - error.occurred_at).to_i
230
- }
231
-
232
- average_seconds = total_time / resolved_errors.count
233
- (average_seconds / 3600.0).round(2) # Convert to hours
234
- end
235
-
236
- def unresolved_age_distribution
237
- unresolved = base_query.unresolved
238
-
239
- {
240
- under_1_hour: unresolved.where("occurred_at >= ?", 1.hour.ago).count,
241
- "1_24_hours": unresolved.where("occurred_at >= ? AND occurred_at < ?",
242
- 24.hours.ago, 1.hour.ago).count,
243
- "1_7_days": unresolved.where("occurred_at >= ? AND occurred_at < ?",
244
- 7.days.ago, 24.hours.ago).count,
245
- over_7_days: unresolved.where("occurred_at < ?", 7.days.ago).count
246
- }
247
- end
248
-
249
- def detect_spikes
250
- # Find error types that suddenly spiked in last 24 hours
251
- last_24h = ErrorLog.where("occurred_at >= ?", 24.hours.ago)
252
- prev_24h = ErrorLog.where("occurred_at >= ? AND occurred_at < ?",
253
- 48.hours.ago, 24.hours.ago)
254
-
255
- current_counts = last_24h.group(:error_type).count
256
- previous_counts = prev_24h.group(:error_type).count
257
-
258
- spikes = []
259
- current_counts.each do |error_type, current_count|
260
- previous_count = previous_counts[error_type] || 0
261
-
262
- # Spike if current is > 2x previous AND at least 5 errors
263
- if current_count > previous_count * 2 && current_count >= 5
264
- spikes << {
265
- error_type: error_type,
266
- current_count: current_count,
267
- previous_count: previous_count,
268
- increase_percent: previous_count.zero? ? 999 : ((current_count - previous_count).to_f / previous_count * 100).round(0)
269
- }
270
- end
271
- end
272
-
273
- spikes.sort_by { |s| -s[:increase_percent] }.first(5)
274
- end
275
- end
276
- end
277
- end
@@ -1,149 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RailsErrorDashboard
4
- module Queries
5
- # Query: Fetch errors with improved filtering for developers
6
- # Removes environment filtering (each env has separate DB)
7
- # Adds time-based, severity, and frequency filtering
8
- class ErrorsListV2
9
- def self.call(filters = {})
10
- new(filters).call
11
- end
12
-
13
- def initialize(filters = {})
14
- @filters = filters
15
- end
16
-
17
- def call
18
- query = ErrorLog.order(occurred_at: :desc)
19
- # Only eager load user if User model exists
20
- query = query.includes(:user) if defined?(::User)
21
- query = apply_filters(query)
22
- query
23
- end
24
-
25
- private
26
-
27
- def apply_filters(query)
28
- query = filter_by_timeframe(query)
29
- query = filter_by_error_type(query)
30
- query = filter_by_resolved(query)
31
- query = filter_by_platform(query)
32
- query = filter_by_severity(query)
33
- query = filter_by_frequency(query)
34
- query = filter_by_search(query)
35
- query
36
- end
37
-
38
- # Time-based filtering (more useful than environment)
39
- def filter_by_timeframe(query)
40
- return query unless @filters[:timeframe].present?
41
-
42
- case @filters[:timeframe]
43
- when "last_hour"
44
- query.where("occurred_at >= ?", 1.hour.ago)
45
- when "today"
46
- query.where("occurred_at >= ?", Time.current.beginning_of_day)
47
- when "yesterday"
48
- query.where("occurred_at >= ? AND occurred_at < ?",
49
- 1.day.ago.beginning_of_day,
50
- Time.current.beginning_of_day)
51
- when "last_7_days"
52
- query.where("occurred_at >= ?", 7.days.ago)
53
- when "last_30_days"
54
- query.where("occurred_at >= ?", 30.days.ago)
55
- when "last_90_days"
56
- query.where("occurred_at >= ?", 90.days.ago)
57
- else
58
- query
59
- end
60
- end
61
-
62
- def filter_by_error_type(query)
63
- return query unless @filters[:error_type].present?
64
-
65
- query.where(error_type: @filters[:error_type])
66
- end
67
-
68
- def filter_by_resolved(query)
69
- return query unless @filters[:unresolved] == "true" || @filters[:unresolved] == true
70
-
71
- query.unresolved
72
- end
73
-
74
- def filter_by_platform(query)
75
- return query unless @filters[:platform].present?
76
-
77
- query.where(platform: @filters[:platform])
78
- end
79
-
80
- # Filter by severity (based on error type)
81
- def filter_by_severity(query)
82
- return query unless @filters[:severity].present?
83
-
84
- case @filters[:severity]
85
- when "critical"
86
- # Security, data loss, crashes
87
- critical_errors = [
88
- "SecurityError",
89
- "ActiveRecord::RecordInvalid",
90
- "NoMemoryError",
91
- "SystemStackError",
92
- "SignalException"
93
- ]
94
- query.where(error_type: critical_errors)
95
- when "high"
96
- # Business logic failures
97
- high_errors = [
98
- "ActiveRecord::RecordNotFound",
99
- "ArgumentError",
100
- "TypeError",
101
- "NoMethodError"
102
- ]
103
- query.where(error_type: high_errors)
104
- when "medium"
105
- # Validation, timeouts
106
- medium_errors = [
107
- "ActiveRecord::RecordInvalid",
108
- "Timeout::Error",
109
- "Net::ReadTimeout"
110
- ]
111
- query.where(error_type: medium_errors)
112
- else
113
- query
114
- end
115
- end
116
-
117
- # Filter by frequency (how often error occurs)
118
- def filter_by_frequency(query)
119
- return query unless @filters[:frequency].present?
120
-
121
- case @filters[:frequency]
122
- when "high"
123
- # Occurs more than 10 times
124
- query.where("occurrence_count > ?", 10)
125
- when "medium"
126
- # Occurs 3-10 times
127
- query.where("occurrence_count >= ? AND occurrence_count <= ?", 3, 10)
128
- when "low"
129
- # Occurs 1-2 times
130
- query.where("occurrence_count <= ?", 2)
131
- when "recurring"
132
- # Seen multiple times over more than 1 hour
133
- query.where("occurrence_count > ? AND (last_seen_at - first_seen_at) > ?",
134
- 1, 1.hour.to_i)
135
- else
136
- query
137
- end
138
- end
139
-
140
- def filter_by_search(query)
141
- return query unless @filters[:search].present?
142
-
143
- search_term = "%#{@filters[:search]}%"
144
- query.where("message ILIKE ? OR error_type ILIKE ? OR backtrace ILIKE ?",
145
- search_term, search_term, search_term)
146
- end
147
- end
148
- end
149
- end