rails_error_dashboard 0.14.2 → 0.14.4
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 +36 -18
- data/app/helpers/rails_error_dashboard/application_helper.rb +8 -0
- data/app/jobs/rails_error_dashboard/retention_cleanup_job.rb +27 -23
- data/app/views/layouts/rails_error_dashboard.html.erb +13 -0
- data/config/locales/de.yml +4 -0
- data/config/locales/en.yml +5 -0
- data/config/locales/es.yml +4 -0
- data/config/locales/fr.yml +4 -0
- data/config/locales/it.yml +4 -0
- data/config/locales/ja.yml +4 -0
- data/config/locales/pl.yml +4 -0
- data/config/locales/pt-BR.yml +4 -0
- data/config/locales/ru.yml +4 -0
- data/config/locales/uk.yml +4 -0
- data/config/locales/zh-CN.yml +4 -0
- data/db/migrate/20251225074653_remove_environment_from_error_logs.rb +9 -0
- data/lib/generators/rails_error_dashboard/install/install_generator.rb +45 -50
- data/lib/generators/rails_error_dashboard/install/templates/initializer.rb +17 -10
- data/lib/generators/rails_error_dashboard/solid_queue/solid_queue_generator.rb +41 -21
- data/lib/generators/rails_error_dashboard/uninstall/uninstall_generator.rb +79 -66
- data/lib/rails_error_dashboard/commands/drop_all_tables.rb +77 -0
- data/lib/rails_error_dashboard/commands/log_error.rb +5 -2
- data/lib/rails_error_dashboard/configuration.rb +67 -4
- data/lib/rails_error_dashboard/engine.rb +10 -4
- data/lib/rails_error_dashboard/logger.rb +11 -3
- data/lib/rails_error_dashboard/middleware/rate_limiter.rb +15 -43
- data/lib/rails_error_dashboard/plugin.rb +30 -0
- data/lib/rails_error_dashboard/queries/errors_list.rb +3 -1
- data/lib/rails_error_dashboard/queries/uninstall_plan.rb +63 -0
- data/lib/rails_error_dashboard/services/exception_filter.rb +4 -1
- data/lib/rails_error_dashboard/services/solid_queue_config_check.rb +261 -0
- data/lib/rails_error_dashboard/version.rb +1 -1
- data/lib/rails_error_dashboard.rb +3 -0
- data/lib/tasks/error_dashboard.rake +77 -5
- data/lib/tasks/rails_error_dashboard_tasks.rake +37 -43
- metadata +5 -3
- data/lib/generators/rails_error_dashboard/solid_queue/templates/queue.yml +0 -55
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bd115b4f0fa37f0b90cc22ceea5d5f8db5bdb59ceb40972c3d9ff70c6055a643
|
|
4
|
+
data.tar.gz: b1339930832c6e108d0e55aae93ad2cf14ed1935fa5af23bee24b9f9f4d8943d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9901f9f6fcc64cf53f71cdf43545e2314fe410638eafb414619159d9955763e8251007b13aa5d02e3967ebfbe4b87fb6dff3700694d27031d67ed39c8281e8ac
|
|
7
|
+
data.tar.gz: d039b6f3796fad5884ae83bbe374671d5d2f90137747c0f404fd917cbcf8088f3b4101caf5c9b77524562b4e4c2c2ca3581d99abadfc16797d9bd35122c83afc
|
data/README.md
CHANGED
|
@@ -19,7 +19,7 @@ rails generate rails_error_dashboard:install
|
|
|
19
19
|
rails db:migrate
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
Open `/red
|
|
22
|
+
Open `/red`, then send a test error from its Settings page. No monitoring account or ingestion service is required.
|
|
23
23
|
|
|
24
24
|
[Try the live demo](https://rails-error-dashboard.anjan.dev) (`gandalf` / `youshallnotpass`) · [Read the documentation](https://anjanj.github.io/rails_error_dashboard/) · [View on RubyGems](https://rubygems.org/gems/rails_error_dashboard)
|
|
25
25
|
|
|
@@ -91,7 +91,7 @@ That makes RED a self-hosted Sentry alternative for teams that want Rails-specif
|
|
|
91
91
|
|
|
92
92
|
- Store data in the application's existing PostgreSQL, MySQL/Trilogy or SQLite database.
|
|
93
93
|
- Isolate monitoring writes in a separate error database.
|
|
94
|
-
- Use synchronous writes, or async logging through
|
|
94
|
+
- Use synchronous writes, or async logging through your app's own Active Job backend (Sidekiq, Solid Queue, GoodJob or Rails' in-process `:async`).
|
|
95
95
|
- Track several Rails applications through a shared database.
|
|
96
96
|
|
|
97
97
|
No RED licence or event-ingestion fee, and no plan limits — your database is the only cap, and storm protection deliberately sheds context during floods.
|
|
@@ -619,6 +619,11 @@ Span names follow the `rails_error_dashboard.<operation>` convention, e.g. `rail
|
|
|
619
619
|
gem 'rails_error_dashboard'
|
|
620
620
|
```
|
|
621
621
|
|
|
622
|
+
RED requires Rails 7.0 or newer, Ruby 3.2 or newer, `pagy ~> 43` and `groupdate ~> 6`. An app that pins an older Pagy or groupdate must upgrade it first, or `bundle install` fails.
|
|
623
|
+
|
|
624
|
+
- **Rails before 8.1.4 or 7.2.4** (every 8.0, 7.1 and 7.0 release): also add `gem "json", "< 3"`. json 3 breaks those Rails versions, and the dashboard returns 500. See [the json pin](docs/UPGRADING.md#rails-before-814-or-724-pin-json-below-3).
|
|
625
|
+
- **MySQL**: load the time-zone tables (`mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql`), or the charts fail.
|
|
626
|
+
|
|
622
627
|
### 2. Install with Interactive Setup
|
|
623
628
|
|
|
624
629
|
```bash
|
|
@@ -627,7 +632,9 @@ rails generate rails_error_dashboard:install
|
|
|
627
632
|
rails db:migrate
|
|
628
633
|
```
|
|
629
634
|
|
|
630
|
-
The installer
|
|
635
|
+
The installer asks about notifications and advanced analytics, then where to store errors: in your app's database (the default), a separate one, or one shared by several apps. Without a terminal (CI, Docker) it asks nothing: async logging is on, and every other optional feature is off.
|
|
636
|
+
|
|
637
|
+
**Chose a separate or shared database?** Add the `config/database.yml` entry the installer prints, then run `bin/rails db:create` before `db:migrate`. See [Database Options](docs/guides/DATABASE_OPTIONS.md).
|
|
631
638
|
|
|
632
639
|
### 3. Visit your dashboard
|
|
633
640
|
|
|
@@ -635,37 +642,46 @@ The installer guides you through optional feature selection — notifications, p
|
|
|
635
642
|
http://localhost:3000/red
|
|
636
643
|
```
|
|
637
644
|
|
|
638
|
-
Default credentials: `gandalf` / `youshallnotpass
|
|
645
|
+
Default credentials: `gandalf` / `youshallnotpass`, for development and test only.
|
|
639
646
|
|
|
640
|
-
**
|
|
647
|
+
**Before you deploy anywhere else**, set `ERROR_DASHBOARD_USER` and `ERROR_DASHBOARD_PASSWORD` in that environment. Outside development and test, the app refuses to boot on the defaults. See [Dashboard Credentials](docs/guides/CONFIGURATION.md#dashboard-credentials). For the rest of what production needs (a worker, scheduled jobs, migrations on deploy), see [Running in Production](docs/PRODUCTION.md).
|
|
641
648
|
|
|
642
649
|
### 4. Test it out
|
|
643
650
|
|
|
651
|
+
Open `/red/settings` and click **Send Test Error**, or raise an exception in any controller action. Errors raised at the Rails console prompt are not captured. To report one from the console, use:
|
|
652
|
+
|
|
644
653
|
```ruby
|
|
645
|
-
|
|
646
|
-
raise "Test error from Rails Error Dashboard!"
|
|
654
|
+
Rails.error.report(RuntimeError.new("Test error from Rails Error Dashboard"), handled: false)
|
|
647
655
|
```
|
|
648
656
|
|
|
657
|
+
With async logging on (the default), leave the console open for a second or two so the background job can write it.
|
|
658
|
+
|
|
649
659
|
[Full installation guide →](docs/QUICKSTART.md)
|
|
650
660
|
|
|
661
|
+
### Upgrading
|
|
662
|
+
|
|
663
|
+
```bash
|
|
664
|
+
bundle update rails_error_dashboard
|
|
665
|
+
bin/rails generate rails_error_dashboard:install --no-interactive
|
|
666
|
+
bin/rails db:migrate
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
The installer keeps your initializer and copies only the new migrations. Some releases need a step of their own, and two of them can stop an app booting: [read the upgrade guide](docs/UPGRADING.md) before you deploy.
|
|
670
|
+
|
|
651
671
|
---
|
|
652
672
|
|
|
653
673
|
## Configuration
|
|
654
674
|
|
|
655
675
|
```ruby
|
|
656
676
|
RailsErrorDashboard.configure do |config|
|
|
657
|
-
#
|
|
658
|
-
|
|
659
|
-
config.dashboard_password = ENV.fetch('ERROR_DASHBOARD_PASSWORD', 'youshallnotpass')
|
|
660
|
-
|
|
661
|
-
# Or use your existing auth (Devise, Warden, etc.):
|
|
677
|
+
# Dashboard login: set ERROR_DASHBOARD_USER and ERROR_DASHBOARD_PASSWORD outside
|
|
678
|
+
# development and test (the gem reads them itself). Or use your existing auth:
|
|
662
679
|
# config.authenticate_with = -> { warden.authenticated? }
|
|
663
680
|
|
|
664
681
|
# Optional features — enable as needed
|
|
665
682
|
config.enable_slack_notifications = true
|
|
666
683
|
config.slack_webhook_url = ENV['SLACK_WEBHOOK_URL']
|
|
667
|
-
config.async_logging = true
|
|
668
|
-
config.async_adapter = :sidekiq # or :solid_queue, :async
|
|
684
|
+
config.async_logging = true # jobs run on your app's Active Job adapter; production needs a worker
|
|
669
685
|
end
|
|
670
686
|
```
|
|
671
687
|
|
|
@@ -673,7 +689,7 @@ end
|
|
|
673
689
|
|
|
674
690
|
**Multi-App Support** — Track errors from multiple Rails apps in a single shared database. Auto-detects app name, supports per-app filtering. [Multi-App guide →](docs/MULTI_APP_PERFORMANCE.md)
|
|
675
691
|
|
|
676
|
-
**OpenTelemetry Export** — Emit error-capture operations as OTel spans to Datadog, Honeycomb, or Jaeger. Add `gem "opentelemetry-api"` and set `config.enable_otel_export = true`. See
|
|
692
|
+
**OpenTelemetry Export** — Emit error-capture operations as OTel spans to Datadog, Honeycomb, or Jaeger. Add `gem "opentelemetry-api"` and set `config.enable_otel_export = true`. See **OpenTelemetry Export** under [Features](#features) above for the full options.
|
|
677
693
|
|
|
678
694
|
---
|
|
679
695
|
|
|
@@ -714,7 +730,7 @@ RED translates through its own private I18n backend, so it never reads, writes o
|
|
|
714
730
|
## FAQ
|
|
715
731
|
|
|
716
732
|
**Does Rails Error Dashboard support a separate database for errors?**
|
|
717
|
-
Yes. You can store errors in your app's existing database
|
|
733
|
+
Yes. You can store errors in your app's existing database **or** in a dedicated one. Choose it at the installer's database prompt (or pass `--separate-database`), then add the `error_dashboard` entry it prints to `config/database.yml` for every environment. The engine routes all of its tables through `connects_to`, keeping error data isolated from your app data. Both modes are first-class and covered by the [Database Options guide](docs/guides/DATABASE_OPTIONS.md).
|
|
718
734
|
|
|
719
735
|
**Which databases does it work with?**
|
|
720
736
|
SQLite, PostgreSQL, and MySQL/Trilogy — in either shared or separate-database mode.
|
|
@@ -729,13 +745,13 @@ Yes — local **and** instance variables at the moment the exception is raised,
|
|
|
729
745
|
No. Storm protection (a circuit breaker with adaptive sampling, **ON by default**) makes the gem degrade itself first during error floods — occurrence counts stay exact while it sheds the expensive work, and a Storm History page shows exactly what was shed. There is no I/O on the hot path — the check is a digest and an atomic increment.
|
|
730
746
|
|
|
731
747
|
**Does it work with my background jobs?**
|
|
732
|
-
Yes — errors raised in jobs are captured, and it can log errors asynchronously through Sidekiq
|
|
748
|
+
Yes — errors raised in jobs are captured, and it can log errors asynchronously through your app's Active Job adapter (Sidekiq, Solid Queue, GoodJob or the in-process `:async`). In production, run a worker for the `default` and `error_notifications` queues. Sidekiq, Solid Queue and GoodJob are all auto-detected for the job-queue stats stored on each error.
|
|
733
749
|
|
|
734
750
|
**Does it work with my authentication?**
|
|
735
751
|
Yes — HTTP Basic Auth out of the box, or a custom `authenticate_with` lambda that integrates with Devise, Warden, or session-based auth.
|
|
736
752
|
|
|
737
753
|
**Can it track more than one app?**
|
|
738
|
-
Yes —
|
|
754
|
+
Yes — apps that point at the same error database share one dashboard, with per-app filtering.
|
|
739
755
|
|
|
740
756
|
**What Rails and Ruby versions are supported?**
|
|
741
757
|
Rails 7.0–8.1 and Ruby 3.2–4.0.
|
|
@@ -747,6 +763,8 @@ Rails 7.0–8.1 and Ruby 3.2–4.0.
|
|
|
747
763
|
### Getting Started
|
|
748
764
|
- **[Quickstart Guide](docs/QUICKSTART.md)** — 5-minute setup
|
|
749
765
|
- **[Configuration](docs/guides/CONFIGURATION.md)** — All configuration options
|
|
766
|
+
- **[Upgrading](docs/UPGRADING.md)** — The upgrade, and the releases that need a step
|
|
767
|
+
- **[Running in Production](docs/PRODUCTION.md)** — A worker, scheduled jobs and the other things RED needs before the first deploy
|
|
750
768
|
- **[Uninstalling](docs/UNINSTALL.md)** — Clean removal
|
|
751
769
|
|
|
752
770
|
### Features
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
module RailsErrorDashboard
|
|
2
2
|
module ApplicationHelper
|
|
3
|
+
# Problems in config/queue.yml that stop RED's jobs in this environment:
|
|
4
|
+
# empty when the config is fine, or when Solid Queue doesn't run RED's jobs.
|
|
5
|
+
def red_solid_queue_problems
|
|
6
|
+
Services::SolidQueueConfigCheck.current_problems
|
|
7
|
+
rescue StandardError
|
|
8
|
+
[]
|
|
9
|
+
end
|
|
10
|
+
|
|
3
11
|
# Returns the host app's CSP nonce (if any) so inline <script> tags pass strict CSP.
|
|
4
12
|
# Falls back to nil when the host has no CSP configured — in that case the script tag
|
|
5
13
|
# works without a nonce attribute. Strict CSPs (script-src 'self' 'nonce-...') require
|
|
@@ -33,6 +33,32 @@ module RailsErrorDashboard
|
|
|
33
33
|
)
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
+
# Deletes error logs and everything that references them: dependents first,
|
|
37
|
+
# all in batches. Occurrences, comments and cascade patterns hold foreign
|
|
38
|
+
# keys to the log, so deleting the logs first fails, and one unbounded
|
|
39
|
+
# DELETE would lock the table. Public because error_dashboard:cleanup_resolved
|
|
40
|
+
# deletes the same way.
|
|
41
|
+
#
|
|
42
|
+
# @param scope [ActiveRecord::Relation] the ErrorLog rows to delete
|
|
43
|
+
# @return [Integer] number of error logs deleted
|
|
44
|
+
def self.delete_with_dependents(scope)
|
|
45
|
+
ids = scope.select(:id)
|
|
46
|
+
|
|
47
|
+
ErrorOccurrence.where(error_log_id: ids).in_batches(of: 1000).delete_all
|
|
48
|
+
# Hour buckets for storm-shed events. Listed explicitly because delete_all
|
|
49
|
+
# does not fire the has_many :dependent callback on ErrorLog -- without
|
|
50
|
+
# this line the buckets outlive the group they describe, forever.
|
|
51
|
+
EventCount.where(error_log_id: ids).in_batches(of: 1000).delete_all if EventCount.table_exists?
|
|
52
|
+
ErrorComment.where(error_log_id: ids).in_batches(of: 1000).delete_all
|
|
53
|
+
CascadePattern.where(parent_error_id: ids)
|
|
54
|
+
.or(CascadePattern.where(child_error_id: ids))
|
|
55
|
+
.in_batches(of: 1000).delete_all
|
|
56
|
+
|
|
57
|
+
deleted = 0
|
|
58
|
+
scope.in_batches(of: 1000) { |batch| deleted += batch.delete_all }
|
|
59
|
+
deleted
|
|
60
|
+
end
|
|
61
|
+
|
|
36
62
|
# @return [Integer] number of errors deleted
|
|
37
63
|
def perform
|
|
38
64
|
retention_days = RailsErrorDashboard.configuration.retention_days
|
|
@@ -52,29 +78,7 @@ module RailsErrorDashboard
|
|
|
52
78
|
expired_scope = self.class.expired_scope(cutoff)
|
|
53
79
|
return 0 if expired_scope.none?
|
|
54
80
|
|
|
55
|
-
deleted_count =
|
|
56
|
-
|
|
57
|
-
# Delete dependents first, then errors — all in batches to prevent table locks
|
|
58
|
-
expired_ids_scope = expired_scope.select(:id)
|
|
59
|
-
|
|
60
|
-
# Batch delete dependent records (occurrences, comments, cascade patterns)
|
|
61
|
-
ErrorOccurrence.where(error_log_id: expired_ids_scope).in_batches(of: 1000).delete_all
|
|
62
|
-
# Hour buckets for storm-shed events. Listed explicitly because this job
|
|
63
|
-
# deletes with delete_all, which does not fire the has_many :dependent
|
|
64
|
-
# callback on ErrorLog -- without this line the buckets outlive the group
|
|
65
|
-
# they describe, forever. The migration's own comment promised this
|
|
66
|
-
# pruning before the code existed.
|
|
67
|
-
EventCount.where(error_log_id: expired_ids_scope).in_batches(of: 1000).delete_all if EventCount.table_exists?
|
|
68
|
-
ErrorComment.where(error_log_id: expired_ids_scope).in_batches(of: 1000).delete_all
|
|
69
|
-
CascadePattern.where(parent_error_id: expired_ids_scope)
|
|
70
|
-
.or(CascadePattern.where(child_error_id: expired_ids_scope))
|
|
71
|
-
.in_batches(of: 1000).delete_all
|
|
72
|
-
|
|
73
|
-
# Now batch delete the error logs themselves
|
|
74
|
-
expired_scope.in_batches(of: 1000) do |batch|
|
|
75
|
-
batch_size = batch.delete_all
|
|
76
|
-
deleted_count += batch_size
|
|
77
|
-
end
|
|
81
|
+
deleted_count = self.class.delete_with_dependents(expired_scope)
|
|
78
82
|
|
|
79
83
|
# delete_all skips callbacks, and the stat cards are cached.
|
|
80
84
|
Services::AnalyticsCacheManager.clear if deleted_count > 0
|
|
@@ -1335,6 +1335,19 @@ tr[data-red-row-href]:hover .sev-bar { opacity: 1 !important; }
|
|
|
1335
1335
|
</div>
|
|
1336
1336
|
<script<%= " nonce=\"#{red_csp_nonce}\"".html_safe if red_csp_nonce %>>try { if (sessionStorage.getItem('red_dismiss_creds_warning') === '1') { document.getElementById('security-warning').style.display = 'none'; } } catch(e) {}</script>
|
|
1337
1337
|
<% end %>
|
|
1338
|
+
<% solid_queue_problems = red_solid_queue_problems %>
|
|
1339
|
+
<% if solid_queue_problems.any? %>
|
|
1340
|
+
<div id="solid-queue-warning" class="alert alert-warning" style="display: flex; align-items: flex-start; gap: 10px; margin-top: var(--space-2); margin-bottom: var(--space-4); border-left: 4px solid var(--status-warning);">
|
|
1341
|
+
<i class="bi bi-exclamation-triangle-fill" style="font-size: 18px; flex-shrink: 0;"></i>
|
|
1342
|
+
<div style="flex: 1;">
|
|
1343
|
+
<strong><%= red_t("red.banners.solid_queue.label") %></strong> <%= red_t("red.banners.solid_queue.body_html") %>
|
|
1344
|
+
<ul style="margin: var(--space-2) 0; padding-left: var(--space-5); font-family: var(--font-mono); font-size: 12px;">
|
|
1345
|
+
<% solid_queue_problems.each do |problem| %><li><%= problem %></li><% end %>
|
|
1346
|
+
</ul>
|
|
1347
|
+
<a href="<%= RailsErrorDashboard::Services::SolidQueueConfigCheck::GUIDE_URL %>" target="_blank" rel="noopener"><%= red_t("red.banners.solid_queue.guide") %></a>
|
|
1348
|
+
</div>
|
|
1349
|
+
</div>
|
|
1350
|
+
<% end %>
|
|
1338
1351
|
<% if defined?(@storm_banner_event) && @storm_banner_event %>
|
|
1339
1352
|
<% storm_active = @storm_banner_event.active? %>
|
|
1340
1353
|
<div id="storm-banner" class="alert <%= storm_active ? 'alert-danger' : 'alert-info' %>" style="display: flex; align-items: center; gap: 10px; margin-top: var(--space-2); margin-bottom: var(--space-4); border-left: 4px solid <%= storm_active ? 'var(--status-critical)' : 'var(--status-info)' %>;">
|
data/config/locales/de.yml
CHANGED
|
@@ -87,6 +87,10 @@ de:
|
|
|
87
87
|
<code>ERROR_DASHBOARD_PASSWORD</code> oder konfigurieren Sie <code>authenticate_with</code>
|
|
88
88
|
in Ihrem Initializer.
|
|
89
89
|
dismiss: Für diese Sitzung ausblenden
|
|
90
|
+
solid_queue:
|
|
91
|
+
label: "Solid Queue führt die Jobs von RED nicht aus."
|
|
92
|
+
body_html: "Im Hintergrund erfasste Fehler und Benachrichtigungen warten in der Warteschlange, bis <code>config/queue.yml</code> korrigiert ist. Führen Sie <code>bin/rails error_dashboard:verify</code> aus, um die Korrektur zu sehen, und starten Sie die App danach neu."
|
|
93
|
+
guide: "Was RED von Solid Queue braucht"
|
|
90
94
|
storm:
|
|
91
95
|
active_title: Fehlersturm im Gange
|
|
92
96
|
recent_title: Sturmschutz war kürzlich aktiv
|
data/config/locales/en.yml
CHANGED
|
@@ -155,6 +155,11 @@ en:
|
|
|
155
155
|
initializer.
|
|
156
156
|
dismiss: "Dismiss for this session"
|
|
157
157
|
|
|
158
|
+
solid_queue:
|
|
159
|
+
# Shown when Solid Queue runs RED's jobs with a config/queue.yml that never would.
|
|
160
|
+
label: "Solid Queue won't run RED's jobs."
|
|
161
|
+
body_html: "Errors captured in the background and notifications wait in the queue until <code>config/queue.yml</code> is fixed. Run <code>bin/rails error_dashboard:verify</code> for the fix, then restart."
|
|
162
|
+
guide: "What RED needs from Solid Queue"
|
|
158
163
|
storm:
|
|
159
164
|
# Whole sentences, not fragments. The English original assembled these
|
|
160
165
|
# from a stem plus a conditional clause, which cannot be reordered into
|
data/config/locales/es.yml
CHANGED
|
@@ -86,6 +86,10 @@ es:
|
|
|
86
86
|
Defina las variables de entorno <code>ERROR_DASHBOARD_USER</code> y <code>ERROR_DASHBOARD_PASSWORD</code>,
|
|
87
87
|
o configure <code>authenticate_with</code> en su initializer.
|
|
88
88
|
dismiss: Ocultar durante esta sesión
|
|
89
|
+
solid_queue:
|
|
90
|
+
label: "Solid Queue no ejecutará los trabajos de RED."
|
|
91
|
+
body_html: "Los errores capturados en segundo plano y las notificaciones esperan en la cola hasta que se corrija <code>config/queue.yml</code>. Ejecute <code>bin/rails error_dashboard:verify</code> para ver la corrección y luego reinicie."
|
|
92
|
+
guide: "Lo que RED necesita de Solid Queue"
|
|
89
93
|
storm:
|
|
90
94
|
active_title: Tormenta de errores en curso
|
|
91
95
|
recent_title: La protección ante tormentas se activó recientemente
|
data/config/locales/fr.yml
CHANGED
|
@@ -87,6 +87,10 @@ fr:
|
|
|
87
87
|
et <code>ERROR_DASHBOARD_PASSWORD</code>, ou configurez <code>authenticate_with</code>
|
|
88
88
|
dans votre initializer.
|
|
89
89
|
dismiss: Masquer pour cette session
|
|
90
|
+
solid_queue:
|
|
91
|
+
label: "Solid Queue n'exécutera pas les tâches de RED."
|
|
92
|
+
body_html: "Les erreurs capturées en arrière-plan et les notifications restent en file d'attente tant que <code>config/queue.yml</code> n'est pas corrigé. Lancez <code>bin/rails error_dashboard:verify</code> pour voir la correction, puis redémarrez."
|
|
93
|
+
guide: "Ce dont RED a besoin de Solid Queue"
|
|
90
94
|
storm:
|
|
91
95
|
active_title: Tempête d'erreurs en cours
|
|
92
96
|
recent_title: La protection anti-tempête s'est déclenchée récemment
|
data/config/locales/it.yml
CHANGED
|
@@ -86,6 +86,10 @@ it:
|
|
|
86
86
|
Imposta le variabili d'ambiente <code>ERROR_DASHBOARD_USER</code> e <code>ERROR_DASHBOARD_PASSWORD</code>
|
|
87
87
|
oppure configura <code>authenticate_with</code> nel tuo inizializzatore.
|
|
88
88
|
dismiss: Nascondi per questa sessione
|
|
89
|
+
solid_queue:
|
|
90
|
+
label: "Solid Queue non eseguirà i job di RED."
|
|
91
|
+
body_html: "Gli errori acquisiti in background e le notifiche restano in coda finché <code>config/queue.yml</code> non viene corretto. Esegui <code>bin/rails error_dashboard:verify</code> per vedere la correzione, poi riavvia."
|
|
92
|
+
guide: "Cosa serve a RED da Solid Queue"
|
|
89
93
|
storm:
|
|
90
94
|
active_title: Tempesta di errori in corso
|
|
91
95
|
recent_title: Protezione dalle tempeste attivata di recente
|
data/config/locales/ja.yml
CHANGED
|
@@ -86,6 +86,10 @@ ja:
|
|
|
86
86
|
と <code>ERROR_DASHBOARD_PASSWORD</code> を設定するか、イニシャライザで <code>authenticate_with</code>
|
|
87
87
|
を設定してください。
|
|
88
88
|
dismiss: このセッションでは表示しない
|
|
89
|
+
solid_queue:
|
|
90
|
+
label: "Solid Queue は RED のジョブを実行しません。"
|
|
91
|
+
body_html: "<code>config/queue.yml</code> を修正するまで、バックグラウンドで記録されたエラーと通知はキューで待機します。<code>bin/rails error_dashboard:verify</code> を実行して修正方法を確認し、再起動してください。"
|
|
92
|
+
guide: "RED が Solid Queue に必要とするもの"
|
|
89
93
|
storm:
|
|
90
94
|
active_title: エラーストームが発生中です
|
|
91
95
|
recent_title: ストーム保護が最近作動しました
|
data/config/locales/pl.yml
CHANGED
|
@@ -86,6 +86,10 @@ pl:
|
|
|
86
86
|
Ustaw zmienne środowiskowe <code>ERROR_DASHBOARD_USER</code> i <code>ERROR_DASHBOARD_PASSWORD</code>
|
|
87
87
|
albo skonfiguruj <code>authenticate_with</code> w swoim inicjalizatorze.
|
|
88
88
|
dismiss: Ukryj na czas tej sesji
|
|
89
|
+
solid_queue:
|
|
90
|
+
label: "Solid Queue nie uruchomi zadań RED."
|
|
91
|
+
body_html: "Błędy przechwycone w tle i powiadomienia czekają w kolejce, dopóki <code>config/queue.yml</code> nie zostanie poprawiony. Uruchom <code>bin/rails error_dashboard:verify</code>, aby zobaczyć poprawkę, a następnie zrestartuj aplikację."
|
|
92
|
+
guide: "Czego RED potrzebuje od Solid Queue"
|
|
89
93
|
storm:
|
|
90
94
|
active_title: Trwa sztorm błędów
|
|
91
95
|
recent_title: Ochrona przed sztormem zadziałała niedawno
|
data/config/locales/pt-BR.yml
CHANGED
|
@@ -86,6 +86,10 @@ pt-BR:
|
|
|
86
86
|
Defina as variáveis de ambiente <code>ERROR_DASHBOARD_USER</code> e <code>ERROR_DASHBOARD_PASSWORD</code>,
|
|
87
87
|
ou configure <code>authenticate_with</code> no seu initializer.
|
|
88
88
|
dismiss: Ocultar nesta sessão
|
|
89
|
+
solid_queue:
|
|
90
|
+
label: "O Solid Queue não executará os jobs do RED."
|
|
91
|
+
body_html: "Erros capturados em segundo plano e notificações aguardam na fila até que <code>config/queue.yml</code> seja corrigido. Execute <code>bin/rails error_dashboard:verify</code> para ver a correção e reinicie."
|
|
92
|
+
guide: "O que o RED precisa do Solid Queue"
|
|
89
93
|
storm:
|
|
90
94
|
active_title: Tempestade de erros em andamento
|
|
91
95
|
recent_title: A proteção contra tempestades foi acionada recentemente
|
data/config/locales/ru.yml
CHANGED
|
@@ -86,6 +86,10 @@ ru:
|
|
|
86
86
|
Задайте переменные окружения <code>ERROR_DASHBOARD_USER</code> и <code>ERROR_DASHBOARD_PASSWORD</code>
|
|
87
87
|
или настройте <code>authenticate_with</code> в инициализаторе.
|
|
88
88
|
dismiss: Скрыть до конца сессии
|
|
89
|
+
solid_queue:
|
|
90
|
+
label: "Solid Queue не будет выполнять задания RED."
|
|
91
|
+
body_html: "Ошибки, записанные в фоне, и уведомления ждут в очереди, пока не исправлен <code>config/queue.yml</code>. Запустите <code>bin/rails error_dashboard:verify</code>, чтобы увидеть исправление, затем перезапустите приложение."
|
|
92
|
+
guide: "Что RED нужно от Solid Queue"
|
|
89
93
|
storm:
|
|
90
94
|
active_title: Идёт шторм ошибок
|
|
91
95
|
recent_title: Недавно сработала защита от шторма
|
data/config/locales/uk.yml
CHANGED
|
@@ -86,6 +86,10 @@ uk:
|
|
|
86
86
|
Встановіть змінні середовища <code>ERROR_DASHBOARD_USER</code> і <code>ERROR_DASHBOARD_PASSWORD</code>
|
|
87
87
|
або налаштуйте <code>authenticate_with</code> у своєму ініціалізаторі.
|
|
88
88
|
dismiss: Приховати для цієї сесії
|
|
89
|
+
solid_queue:
|
|
90
|
+
label: "Solid Queue не виконуватиме завдання RED."
|
|
91
|
+
body_html: "Помилки, записані у фоні, і сповіщення чекають у черзі, доки не виправлено <code>config/queue.yml</code>. Запустіть <code>bin/rails error_dashboard:verify</code>, щоб побачити виправлення, потім перезапустіть застосунок."
|
|
92
|
+
guide: "Що RED потрібно від Solid Queue"
|
|
89
93
|
storm:
|
|
90
94
|
active_title: Триває шторм помилок
|
|
91
95
|
recent_title: Нещодавно спрацював захист від штормів
|
data/config/locales/zh-CN.yml
CHANGED
|
@@ -85,6 +85,10 @@ zh-CN:
|
|
|
85
85
|
body_html: 你正在使用默认凭据(gandalf/youshallnotpass)。请设置环境变量 <code>ERROR_DASHBOARD_USER</code>
|
|
86
86
|
和 <code>ERROR_DASHBOARD_PASSWORD</code>,或在初始化文件中配置 <code>authenticate_with</code>。
|
|
87
87
|
dismiss: 本次会话内不再提示
|
|
88
|
+
solid_queue:
|
|
89
|
+
label: "Solid Queue 不会运行 RED 的任务。"
|
|
90
|
+
body_html: "在修复 <code>config/queue.yml</code> 之前,后台捕获的错误和通知会一直在队列中等待。运行 <code>bin/rails error_dashboard:verify</code> 查看修复方法,然后重启应用。"
|
|
91
|
+
guide: "RED 对 Solid Queue 的要求"
|
|
88
92
|
storm:
|
|
89
93
|
active_title: 错误风暴进行中
|
|
90
94
|
recent_title: 近期触发过风暴保护
|
|
@@ -3,6 +3,15 @@ class RemoveEnvironmentFromErrorLogs < ActiveRecord::Migration[7.0]
|
|
|
3
3
|
# Skip if squashed migration ran (column never existed) or already removed
|
|
4
4
|
return unless column_exists?(:rails_error_dashboard_error_logs, :environment)
|
|
5
5
|
|
|
6
|
+
# Only the v0.1.x column is removed: it was NOT NULL. The column
|
|
7
|
+
# AddEnvironmentToErrorLogs adds back (0.11.0) is nullable and holds real
|
|
8
|
+
# data. This migration replays over it whenever RED's migrations run
|
|
9
|
+
# against tables that already exist (an app joining a shared error
|
|
10
|
+
# database runs its own renumbered copy of every migration), and dropping
|
|
11
|
+
# it there wiped every error's environment.
|
|
12
|
+
environment = columns(:rails_error_dashboard_error_logs).find { |column| column.name == "environment" }
|
|
13
|
+
return if environment.nil? || environment.null
|
|
14
|
+
|
|
6
15
|
# Remove composite index first
|
|
7
16
|
remove_index :rails_error_dashboard_error_logs,
|
|
8
17
|
name: 'index_error_logs_on_environment_and_occurred_at',
|
|
@@ -15,7 +15,7 @@ module RailsErrorDashboard
|
|
|
15
15
|
class_option :pagerduty, type: :boolean, default: false, desc: "Enable PagerDuty notifications"
|
|
16
16
|
class_option :webhooks, type: :boolean, default: false, desc: "Enable webhook notifications"
|
|
17
17
|
# Performance options
|
|
18
|
-
class_option :async_logging, type: :boolean, default: true, desc: "Enable async error logging (default: true
|
|
18
|
+
class_option :async_logging, type: :boolean, default: true, desc: "Enable async error logging (default: true; jobs run on your app's Active Job adapter, so production needs a worker)"
|
|
19
19
|
class_option :error_sampling, type: :boolean, default: false, desc: "Enable error sampling (reduce volume)"
|
|
20
20
|
class_option :separate_database, type: :boolean, default: false, desc: "Use separate database for errors"
|
|
21
21
|
class_option :database, type: :string, default: nil, desc: "Database name to use for errors (e.g., 'error_dashboard')"
|
|
@@ -58,7 +58,7 @@ module RailsErrorDashboard
|
|
|
58
58
|
|
|
59
59
|
if quick_mode?
|
|
60
60
|
@selected_features = build_quick_defaults
|
|
61
|
-
say " Using sensible defaults (analytics ON,
|
|
61
|
+
say " Using sensible defaults (analytics, breadcrumbs ON, system health ON, 50% sampling; notifications OFF)", :green
|
|
62
62
|
return
|
|
63
63
|
end
|
|
64
64
|
|
|
@@ -131,7 +131,10 @@ module RailsErrorDashboard
|
|
|
131
131
|
advanced_keys = %i[async_logging error_sampling breadcrumbs system_health
|
|
132
132
|
source_code_integration git_blame swallowed_exceptions
|
|
133
133
|
crash_capture diagnostic_dump]
|
|
134
|
-
|
|
134
|
+
# A flag the user passed, not an option left at its default: async_logging
|
|
135
|
+
# defaults to true, so "is any of these set?" was always yes and this
|
|
136
|
+
# question was never asked.
|
|
137
|
+
any_advanced_cli_flag = advanced_keys.any? { |k| options[k] != self.class.class_options[k]&.default }
|
|
135
138
|
|
|
136
139
|
say "\n[3/3] Advanced Options (performance tuning & diagnostics)", :cyan
|
|
137
140
|
say " Async logging, error sampling, breadcrumbs, system health,", :white
|
|
@@ -169,8 +172,10 @@ module RailsErrorDashboard
|
|
|
169
172
|
advanced_features.each do |f|
|
|
170
173
|
say "\n #{f[:name]}", :cyan
|
|
171
174
|
say " #{f[:desc]}", :white
|
|
172
|
-
|
|
173
|
-
|
|
175
|
+
# Async logging is on unless declined, as it is without this question.
|
|
176
|
+
default_on = f[:key] == :async_logging
|
|
177
|
+
r = ask(" Enable? (#{default_on ? 'Y/n' : 'y/N'}):", :yellow, limited_to: [ "y", "Y", "n", "N", "" ])
|
|
178
|
+
@selected_features[f[:key]] = default_on ? r.downcase != "n" : r.downcase == "y"
|
|
174
179
|
if @selected_features[f[:key]] && f[:key] == :swallowed_exceptions && RUBY_VERSION < "3.3"
|
|
175
180
|
say " ⚠ Requires Ruby 3.3+ (you have #{RUBY_VERSION}) — will activate after upgrade", :yellow
|
|
176
181
|
end
|
|
@@ -293,7 +298,9 @@ module RailsErrorDashboard
|
|
|
293
298
|
@enable_webhooks = @selected_features&.dig(:webhooks) || options[:webhooks]
|
|
294
299
|
|
|
295
300
|
# Performance
|
|
296
|
-
|
|
301
|
+
# An answer, when there was one, wins: `answer || default` turned a "no"
|
|
302
|
+
# into the default's "yes".
|
|
303
|
+
@enable_async_logging = @selected_features&.key?(:async_logging) ? @selected_features[:async_logging] : options[:async_logging]
|
|
297
304
|
@enable_error_sampling = @selected_features&.dig(:error_sampling) || options[:error_sampling]
|
|
298
305
|
|
|
299
306
|
# Database mode (set by select_database_mode or CLI flags)
|
|
@@ -383,7 +390,7 @@ module RailsErrorDashboard
|
|
|
383
390
|
return
|
|
384
391
|
end
|
|
385
392
|
|
|
386
|
-
route "mount RailsErrorDashboard::Engine => '/red' # RED (Rails Error Dashboard)
|
|
393
|
+
route "mount RailsErrorDashboard::Engine => '/red' # RED (Rails Error Dashboard)"
|
|
387
394
|
end
|
|
388
395
|
|
|
389
396
|
def show_feature_summary
|
|
@@ -400,7 +407,7 @@ module RailsErrorDashboard
|
|
|
400
407
|
say " ✓ Dashboard UI", :green
|
|
401
408
|
say " ✓ Real-time Updates", :green
|
|
402
409
|
say " ✓ Analytics", :green
|
|
403
|
-
say " ✓ Async Logging (
|
|
410
|
+
say " ✓ Async Logging (runs on your app's Active Job adapter)", :green
|
|
404
411
|
|
|
405
412
|
# Count optional features enabled
|
|
406
413
|
enabled_count = 0
|
|
@@ -477,14 +484,11 @@ module RailsErrorDashboard
|
|
|
477
484
|
say " → Set PAGERDUTY_INTEGRATION_KEY in .env", :yellow if @enable_pagerduty
|
|
478
485
|
say " → Set WEBHOOK_URLS in .env", :yellow if @enable_webhooks
|
|
479
486
|
if @enable_async_logging
|
|
480
|
-
#
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
else
|
|
486
|
-
say " ✓ Async logging uses Rails :async adapter — no extra process needed", :green
|
|
487
|
-
end
|
|
487
|
+
# RED's jobs run on the app's own Active Job adapter; async_adapter only
|
|
488
|
+
# feeds validation and the Settings page. Rails 8 production uses Solid
|
|
489
|
+
# Queue, which needs a worker, so don't promise that none is needed.
|
|
490
|
+
say " → Async logging enqueues on your app's config.active_job.queue_adapter.", :yellow
|
|
491
|
+
say " Run a worker for the default and error_notifications queues, or set config.async_logging = false.", :yellow
|
|
488
492
|
end
|
|
489
493
|
|
|
490
494
|
# Database-specific instructions
|
|
@@ -496,28 +500,29 @@ module RailsErrorDashboard
|
|
|
496
500
|
say "Next Steps:", :cyan
|
|
497
501
|
if @enable_separate_database
|
|
498
502
|
say " 1. Add the database.yml entry shown above"
|
|
499
|
-
say " 2. Run: rails db:create
|
|
503
|
+
say " 2. Run: rails db:create:#{@database_name}"
|
|
500
504
|
if @enable_multi_app
|
|
501
505
|
say " 3. Run migrations (only needed on the FIRST app):"
|
|
502
|
-
say " rails db:migrate
|
|
506
|
+
say " rails db:migrate:#{@database_name}"
|
|
503
507
|
else
|
|
504
|
-
say " 3. Run: rails db:migrate
|
|
508
|
+
say " 3. Run: rails db:migrate:#{@database_name}"
|
|
505
509
|
end
|
|
506
|
-
say " 4.
|
|
510
|
+
say " 4. Before deploying: set ERROR_DASHBOARD_USER and ERROR_DASHBOARD_PASSWORD there"
|
|
507
511
|
say " 5. Restart your Rails server"
|
|
508
512
|
say " 6. Visit http://localhost:3000/red"
|
|
509
513
|
say " 7. Verify: rails error_dashboard:verify"
|
|
510
514
|
else
|
|
511
515
|
say " 1. Run: rails db:migrate"
|
|
512
|
-
say " 2.
|
|
516
|
+
say " 2. Before deploying: set ERROR_DASHBOARD_USER and ERROR_DASHBOARD_PASSWORD there"
|
|
513
517
|
say " 3. Restart your Rails server"
|
|
514
518
|
say " 4. Visit http://localhost:3000/red"
|
|
515
519
|
end
|
|
516
520
|
say "Authentication:", :cyan
|
|
517
|
-
say " Default: HTTP Basic Auth
|
|
521
|
+
say " Default: HTTP Basic Auth, gandalf/youshallnotpass in development and test only", :white
|
|
522
|
+
say " Elsewhere: set ERROR_DASHBOARD_USER and ERROR_DASHBOARD_PASSWORD, or the app won't boot", :white
|
|
518
523
|
say " Devise/Warden: config.authenticate_with = -> { warden.authenticated? }", :white
|
|
519
524
|
say " Session-based: config.authenticate_with = -> { session[:admin] == true }", :white
|
|
520
|
-
say " See: https://github.com/AnjanJ/rails_error_dashboard/blob/main/docs/guides/CONFIGURATION.md#
|
|
525
|
+
say " See: https://github.com/AnjanJ/rails_error_dashboard/blob/main/docs/guides/CONFIGURATION.md#dashboard-credentials", :white
|
|
521
526
|
say "\n"
|
|
522
527
|
say "Issue Tracking (optional):", :cyan
|
|
523
528
|
say " Create a dedicated RED (Rails Error Dashboard) bot account on your platform:", :white
|
|
@@ -549,7 +554,7 @@ module RailsErrorDashboard
|
|
|
549
554
|
|
|
550
555
|
def build_quick_defaults
|
|
551
556
|
{
|
|
552
|
-
# Async ON (
|
|
557
|
+
# Async ON (runs on the app's Active Job adapter)
|
|
553
558
|
async_logging: true,
|
|
554
559
|
# All analytics ON — run at query/background time, zero request-path overhead
|
|
555
560
|
baseline_alerts: true,
|
|
@@ -597,33 +602,23 @@ module RailsErrorDashboard
|
|
|
597
602
|
say " # Separate error database", :white
|
|
598
603
|
end
|
|
599
604
|
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
say "
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
say " <<: *default", :white
|
|
617
|
-
say " database: #{app_name_snake}_production", :white
|
|
618
|
-
say " error_dashboard:", :white
|
|
619
|
-
say " <<: *default", :white
|
|
620
|
-
if @enable_multi_app
|
|
621
|
-
shared_db_base = @shared_db_name || "shared_errors"
|
|
622
|
-
say " database: #{shared_db_base}_production", :white
|
|
623
|
-
else
|
|
624
|
-
say " database: #{app_name_snake}_errors_production", :white
|
|
605
|
+
# Every environment the app boots in needs the entry, test included:
|
|
606
|
+
# without it RED falls back to the main database and records nothing.
|
|
607
|
+
%w[development test production].each do |env|
|
|
608
|
+
say "\n #{env}:", :cyan
|
|
609
|
+
say " primary:", :white
|
|
610
|
+
say " <<: *default", :white
|
|
611
|
+
say " database: #{app_name_snake}_#{env}", :white
|
|
612
|
+
say " #{@database_name}:", :white
|
|
613
|
+
say " <<: *default", :white
|
|
614
|
+
if @enable_multi_app
|
|
615
|
+
shared_db_base = @shared_db_name || "shared_errors"
|
|
616
|
+
say " database: #{shared_db_base}_#{env}", :white
|
|
617
|
+
else
|
|
618
|
+
say " database: #{app_name_snake}_errors_#{env}", :white
|
|
619
|
+
end
|
|
620
|
+
say " migrations_paths: db/error_dashboard_migrate", :white
|
|
625
621
|
end
|
|
626
|
-
say " migrations_paths: db/error_dashboard_migrate", :white
|
|
627
622
|
say "\n"
|
|
628
623
|
|
|
629
624
|
if @enable_multi_app
|