rails_error_dashboard 0.1.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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +858 -0
- data/Rakefile +3 -0
- data/app/assets/stylesheets/rails_error_dashboard/application.css +15 -0
- data/app/controllers/rails_error_dashboard/application_controller.rb +12 -0
- data/app/controllers/rails_error_dashboard/errors_controller.rb +123 -0
- data/app/helpers/rails_error_dashboard/application_helper.rb +4 -0
- data/app/jobs/rails_error_dashboard/application_job.rb +4 -0
- data/app/jobs/rails_error_dashboard/discord_error_notification_job.rb +116 -0
- data/app/jobs/rails_error_dashboard/email_error_notification_job.rb +19 -0
- data/app/jobs/rails_error_dashboard/pagerduty_error_notification_job.rb +105 -0
- data/app/jobs/rails_error_dashboard/slack_error_notification_job.rb +166 -0
- data/app/jobs/rails_error_dashboard/webhook_error_notification_job.rb +108 -0
- data/app/mailers/rails_error_dashboard/application_mailer.rb +8 -0
- data/app/mailers/rails_error_dashboard/error_notification_mailer.rb +27 -0
- data/app/models/rails_error_dashboard/application_record.rb +5 -0
- data/app/models/rails_error_dashboard/error_log.rb +185 -0
- data/app/models/rails_error_dashboard/error_logs_record.rb +34 -0
- data/app/views/layouts/rails_error_dashboard/application.html.erb +17 -0
- data/app/views/layouts/rails_error_dashboard.html.erb +351 -0
- data/app/views/rails_error_dashboard/error_notification_mailer/error_alert.html.erb +200 -0
- data/app/views/rails_error_dashboard/error_notification_mailer/error_alert.text.erb +32 -0
- data/app/views/rails_error_dashboard/errors/analytics.html.erb +237 -0
- data/app/views/rails_error_dashboard/errors/index.html.erb +334 -0
- data/app/views/rails_error_dashboard/errors/show.html.erb +294 -0
- data/config/routes.rb +13 -0
- data/db/migrate/20251224000001_create_rails_error_dashboard_error_logs.rb +40 -0
- data/db/migrate/20251224081522_add_better_tracking_to_error_logs.rb +13 -0
- data/db/migrate/20251224101217_add_controller_action_to_error_logs.rb +10 -0
- data/lib/generators/rails_error_dashboard/install/install_generator.rb +27 -0
- data/lib/generators/rails_error_dashboard/install/templates/README +33 -0
- data/lib/generators/rails_error_dashboard/install/templates/initializer.rb +64 -0
- data/lib/rails_error_dashboard/commands/batch_delete_errors.rb +40 -0
- data/lib/rails_error_dashboard/commands/batch_resolve_errors.rb +60 -0
- data/lib/rails_error_dashboard/commands/log_error.rb +134 -0
- data/lib/rails_error_dashboard/commands/resolve_error.rb +35 -0
- data/lib/rails_error_dashboard/configuration.rb +83 -0
- data/lib/rails_error_dashboard/engine.rb +20 -0
- data/lib/rails_error_dashboard/error_reporter.rb +35 -0
- data/lib/rails_error_dashboard/middleware/error_catcher.rb +41 -0
- data/lib/rails_error_dashboard/plugin.rb +98 -0
- data/lib/rails_error_dashboard/plugin_registry.rb +88 -0
- data/lib/rails_error_dashboard/plugins/audit_log_plugin.rb +96 -0
- data/lib/rails_error_dashboard/plugins/jira_integration_plugin.rb +122 -0
- data/lib/rails_error_dashboard/plugins/metrics_plugin.rb +78 -0
- data/lib/rails_error_dashboard/queries/analytics_stats.rb +108 -0
- data/lib/rails_error_dashboard/queries/dashboard_stats.rb +37 -0
- data/lib/rails_error_dashboard/queries/developer_insights.rb +277 -0
- data/lib/rails_error_dashboard/queries/errors_list.rb +66 -0
- data/lib/rails_error_dashboard/queries/errors_list_v2.rb +149 -0
- data/lib/rails_error_dashboard/queries/filter_options.rb +21 -0
- data/lib/rails_error_dashboard/services/platform_detector.rb +41 -0
- data/lib/rails_error_dashboard/value_objects/error_context.rb +148 -0
- data/lib/rails_error_dashboard/version.rb +3 -0
- data/lib/rails_error_dashboard.rb +60 -0
- data/lib/tasks/rails_error_dashboard_tasks.rake +4 -0
- metadata +318 -0
data/README.md
ADDED
|
@@ -0,0 +1,858 @@
|
|
|
1
|
+
# Rails Error Dashboard
|
|
2
|
+
|
|
3
|
+
[](https://badge.fury.io/rb/rails_error_dashboard)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
[](https://github.com/AnjanJ/rails_error_dashboard/actions)
|
|
6
|
+
|
|
7
|
+
> **⚠️ BETA SOFTWARE**: This gem is currently in beta and under active development. While functional and tested, the API and features may change before v1.0.0. Use in production at your own discretion.
|
|
8
|
+
|
|
9
|
+
> **A beautiful error tracking dashboard for Rails applications and their frontends**
|
|
10
|
+
|
|
11
|
+
Rails Error Dashboard provides a complete error tracking and alerting solution for Rails backends AND frontend/mobile apps (React, React Native, Vue, Angular, Flutter, etc.). Features include: modern UI, multi-channel notifications (Slack + Email), real-time analytics, platform detection (iOS/Android/Web/API), and optional separate database support. Built with Rails 7+ error reporting and following Service Objects + CQRS principles.
|
|
12
|
+
|
|
13
|
+
**Tested on**: Rails 7.0, 7.1, 7.2, 8.0 | Ruby 3.2, 3.3+
|
|
14
|
+
|
|
15
|
+

|
|
16
|
+
|
|
17
|
+
## 📖 Table of Contents
|
|
18
|
+
|
|
19
|
+
- [Features](#-features)
|
|
20
|
+
- [Installation](#-installation)
|
|
21
|
+
- [Configuration](#️-configuration)
|
|
22
|
+
- [Usage](#-usage)
|
|
23
|
+
- [Automatic Error Tracking](#automatic-error-tracking)
|
|
24
|
+
- [Manual Error Logging](#manual-error-logging)
|
|
25
|
+
- [Frontend & Mobile Error Reporting](#frontend--mobile-error-reporting)
|
|
26
|
+
- [Optional Separate Database](#️-optional-separate-database)
|
|
27
|
+
- [Advanced Features](#-advanced-features)
|
|
28
|
+
- [Notification System](#-notification-system)
|
|
29
|
+
- [Platform Detection](#platform-detection)
|
|
30
|
+
- [Architecture Details](#-architecture-details)
|
|
31
|
+
- [Documentation](#-documentation)
|
|
32
|
+
- [Contributing](#-contributing)
|
|
33
|
+
- [License](#-license)
|
|
34
|
+
|
|
35
|
+
## ✨ Features
|
|
36
|
+
|
|
37
|
+
### 🎯 Complete Error Tracking
|
|
38
|
+
- **Automatic error capture** from Rails controllers, jobs, services, and middleware
|
|
39
|
+
- **Frontend & mobile support** - React, React Native, Vue, Angular, Flutter, and more
|
|
40
|
+
- **Platform detection** (iOS/Android/Web/API) using user agent parsing
|
|
41
|
+
- **User context tracking** with optional user associations
|
|
42
|
+
- **Request context** including URL, params, IP address, component/screen
|
|
43
|
+
- **Full stack traces** for debugging (Ruby + JavaScript)
|
|
44
|
+
|
|
45
|
+
### 📊 Beautiful Dashboard
|
|
46
|
+
- **Modern UI** with Bootstrap 5
|
|
47
|
+
- **Dark/Light mode** with theme switcher
|
|
48
|
+
- **Responsive design** for mobile and desktop
|
|
49
|
+
- **Real-time statistics** and error counts
|
|
50
|
+
- **Search and filtering** by type, platform, environment
|
|
51
|
+
- **Fast pagination** with Pagy (40x faster than Kaminari)
|
|
52
|
+
|
|
53
|
+
### 📈 Analytics & Insights
|
|
54
|
+
- **Time-series charts** showing error trends
|
|
55
|
+
- **Breakdown by type**, platform, and environment
|
|
56
|
+
- **Resolution rate tracking**
|
|
57
|
+
- **Top affected users**
|
|
58
|
+
- **Mobile vs API analysis**
|
|
59
|
+
- **Customizable date ranges** (7, 14, 30, 90 days)
|
|
60
|
+
|
|
61
|
+
### ✅ Resolution Tracking
|
|
62
|
+
- Mark errors as resolved
|
|
63
|
+
- Add resolution comments
|
|
64
|
+
- Link to PRs, commits, or issues
|
|
65
|
+
- Track resolver name and timestamp
|
|
66
|
+
- View related errors
|
|
67
|
+
- **Batch operations** - resolve or delete multiple errors at once
|
|
68
|
+
|
|
69
|
+
### 🚨 Multi-Channel Alerting
|
|
70
|
+
- **5 notification backends**: Email, Slack, Discord, PagerDuty, Webhooks
|
|
71
|
+
- **Slack notifications** with beautifully formatted messages
|
|
72
|
+
- **Discord notifications** with rich embeds and color-coded severity
|
|
73
|
+
- **PagerDuty integration** for critical errors (on-call escalation)
|
|
74
|
+
- **Custom webhooks** for integration with any monitoring service
|
|
75
|
+
- **Email alerts** with HTML templates to multiple recipients
|
|
76
|
+
- **Instant notifications** when errors occur (async background jobs)
|
|
77
|
+
- **Rich context** including user, platform, environment, stack trace
|
|
78
|
+
- **Direct links** to view full error details in dashboard
|
|
79
|
+
- **Customizable** - enable/disable channels independently
|
|
80
|
+
|
|
81
|
+
See [NOTIFICATION_CONFIGURATION.md](NOTIFICATION_CONFIGURATION.md) for detailed setup.
|
|
82
|
+
|
|
83
|
+
### 🔒 Security & Configuration
|
|
84
|
+
- **HTTP Basic Auth** (configurable)
|
|
85
|
+
- **Environment-based settings**
|
|
86
|
+
- **Optional separate database** for performance isolation
|
|
87
|
+
|
|
88
|
+
### 🔌 Plugin System
|
|
89
|
+
- **Extensible architecture** for custom integrations
|
|
90
|
+
- **Event hooks** throughout error lifecycle
|
|
91
|
+
- **Built-in examples**: Metrics tracking, Audit logging, Jira integration
|
|
92
|
+
- **Easy to create** custom plugins for any service
|
|
93
|
+
- **Safe execution** - plugin errors don't break the app
|
|
94
|
+
|
|
95
|
+
Common plugin use cases:
|
|
96
|
+
- 📊 Send metrics to StatsD, Datadog, Prometheus
|
|
97
|
+
- 🎫 Create tickets in Jira, Linear, GitHub Issues
|
|
98
|
+
- 📝 Log audit trails for compliance
|
|
99
|
+
- 📢 Send custom notifications
|
|
100
|
+
- 💾 Archive errors to data warehouses
|
|
101
|
+
|
|
102
|
+
See [PLUGIN_SYSTEM_GUIDE.md](PLUGIN_SYSTEM_GUIDE.md) for detailed documentation.
|
|
103
|
+
|
|
104
|
+
### 🏗️ Architecture
|
|
105
|
+
Built with **Service Objects + CQRS Principles**:
|
|
106
|
+
- **Commands**: LogError, ResolveError, BatchResolveErrors, BatchDeleteErrors (write operations)
|
|
107
|
+
- **Queries**: ErrorsList, DashboardStats, AnalyticsStats (read operations)
|
|
108
|
+
- **Value Objects**: ErrorContext (immutable data)
|
|
109
|
+
- **Services**: PlatformDetector (business logic)
|
|
110
|
+
- **Plugins**: Extensible event-driven architecture
|
|
111
|
+
|
|
112
|
+
### ✅ Multi-Version Testing
|
|
113
|
+
- **Rails Support**: 7.0, 7.1, 7.2, 8.0
|
|
114
|
+
- **Ruby Support**: 3.2, 3.3+
|
|
115
|
+
- **CI/CD**: 8 version combinations tested automatically
|
|
116
|
+
- **Compatibility**: 100% feature parity across all versions
|
|
117
|
+
|
|
118
|
+
See [MULTI_VERSION_TESTING.md](MULTI_VERSION_TESTING.md) for testing guide.
|
|
119
|
+
|
|
120
|
+
## 🧪 Implementation Status
|
|
121
|
+
|
|
122
|
+
### ✅ Phase 1: Core Error Tracking (COMPLETE & TESTED)
|
|
123
|
+
- Error logging and deduplication
|
|
124
|
+
- Automatic tracking via middleware
|
|
125
|
+
- Controller/action context
|
|
126
|
+
- Request metadata capture
|
|
127
|
+
- User tracking
|
|
128
|
+
- Dashboard UI with search/filter
|
|
129
|
+
- Stack trace viewer
|
|
130
|
+
- Mark errors as resolved
|
|
131
|
+
- **Test Coverage**: 111 RSpec examples passing
|
|
132
|
+
|
|
133
|
+
### ✅ Phase 2: Multi-Channel Notifications (COMPLETE)
|
|
134
|
+
- Slack integration
|
|
135
|
+
- Email notifications
|
|
136
|
+
- Discord webhooks
|
|
137
|
+
- PagerDuty integration
|
|
138
|
+
- Custom webhooks
|
|
139
|
+
- **Test Coverage**: Needs additional tests (functional but not extensively tested)
|
|
140
|
+
|
|
141
|
+
### ✅ Phase 3: Batch Operations (COMPLETE)
|
|
142
|
+
- Bulk resolve errors
|
|
143
|
+
- Bulk delete errors
|
|
144
|
+
- API endpoints
|
|
145
|
+
- **Test Coverage**: Needs additional tests (functional but not extensively tested)
|
|
146
|
+
|
|
147
|
+
### ✅ Phase 4: Analytics & Insights (COMPLETE)
|
|
148
|
+
- Error trends over time
|
|
149
|
+
- Platform breakdown
|
|
150
|
+
- Developer insights
|
|
151
|
+
- Dashboard statistics
|
|
152
|
+
- **Test Coverage**: Needs additional tests (functional but not extensively tested)
|
|
153
|
+
|
|
154
|
+
### ✅ Phase 5: Plugin System (COMPLETE)
|
|
155
|
+
- Plugin architecture
|
|
156
|
+
- Event hooks
|
|
157
|
+
- Built-in plugins (Jira, Metrics, Audit Log)
|
|
158
|
+
- **Test Coverage**: Needs additional tests (functional but not extensively tested)
|
|
159
|
+
|
|
160
|
+
### 🔜 What's Next
|
|
161
|
+
- Expand test coverage for Phases 2-5
|
|
162
|
+
- Real-world production testing
|
|
163
|
+
- Performance optimizations
|
|
164
|
+
- Additional integrations based on feedback
|
|
165
|
+
|
|
166
|
+
## 📦 Installation
|
|
167
|
+
|
|
168
|
+
### 1. Add to Gemfile
|
|
169
|
+
|
|
170
|
+
```ruby
|
|
171
|
+
gem 'rails_error_dashboard'
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### 2. Install the gem
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
bundle install
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### 3. Run the installer
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
rails generate rails_error_dashboard:install
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
This will:
|
|
187
|
+
- Create `config/initializers/rails_error_dashboard.rb`
|
|
188
|
+
- Copy migrations to your app
|
|
189
|
+
- Mount the engine at `/error_dashboard`
|
|
190
|
+
|
|
191
|
+
### 4. Run migrations
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
rails db:migrate
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### 5. (Optional) Configure queue for notifications
|
|
198
|
+
|
|
199
|
+
If you're using **Sidekiq**, add the notification queue to your config:
|
|
200
|
+
|
|
201
|
+
```yaml
|
|
202
|
+
# config/sidekiq.yml
|
|
203
|
+
:queues:
|
|
204
|
+
- error_notifications
|
|
205
|
+
- default
|
|
206
|
+
- mailers
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
If you're using **Solid Queue** (Rails 8.1+), add to your config:
|
|
210
|
+
|
|
211
|
+
```yaml
|
|
212
|
+
# config/queue.yml
|
|
213
|
+
workers:
|
|
214
|
+
- queues: error_notifications
|
|
215
|
+
threads: 3
|
|
216
|
+
processes: 1
|
|
217
|
+
- queues: default
|
|
218
|
+
threads: 5
|
|
219
|
+
processes: 1
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
**Note:** If you're using the default `async` adapter or other backends, no additional configuration is needed. The gem works with all ActiveJob adapters out of the box.
|
|
223
|
+
|
|
224
|
+
### 6. Visit the dashboard
|
|
225
|
+
|
|
226
|
+
Start your server and visit:
|
|
227
|
+
```
|
|
228
|
+
http://localhost:3000/error_dashboard
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
**Default credentials** (change in the initializer):
|
|
232
|
+
- Username: `admin`
|
|
233
|
+
- Password: `password`
|
|
234
|
+
|
|
235
|
+
## ⚙️ Configuration
|
|
236
|
+
|
|
237
|
+
Edit `config/initializers/rails_error_dashboard.rb`:
|
|
238
|
+
|
|
239
|
+
```ruby
|
|
240
|
+
RailsErrorDashboard.configure do |config|
|
|
241
|
+
# Dashboard authentication
|
|
242
|
+
config.dashboard_username = ENV.fetch('ERROR_DASHBOARD_USER', 'admin')
|
|
243
|
+
config.dashboard_password = ENV.fetch('ERROR_DASHBOARD_PASSWORD', 'password')
|
|
244
|
+
config.require_authentication = true
|
|
245
|
+
config.require_authentication_in_development = false
|
|
246
|
+
|
|
247
|
+
# User model for associations
|
|
248
|
+
config.user_model = 'User'
|
|
249
|
+
|
|
250
|
+
# === Notification Settings ===
|
|
251
|
+
|
|
252
|
+
# Slack notifications
|
|
253
|
+
config.enable_slack_notifications = true
|
|
254
|
+
config.slack_webhook_url = ENV['SLACK_WEBHOOK_URL']
|
|
255
|
+
|
|
256
|
+
# Email notifications
|
|
257
|
+
config.enable_email_notifications = true
|
|
258
|
+
config.notification_email_recipients = ENV.fetch('ERROR_NOTIFICATION_EMAILS', '').split(',').map(&:strip)
|
|
259
|
+
config.notification_email_from = ENV.fetch('ERROR_NOTIFICATION_FROM', 'errors@example.com')
|
|
260
|
+
|
|
261
|
+
# Dashboard base URL (for notification links)
|
|
262
|
+
config.dashboard_base_url = ENV['DASHBOARD_BASE_URL']
|
|
263
|
+
|
|
264
|
+
# Separate database (optional - for high-volume apps)
|
|
265
|
+
config.use_separate_database = ENV.fetch('USE_SEPARATE_ERROR_DB', 'false') == 'true'
|
|
266
|
+
|
|
267
|
+
# Retention policy
|
|
268
|
+
config.retention_days = 90
|
|
269
|
+
|
|
270
|
+
# Error catching
|
|
271
|
+
config.enable_middleware = true
|
|
272
|
+
config.enable_error_subscriber = true
|
|
273
|
+
end
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Environment Variables
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
# .env
|
|
280
|
+
ERROR_DASHBOARD_USER=admin
|
|
281
|
+
ERROR_DASHBOARD_PASSWORD=your_secure_password
|
|
282
|
+
|
|
283
|
+
# Slack notifications
|
|
284
|
+
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/YOUR/WEBHOOK/URL
|
|
285
|
+
|
|
286
|
+
# Email notifications (comma-separated list)
|
|
287
|
+
ERROR_NOTIFICATION_EMAILS=dev-team@example.com,ops@example.com
|
|
288
|
+
ERROR_NOTIFICATION_FROM=errors@myapp.com
|
|
289
|
+
|
|
290
|
+
# Dashboard URL (used in notification links)
|
|
291
|
+
DASHBOARD_BASE_URL=https://myapp.com
|
|
292
|
+
|
|
293
|
+
USE_SEPARATE_ERROR_DB=false # Set to true for separate database
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
## 🚀 Usage
|
|
297
|
+
|
|
298
|
+
### Automatic Error Tracking
|
|
299
|
+
|
|
300
|
+
The gem automatically tracks errors from:
|
|
301
|
+
- **Controllers** (via Rails error reporting)
|
|
302
|
+
- **Background jobs** (ActiveJob, Sidekiq)
|
|
303
|
+
- **Rack middleware** (catches everything else)
|
|
304
|
+
|
|
305
|
+
No code changes needed! Just install and go.
|
|
306
|
+
|
|
307
|
+
### Manual Error Logging
|
|
308
|
+
|
|
309
|
+
You can also manually log errors:
|
|
310
|
+
|
|
311
|
+
```ruby
|
|
312
|
+
begin
|
|
313
|
+
# Your code
|
|
314
|
+
rescue => e
|
|
315
|
+
Rails.error.report(e,
|
|
316
|
+
handled: true,
|
|
317
|
+
severity: :error,
|
|
318
|
+
context: {
|
|
319
|
+
current_user: current_user,
|
|
320
|
+
custom_data: "anything you want"
|
|
321
|
+
}
|
|
322
|
+
)
|
|
323
|
+
end
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### Frontend & Mobile Error Reporting
|
|
327
|
+
|
|
328
|
+
Rails Error Dashboard can track errors from **any frontend or mobile application** - not just your Rails backend!
|
|
329
|
+
|
|
330
|
+
**Supported platforms:**
|
|
331
|
+
- 📱 **React Native** (iOS & Android)
|
|
332
|
+
- ⚛️ **React** (Web)
|
|
333
|
+
- 🅰️ **Angular**
|
|
334
|
+
- 💚 **Vue.js**
|
|
335
|
+
- 📱 **Flutter** (via HTTP)
|
|
336
|
+
- 📱 **Swift/Kotlin** (Native apps)
|
|
337
|
+
- 🌐 **Any JavaScript/TypeScript** application
|
|
338
|
+
|
|
339
|
+
#### Quick Setup
|
|
340
|
+
|
|
341
|
+
**1. Create an API endpoint in your Rails app:**
|
|
342
|
+
|
|
343
|
+
```ruby
|
|
344
|
+
# app/controllers/api/v1/mobile_errors_controller.rb
|
|
345
|
+
module Api
|
|
346
|
+
module V1
|
|
347
|
+
class MobileErrorsController < BaseController
|
|
348
|
+
def create
|
|
349
|
+
mobile_error = MobileError.new(error_params)
|
|
350
|
+
|
|
351
|
+
RailsErrorDashboard::Commands::LogError.call(
|
|
352
|
+
mobile_error,
|
|
353
|
+
{
|
|
354
|
+
current_user: current_user,
|
|
355
|
+
request: request,
|
|
356
|
+
source: :mobile_app # or :react, :vue, :angular, etc.
|
|
357
|
+
}
|
|
358
|
+
)
|
|
359
|
+
|
|
360
|
+
render json: { success: true }, status: :created
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
private
|
|
364
|
+
|
|
365
|
+
def error_params
|
|
366
|
+
params.require(:error).permit(:error_type, :message, :stack, :component)
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
class MobileError < StandardError
|
|
370
|
+
attr_reader :mobile_data
|
|
371
|
+
def initialize(data)
|
|
372
|
+
@mobile_data = data
|
|
373
|
+
super(data[:message])
|
|
374
|
+
end
|
|
375
|
+
def backtrace
|
|
376
|
+
@mobile_data[:stack]&.split("\n") || []
|
|
377
|
+
end
|
|
378
|
+
end
|
|
379
|
+
end
|
|
380
|
+
end
|
|
381
|
+
end
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
**2. Report errors from your frontend:**
|
|
385
|
+
|
|
386
|
+
```javascript
|
|
387
|
+
// React/React Native/Vue/Angular
|
|
388
|
+
async function reportError(error, component) {
|
|
389
|
+
try {
|
|
390
|
+
await fetch('/api/v1/mobile_errors', {
|
|
391
|
+
method: 'POST',
|
|
392
|
+
headers: {
|
|
393
|
+
'Content-Type': 'application/json',
|
|
394
|
+
'Authorization': `Bearer ${authToken}`
|
|
395
|
+
},
|
|
396
|
+
body: JSON.stringify({
|
|
397
|
+
error: {
|
|
398
|
+
error_type: error.name,
|
|
399
|
+
message: error.message,
|
|
400
|
+
stack: error.stack,
|
|
401
|
+
component: component
|
|
402
|
+
}
|
|
403
|
+
})
|
|
404
|
+
});
|
|
405
|
+
} catch (e) {
|
|
406
|
+
console.error('Failed to report error:', e);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// Usage in React component
|
|
411
|
+
try {
|
|
412
|
+
// Your code
|
|
413
|
+
} catch (error) {
|
|
414
|
+
reportError(error, 'UserProfile');
|
|
415
|
+
// Handle error in UI
|
|
416
|
+
}
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
**3. Add Error Boundary (React/React Native):**
|
|
420
|
+
|
|
421
|
+
```jsx
|
|
422
|
+
class ErrorBoundary extends React.Component {
|
|
423
|
+
componentDidCatch(error, errorInfo) {
|
|
424
|
+
reportError(error, errorInfo.componentStack);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
render() {
|
|
428
|
+
return this.props.children;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
**Benefits:**
|
|
434
|
+
- ✅ **Single dashboard** for all errors (backend + frontend + mobile)
|
|
435
|
+
- ✅ **Platform detection** - errors automatically tagged by source
|
|
436
|
+
- ✅ **User tracking** - errors associated with logged-in users
|
|
437
|
+
- ✅ **Real-time notifications** - Slack/Email alerts for frontend errors too
|
|
438
|
+
- ✅ **Component tracking** - know which component/screen errored
|
|
439
|
+
- ✅ **Stack traces** - full JavaScript stack traces
|
|
440
|
+
|
|
441
|
+
**📚 Complete Integration Guide:**
|
|
442
|
+
|
|
443
|
+
For detailed setup instructions including:
|
|
444
|
+
- Offline support and retry logic
|
|
445
|
+
- Batch error reporting
|
|
446
|
+
- React Native integration
|
|
447
|
+
- Error filtering and deduplication
|
|
448
|
+
- Best practices
|
|
449
|
+
|
|
450
|
+
See: [MOBILE_APP_INTEGRATION.md](MOBILE_APP_INTEGRATION.md)
|
|
451
|
+
|
|
452
|
+
### Accessing the Dashboard
|
|
453
|
+
|
|
454
|
+
Navigate to `/error_dashboard` to view:
|
|
455
|
+
- **Overview**: Recent errors, statistics, quick filters
|
|
456
|
+
- **All Errors**: Paginated list with filtering and search
|
|
457
|
+
- **Analytics**: Charts, trends, and insights
|
|
458
|
+
- **Error Details**: Full stack trace, context, and resolution tracking
|
|
459
|
+
|
|
460
|
+
### Resolution Workflow
|
|
461
|
+
|
|
462
|
+
1. Click on an error to view details
|
|
463
|
+
2. Investigate the stack trace and context
|
|
464
|
+
3. Fix the issue in your code
|
|
465
|
+
4. Mark as resolved with:
|
|
466
|
+
- Resolution comment (what was the fix)
|
|
467
|
+
- Reference link (PR, commit, issue)
|
|
468
|
+
- Your name
|
|
469
|
+
|
|
470
|
+
## 🗄️ Optional Separate Database
|
|
471
|
+
|
|
472
|
+
For high-volume applications, you can use a separate database for error logs:
|
|
473
|
+
|
|
474
|
+
### Benefits
|
|
475
|
+
- **Performance isolation** - error logging doesn't slow down main DB
|
|
476
|
+
- **Independent scaling** - different hardware for different workloads
|
|
477
|
+
- **Different retention policies** - auto-delete old errors
|
|
478
|
+
- **Security isolation** - separate access controls
|
|
479
|
+
|
|
480
|
+
### Setup
|
|
481
|
+
|
|
482
|
+
1. **Enable in config**:
|
|
483
|
+
```ruby
|
|
484
|
+
config.use_separate_database = true
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
2. **Configure database.yml**:
|
|
488
|
+
```yaml
|
|
489
|
+
production:
|
|
490
|
+
primary:
|
|
491
|
+
database: myapp_production
|
|
492
|
+
# ... your main DB config
|
|
493
|
+
|
|
494
|
+
error_logs:
|
|
495
|
+
database: myapp_error_logs_production
|
|
496
|
+
username: <%= ENV['ERROR_LOGS_DATABASE_USER'] %>
|
|
497
|
+
password: <%= ENV['ERROR_LOGS_DATABASE_PASSWORD'] %>
|
|
498
|
+
migrations_paths: db/error_logs_migrate
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
3. **Create and migrate**:
|
|
502
|
+
```bash
|
|
503
|
+
rails db:create:error_logs
|
|
504
|
+
rails db:migrate:error_logs
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
### Migrating Existing Data
|
|
508
|
+
|
|
509
|
+
If you already have error logs in your primary database and want to move them to the separate database:
|
|
510
|
+
|
|
511
|
+
**📚 Complete Migration Guide:** See [MIGRATION_TO_SEPARATE_DATABASE.md](MIGRATION_TO_SEPARATE_DATABASE.md)
|
|
512
|
+
|
|
513
|
+
The guide covers:
|
|
514
|
+
- Step-by-step migration process
|
|
515
|
+
- Data integrity verification
|
|
516
|
+
- Safe cleanup of old data
|
|
517
|
+
- Rollback procedures
|
|
518
|
+
- Performance considerations
|
|
519
|
+
- Troubleshooting common issues
|
|
520
|
+
|
|
521
|
+
**Quick summary:**
|
|
522
|
+
```bash
|
|
523
|
+
# 1. Configure separate database in database.yml
|
|
524
|
+
# 2. Create the new database
|
|
525
|
+
rails db:create:error_logs
|
|
526
|
+
rails db:migrate:error_logs
|
|
527
|
+
|
|
528
|
+
# 3. Copy data (use rake task from migration guide)
|
|
529
|
+
rake error_logs:migrate_to_separate_db
|
|
530
|
+
|
|
531
|
+
# 4. Verify migration
|
|
532
|
+
rake error_logs:verify_migration
|
|
533
|
+
|
|
534
|
+
# 5. Enable in config and restart app
|
|
535
|
+
# 6. Clean up primary database
|
|
536
|
+
rake error_logs:cleanup_primary_db
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
## 🔧 Advanced Features
|
|
540
|
+
|
|
541
|
+
### 📧 Notification System
|
|
542
|
+
|
|
543
|
+
Rails Error Dashboard includes a powerful multi-channel notification system to alert your team when errors occur.
|
|
544
|
+
|
|
545
|
+
#### Slack Notifications
|
|
546
|
+
|
|
547
|
+
Get instant alerts in Slack with rich, formatted messages including:
|
|
548
|
+
- Error type and message
|
|
549
|
+
- Environment (Production, Staging, etc.)
|
|
550
|
+
- Platform (iOS, Android, API)
|
|
551
|
+
- User information
|
|
552
|
+
- Request details
|
|
553
|
+
- Direct link to view full error in dashboard
|
|
554
|
+
|
|
555
|
+
**Setup:**
|
|
556
|
+
|
|
557
|
+
1. Create a Slack webhook URL:
|
|
558
|
+
- Go to https://api.slack.com/messaging/webhooks
|
|
559
|
+
- Create a new webhook for your channel
|
|
560
|
+
- Copy the webhook URL
|
|
561
|
+
|
|
562
|
+
2. Configure in your app:
|
|
563
|
+
```bash
|
|
564
|
+
# .env
|
|
565
|
+
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/YOUR/WEBHOOK/URL
|
|
566
|
+
DASHBOARD_BASE_URL=https://myapp.com
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
3. Enable in initializer (enabled by default):
|
|
570
|
+
```ruby
|
|
571
|
+
config.enable_slack_notifications = true
|
|
572
|
+
config.slack_webhook_url = ENV['SLACK_WEBHOOK_URL']
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
**Slack Message Features:**
|
|
576
|
+
- 🎨 Beautifully formatted with color-coded blocks
|
|
577
|
+
- 📱 Platform emoji indicators (iOS 📱, Android 🤖, API 🔌)
|
|
578
|
+
- 👤 User and IP address tracking
|
|
579
|
+
- 🔗 Direct "View Details" button linking to dashboard
|
|
580
|
+
- ⏰ Timestamp with timezone
|
|
581
|
+
|
|
582
|
+
#### Email Notifications
|
|
583
|
+
|
|
584
|
+
Send detailed email alerts to your team with HTML and plain text versions.
|
|
585
|
+
|
|
586
|
+
**Email Features:**
|
|
587
|
+
- 📨 Beautiful HTML email template with your app's branding
|
|
588
|
+
- 📄 Plain text fallback for email clients
|
|
589
|
+
- 🎯 Send to multiple recipients
|
|
590
|
+
- 📊 Full error context including stack trace
|
|
591
|
+
- 🔗 One-click link to view in dashboard
|
|
592
|
+
- 🏷️ Environment and platform badges
|
|
593
|
+
|
|
594
|
+
**Setup:**
|
|
595
|
+
|
|
596
|
+
1. Configure recipients and sender:
|
|
597
|
+
```bash
|
|
598
|
+
# .env
|
|
599
|
+
ERROR_NOTIFICATION_EMAILS=dev-team@example.com,ops@example.com,alerts@example.com
|
|
600
|
+
ERROR_NOTIFICATION_FROM=errors@myapp.com
|
|
601
|
+
DASHBOARD_BASE_URL=https://myapp.com
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
2. Enable in initializer (enabled by default):
|
|
605
|
+
```ruby
|
|
606
|
+
config.enable_email_notifications = true
|
|
607
|
+
config.notification_email_recipients = ENV.fetch('ERROR_NOTIFICATION_EMAILS', '').split(',').map(&:strip)
|
|
608
|
+
config.notification_email_from = ENV.fetch('ERROR_NOTIFICATION_FROM', 'errors@example.com')
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
3. Ensure your Rails app has ActionMailer configured:
|
|
612
|
+
```ruby
|
|
613
|
+
# config/environments/production.rb
|
|
614
|
+
config.action_mailer.delivery_method = :smtp
|
|
615
|
+
config.action_mailer.smtp_settings = {
|
|
616
|
+
address: 'smtp.sendgrid.net',
|
|
617
|
+
port: 587,
|
|
618
|
+
domain: 'myapp.com',
|
|
619
|
+
user_name: ENV['SENDGRID_USERNAME'],
|
|
620
|
+
password: ENV['SENDGRID_PASSWORD'],
|
|
621
|
+
authentication: 'plain',
|
|
622
|
+
enable_starttls_auto: true
|
|
623
|
+
}
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
**Email Template Includes:**
|
|
627
|
+
- Error type and full message
|
|
628
|
+
- Environment badge (Production/Staging/Development)
|
|
629
|
+
- Platform badge (iOS/Android/API)
|
|
630
|
+
- Timestamp with timezone
|
|
631
|
+
- User email and IP address
|
|
632
|
+
- Request URL and parameters
|
|
633
|
+
- First 10 lines of stack trace
|
|
634
|
+
- Prominent "View Full Details" button
|
|
635
|
+
|
|
636
|
+
#### Disabling Notifications
|
|
637
|
+
|
|
638
|
+
You can selectively disable notifications:
|
|
639
|
+
|
|
640
|
+
```ruby
|
|
641
|
+
# Disable Slack only
|
|
642
|
+
config.enable_slack_notifications = false
|
|
643
|
+
|
|
644
|
+
# Disable email only
|
|
645
|
+
config.enable_email_notifications = false
|
|
646
|
+
|
|
647
|
+
# Disable both
|
|
648
|
+
config.enable_slack_notifications = false
|
|
649
|
+
config.enable_email_notifications = false
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
#### Notification Workflow
|
|
653
|
+
|
|
654
|
+
When an error occurs:
|
|
655
|
+
1. Error is logged to database
|
|
656
|
+
2. Notifications are sent **asynchronously** via background jobs
|
|
657
|
+
3. Your team receives alerts via configured channels
|
|
658
|
+
4. Team clicks link in notification to view full details
|
|
659
|
+
5. Error can be investigated and marked as resolved in dashboard
|
|
660
|
+
|
|
661
|
+
#### Queue Configuration
|
|
662
|
+
|
|
663
|
+
Notification jobs use the `:error_notifications` queue by default. This allows you to:
|
|
664
|
+
- Prioritize error notifications over other jobs
|
|
665
|
+
- Monitor notification delivery separately
|
|
666
|
+
- Configure different concurrency/workers for notifications
|
|
667
|
+
|
|
668
|
+
**Works with all ActiveJob backends:**
|
|
669
|
+
- ✅ **Solid Queue** (Rails 8.1+ default)
|
|
670
|
+
- ✅ **Sidekiq** (most popular)
|
|
671
|
+
- ✅ **Delayed Job**
|
|
672
|
+
- ✅ **Resque**
|
|
673
|
+
- ✅ **Async** (Rails default for development)
|
|
674
|
+
- ✅ **Inline** (for testing)
|
|
675
|
+
|
|
676
|
+
**Setup for Sidekiq:**
|
|
677
|
+
|
|
678
|
+
```ruby
|
|
679
|
+
# config/sidekiq.yml
|
|
680
|
+
:queues:
|
|
681
|
+
- default
|
|
682
|
+
- error_notifications # Add this queue
|
|
683
|
+
- mailers
|
|
684
|
+
|
|
685
|
+
# Optional: Higher priority for error notifications
|
|
686
|
+
:queues:
|
|
687
|
+
- [error_notifications, 5] # Process 5x more often
|
|
688
|
+
- [default, 1]
|
|
689
|
+
- [mailers, 1]
|
|
690
|
+
```
|
|
691
|
+
|
|
692
|
+
**Setup for Solid Queue (Rails 8.1+):**
|
|
693
|
+
|
|
694
|
+
```ruby
|
|
695
|
+
# config/queue.yml
|
|
696
|
+
dispatchers:
|
|
697
|
+
batch_size: 500
|
|
698
|
+
|
|
699
|
+
workers:
|
|
700
|
+
- queues: error_notifications
|
|
701
|
+
threads: 3
|
|
702
|
+
processes: 1
|
|
703
|
+
polling_interval: 1
|
|
704
|
+
- queues: default
|
|
705
|
+
threads: 5
|
|
706
|
+
processes: 1
|
|
707
|
+
polling_interval: 5
|
|
708
|
+
```
|
|
709
|
+
|
|
710
|
+
**No additional setup needed for:**
|
|
711
|
+
- Async adapter (Rails default in development)
|
|
712
|
+
- Inline adapter (synchronous, for testing)
|
|
713
|
+
- Other adapters use the queue name automatically
|
|
714
|
+
|
|
715
|
+
**Background Jobs:**
|
|
716
|
+
- Notifications use `ActiveJob` and run in background
|
|
717
|
+
- Use dedicated `:error_notifications` queue
|
|
718
|
+
- Won't block or slow down your application
|
|
719
|
+
- Failed notifications are logged but don't raise errors
|
|
720
|
+
- Retries handled by your ActiveJob backend (Sidekiq, Solid Queue, etc.)
|
|
721
|
+
|
|
722
|
+
### Platform Detection
|
|
723
|
+
|
|
724
|
+
Automatically detects:
|
|
725
|
+
- **iOS** - iPhone, iPad apps
|
|
726
|
+
- **Android** - Android apps
|
|
727
|
+
- **API** - Backend services, web requests
|
|
728
|
+
|
|
729
|
+
### User Association
|
|
730
|
+
|
|
731
|
+
Errors are automatically associated with the current user (if signed in). Configure the user model name if it's not `User`.
|
|
732
|
+
|
|
733
|
+
### Retention Policy
|
|
734
|
+
|
|
735
|
+
Old errors are automatically cleaned up based on `retention_days` configuration.
|
|
736
|
+
|
|
737
|
+
## 📊 Architecture Details
|
|
738
|
+
|
|
739
|
+
### Service Objects Pattern
|
|
740
|
+
|
|
741
|
+
**Commands** (Write Operations):
|
|
742
|
+
```ruby
|
|
743
|
+
# Create an error log
|
|
744
|
+
RailsErrorDashboard::Commands::LogError.call(exception, context)
|
|
745
|
+
|
|
746
|
+
# Mark error as resolved
|
|
747
|
+
RailsErrorDashboard::Commands::ResolveError.call(error_id, resolution_data)
|
|
748
|
+
```
|
|
749
|
+
|
|
750
|
+
**Queries** (Read Operations):
|
|
751
|
+
```ruby
|
|
752
|
+
# Get filtered errors
|
|
753
|
+
RailsErrorDashboard::Queries::ErrorsList.call(filters)
|
|
754
|
+
|
|
755
|
+
# Get dashboard stats
|
|
756
|
+
RailsErrorDashboard::Queries::DashboardStats.call
|
|
757
|
+
|
|
758
|
+
# Get analytics
|
|
759
|
+
RailsErrorDashboard::Queries::AnalyticsStats.call(days: 30)
|
|
760
|
+
```
|
|
761
|
+
|
|
762
|
+
### Database Schema
|
|
763
|
+
|
|
764
|
+
```ruby
|
|
765
|
+
create_table :rails_error_dashboard_error_logs do |t|
|
|
766
|
+
# Error details
|
|
767
|
+
t.string :error_type, null: false
|
|
768
|
+
t.text :message, null: false
|
|
769
|
+
t.text :backtrace
|
|
770
|
+
|
|
771
|
+
# Context
|
|
772
|
+
t.integer :user_id
|
|
773
|
+
t.text :request_url
|
|
774
|
+
t.text :request_params
|
|
775
|
+
t.text :user_agent
|
|
776
|
+
t.string :ip_address
|
|
777
|
+
t.string :environment, null: false
|
|
778
|
+
t.string :platform
|
|
779
|
+
|
|
780
|
+
# Resolution tracking
|
|
781
|
+
t.boolean :resolved, default: false
|
|
782
|
+
t.text :resolution_comment
|
|
783
|
+
t.string :resolution_reference
|
|
784
|
+
t.string :resolved_by_name
|
|
785
|
+
t.datetime :resolved_at
|
|
786
|
+
|
|
787
|
+
# Timestamps
|
|
788
|
+
t.datetime :occurred_at, null: false
|
|
789
|
+
t.timestamps
|
|
790
|
+
end
|
|
791
|
+
```
|
|
792
|
+
|
|
793
|
+
## 📚 Documentation
|
|
794
|
+
|
|
795
|
+
### User Guides
|
|
796
|
+
- **[README.md](README.md)** - Main documentation (you are here!)
|
|
797
|
+
- **[NOTIFICATION_CONFIGURATION.md](NOTIFICATION_CONFIGURATION.md)** - Multi-channel notifications setup (Slack, Email, Discord, PagerDuty, Webhooks)
|
|
798
|
+
- **[MOBILE_APP_INTEGRATION.md](MOBILE_APP_INTEGRATION.md)** - Complete guide for integrating with React Native, Expo, and other mobile frameworks
|
|
799
|
+
- **[BATCH_OPERATIONS_GUIDE.md](BATCH_OPERATIONS_GUIDE.md)** - Bulk resolve/delete errors guide
|
|
800
|
+
- **[PLUGIN_DEVELOPMENT_GUIDE.md](PLUGIN_DEVELOPMENT_GUIDE.md)** - Create custom plugins for Jira, metrics, etc.
|
|
801
|
+
|
|
802
|
+
### Operations & Deployment
|
|
803
|
+
- **[MIGRATION_TO_SEPARATE_DATABASE.md](MIGRATION_TO_SEPARATE_DATABASE.md)** - Step-by-step guide for migrating to a separate error logs database
|
|
804
|
+
- **[MULTI_VERSION_TESTING.md](MULTI_VERSION_TESTING.md)** - Testing across Rails 7.0-8.0 and Ruby 3.2-3.3
|
|
805
|
+
- **[CI_TROUBLESHOOTING.md](CI_TROUBLESHOOTING.md)** - Complete guide to CI issues and solutions (for contributors)
|
|
806
|
+
|
|
807
|
+
### Topics Covered
|
|
808
|
+
- ✅ Rails backend error tracking (automatic + manual)
|
|
809
|
+
- ✅ Frontend/mobile error reporting (React, React Native, Vue, Angular, Flutter)
|
|
810
|
+
- ✅ Multi-channel notifications (Slack, Email, Discord, PagerDuty, Webhooks)
|
|
811
|
+
- ✅ Analytics and dashboard usage
|
|
812
|
+
- ✅ Separate database setup and migration
|
|
813
|
+
- ✅ Queue configuration (Sidekiq, Solid Queue, etc.)
|
|
814
|
+
- ✅ Plugin system and custom integrations
|
|
815
|
+
- ✅ Batch operations (bulk resolve/delete)
|
|
816
|
+
- ✅ Multi-version compatibility (Rails 7.0-8.0, Ruby 3.2-3.3)
|
|
817
|
+
- ✅ Security and authentication
|
|
818
|
+
- ✅ Service Objects + CQRS architecture
|
|
819
|
+
|
|
820
|
+
## 🤝 Contributing
|
|
821
|
+
|
|
822
|
+
Contributions are welcome! Please:
|
|
823
|
+
|
|
824
|
+
1. Fork the repository
|
|
825
|
+
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
|
826
|
+
3. Commit your changes (`git commit -m 'Add amazing feature'`)
|
|
827
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
828
|
+
5. Open a Pull Request
|
|
829
|
+
|
|
830
|
+
### Development Setup
|
|
831
|
+
|
|
832
|
+
```bash
|
|
833
|
+
git clone https://github.com/AnjanJ/rails_error_dashboard.git
|
|
834
|
+
cd rails_error_dashboard
|
|
835
|
+
bundle install
|
|
836
|
+
```
|
|
837
|
+
|
|
838
|
+
## 📝 License
|
|
839
|
+
|
|
840
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
|
841
|
+
|
|
842
|
+
## 🙏 Acknowledgments
|
|
843
|
+
|
|
844
|
+
- Built with [Rails](https://rubyonrails.org/)
|
|
845
|
+
- UI powered by [Bootstrap 5](https://getbootstrap.com/)
|
|
846
|
+
- Charts by [Chart.js](https://www.chartjs.org/)
|
|
847
|
+
- Pagination by [Pagy](https://github.com/ddnexus/pagy)
|
|
848
|
+
- Platform detection by [Browser](https://github.com/fnando/browser)
|
|
849
|
+
|
|
850
|
+
## 📮 Support
|
|
851
|
+
|
|
852
|
+
- **Issues**: [GitHub Issues](https://github.com/AnjanJ/rails_error_dashboard/issues)
|
|
853
|
+
- **Discussions**: [GitHub Discussions](https://github.com/AnjanJ/rails_error_dashboard/discussions)
|
|
854
|
+
- **Repository**: [https://github.com/AnjanJ/rails_error_dashboard](https://github.com/AnjanJ/rails_error_dashboard)
|
|
855
|
+
|
|
856
|
+
---
|
|
857
|
+
|
|
858
|
+
**Made with ❤️ by Anjan for the Rails community**
|