rails_error_dashboard 0.14.4 → 0.15.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 +4 -4
- data/README.md +12 -5
- data/app/controllers/rails_error_dashboard/application_controller.rb +28 -4
- data/app/controllers/rails_error_dashboard/errors_controller.rb +68 -2
- data/app/controllers/rails_error_dashboard/health_controller.rb +38 -0
- data/app/helpers/rails_error_dashboard/application_helper.rb +2 -2
- data/app/helpers/rails_error_dashboard/backtrace_helper.rb +56 -2
- data/app/jobs/rails_error_dashboard/baseline_alert_job.rb +20 -2
- data/app/jobs/rails_error_dashboard/cascade_detection_job.rb +30 -0
- data/app/jobs/rails_error_dashboard/concerns/plain_channel_message.rb +33 -6
- data/app/jobs/rails_error_dashboard/discord_error_notification_job.rb +1 -1
- data/app/jobs/rails_error_dashboard/pagerduty_error_notification_job.rb +1 -1
- data/app/jobs/rails_error_dashboard/retention_cleanup_job.rb +26 -0
- data/app/jobs/rails_error_dashboard/scheduled_digest_job.rb +6 -1
- data/app/jobs/rails_error_dashboard/slack_error_notification_job.rb +1 -1
- data/app/jobs/rails_error_dashboard/telegram_error_notification_job.rb +25 -0
- data/app/jobs/rails_error_dashboard/webhook_error_notification_job.rb +2 -18
- data/app/models/rails_error_dashboard/error_log.rb +43 -12
- data/app/models/rails_error_dashboard/missing_translation.rb +43 -0
- data/app/views/layouts/rails_error_dashboard.html.erb +11 -1
- data/app/views/rails_error_dashboard/errors/_error_info.html.erb +3 -1
- data/app/views/rails_error_dashboard/errors/_sidebar_metadata.html.erb +3 -1
- data/app/views/rails_error_dashboard/errors/_source_code.html.erb +3 -9
- data/app/views/rails_error_dashboard/errors/activestorage_health_summary.html.erb +28 -0
- data/app/views/rails_error_dashboard/errors/boot_errors.html.erb +130 -0
- data/app/views/rails_error_dashboard/errors/index.html.erb +1 -1
- data/app/views/rails_error_dashboard/errors/missing_translations.html.erb +143 -0
- data/app/views/rails_error_dashboard/errors/settings/_value_badge.html.erb +7 -4
- data/app/views/rails_error_dashboard/errors/settings.html.erb +19 -5
- data/config/locales/de.yml +68 -5
- data/config/locales/en.yml +78 -4
- data/config/locales/es.yml +68 -5
- data/config/locales/fr.yml +68 -5
- data/config/locales/it.yml +68 -5
- data/config/locales/ja.yml +68 -4
- data/config/locales/pl.yml +68 -5
- data/config/locales/pt-BR.yml +68 -5
- data/config/locales/ru.yml +68 -5
- data/config/locales/uk.yml +68 -5
- data/config/locales/zh-CN.yml +68 -4
- data/config/routes.rb +6 -0
- data/db/migrate/20251223000000_create_rails_error_dashboard_complete_schema.rb +10 -2
- data/db/migrate/20261010000001_create_missing_translations.rb +50 -0
- data/lib/generators/rails_error_dashboard/install/install_generator.rb +9 -4
- data/lib/generators/rails_error_dashboard/install/templates/initializer.rb +27 -0
- data/lib/rails_error_dashboard/commands/assign_error.rb +24 -1
- data/lib/rails_error_dashboard/commands/batch_resolve_errors.rb +9 -1
- data/lib/rails_error_dashboard/commands/flush_missing_translations.rb +103 -0
- data/lib/rails_error_dashboard/commands/log_error.rb +1 -1
- data/lib/rails_error_dashboard/commands/resolve_error.rb +2 -15
- data/lib/rails_error_dashboard/commands/update_error_status.rb +7 -0
- data/lib/rails_error_dashboard/configuration.rb +42 -1
- data/lib/rails_error_dashboard/engine.rb +42 -1
- data/lib/rails_error_dashboard/middleware/rate_limiter.rb +7 -1
- data/lib/rails_error_dashboard/plugin.rb +19 -3
- data/lib/rails_error_dashboard/plugin_registry.rb +61 -12
- data/lib/rails_error_dashboard/queries/boot_errors.rb +76 -0
- data/lib/rails_error_dashboard/queries/dashboard_stats.rb +3 -11
- data/lib/rails_error_dashboard/queries/errors_list.rb +8 -16
- data/lib/rails_error_dashboard/queries/health_status.rb +191 -0
- data/lib/rails_error_dashboard/queries/missing_translation_summary.rb +82 -0
- data/lib/rails_error_dashboard/services/active_storage_probe.rb +91 -0
- data/lib/rails_error_dashboard/services/backtrace_parser.rb +13 -7
- data/lib/rails_error_dashboard/services/backtrace_processor.rb +15 -0
- data/lib/rails_error_dashboard/services/baseline_alert_payload_builder.rb +30 -0
- data/lib/rails_error_dashboard/services/crash_capture.rb +85 -2
- data/lib/rails_error_dashboard/services/digest_builder.rb +9 -6
- data/lib/rails_error_dashboard/services/error_notification_dispatcher.rb +6 -0
- data/lib/rails_error_dashboard/services/github_link_generator.rb +25 -9
- data/lib/rails_error_dashboard/services/missing_translation_handler.rb +152 -0
- data/lib/rails_error_dashboard/services/missing_translation_tracker.rb +316 -0
- data/lib/rails_error_dashboard/services/resolution_callbacks.rb +44 -0
- data/lib/rails_error_dashboard/services/severity_classifier.rb +52 -0
- data/lib/rails_error_dashboard/services/source_code_reader.rb +23 -3
- data/lib/rails_error_dashboard/services/telegram_delivery.rb +134 -0
- data/lib/rails_error_dashboard/services/telegram_payload_builder.rb +105 -0
- data/lib/rails_error_dashboard/services/webhook_delivery.rb +63 -0
- data/lib/rails_error_dashboard/services/webhook_signer.rb +80 -0
- data/lib/rails_error_dashboard/version.rb +1 -1
- data/lib/rails_error_dashboard.rb +12 -0
- metadata +21 -2
data/config/locales/ru.yml
CHANGED
|
@@ -60,6 +60,8 @@ ru:
|
|
|
60
60
|
llm: LLM
|
|
61
61
|
n_plus_one: N+1 запросы
|
|
62
62
|
deprecations: Устаревшее
|
|
63
|
+
missing_translations: "Переводы"
|
|
64
|
+
boot_errors: "Ошибки запуска"
|
|
63
65
|
swallowed: Подавленные
|
|
64
66
|
diagnostic_dumps: Диагностика
|
|
65
67
|
storms: Штормы
|
|
@@ -868,6 +870,53 @@ ru:
|
|
|
868
870
|
error_log
|
|
869
871
|
footer_tip: Подавленные исключения возбуждаются, а затем молча перехватываются.
|
|
870
872
|
Они могут скрывать настоящие ошибки.
|
|
873
|
+
missing_translations_page:
|
|
874
|
+
title: "Отсутствующие переводы"
|
|
875
|
+
empty_title: "Отсутствующие переводы не зафиксированы"
|
|
876
|
+
empty_body: "За последние %{days} дн. отсутствующие ключи перевода не зафиксированы."
|
|
877
|
+
how_title: "Как отслеживаются отсутствующие переводы:"
|
|
878
|
+
how_enabled_html: "Отслеживание должно быть включено (%{option})"
|
|
879
|
+
how_hooked: "RED оборачивает I18n.exception_handler и передаёт вызов обработчику, который уже был в приложении; больше ничего в настройках I18n не меняется"
|
|
880
|
+
how_recorded: "Каждый запрос, дошедший до обработчика — как через I18n.t, так и через хелпер t() во view — считается по локали и ключу вместе с первым замеченным местом вызова"
|
|
881
|
+
how_not_seen: "Запрос с :default никогда не даёт промаха, а запрос с raise_on_missing_translations выбрасывает исключение до вызова любого обработчика, поэтому здесь не учитываются ни тот, ни другой"
|
|
882
|
+
how_buffered: "Промахи считаются в памяти и записываются в конце запроса или задания, так что они появятся с небольшой задержкой"
|
|
883
|
+
missing_keys: "Отсутствующие ключи"
|
|
884
|
+
total_misses: "Всего промахов"
|
|
885
|
+
locales_affected: "Затронутые локали"
|
|
886
|
+
all_title: "Отсутствующие ключи перевода"
|
|
887
|
+
column_key: "Ключ"
|
|
888
|
+
column_locale: "Локаль"
|
|
889
|
+
column_source: "Впервые замечен в"
|
|
890
|
+
column_misses: "Промахи"
|
|
891
|
+
column_first_seen: "Впервые замечен"
|
|
892
|
+
overflow_notice: "%{count} промахов не удалось отнести к ключу: буфер трекера (%{limit} ключей на поток) был заполнен."
|
|
893
|
+
footer_tip: "Добавьте ключ в файл локали или передайте :default. Ключи, на которые действительно наткнулись пользователи, идут первыми."
|
|
894
|
+
docs: "Руководство Rails по i18n"
|
|
895
|
+
|
|
896
|
+
boot_errors_page:
|
|
897
|
+
title: "Ошибки запуска"
|
|
898
|
+
empty_title: "Ошибки запуска не зафиксированы"
|
|
899
|
+
empty_body: "За последние %{days} дн. ни один процесс не упал при запуске."
|
|
900
|
+
how_title: "Как перехватываются ошибки запуска:"
|
|
901
|
+
how_enabled_html: "Перехват аварий должен быть включён (%{option})"
|
|
902
|
+
how_hooked: "RED регистрирует свой хук at_exit сразу после ваших инициализаторов и до eager loading в Rails, поэтому авария при запуске видна, даже если приложение так и не запустилось"
|
|
903
|
+
how_captured_html: "%{zeitwerk} из файла, определяющего не ту константу, %{syntax} в модели, инициализатор с исключением: всё, что убивает процесс до обработки первого запроса"
|
|
904
|
+
how_imported: "Авария записывается на диск, потому что базы данных ещё нет, и импортируется при следующем успешном запуске"
|
|
905
|
+
how_never: "Процесс, убитый SIGKILL или упавший с segfault, at_exit не увидит ни в одном инструменте"
|
|
906
|
+
unresolved: "Нерешённые"
|
|
907
|
+
boot_crashes: "Аварии при запуске"
|
|
908
|
+
failed_boots: "Неудачные запуски"
|
|
909
|
+
all_title: "Аварии при запуске по ошибке"
|
|
910
|
+
column_error: "Ошибка"
|
|
911
|
+
column_file: "Файл"
|
|
912
|
+
column_constant: "Константа"
|
|
913
|
+
column_boots: "Запуски"
|
|
914
|
+
column_first_seen: "Впервые замечена"
|
|
915
|
+
column_status: "Статус"
|
|
916
|
+
status_open: "Открыта"
|
|
917
|
+
status_resolved: "Решена"
|
|
918
|
+
footer_tip: "Авария при запуске означает, что процесс не обработал ни одного запроса. Исправьте её до следующего деплоя; строка закрывается как любая другая ошибка."
|
|
919
|
+
|
|
871
920
|
rack_attack_page:
|
|
872
921
|
title: События ограничения частоты
|
|
873
922
|
missing_title: Rack Attack не установлен
|
|
@@ -1153,7 +1202,7 @@ ru:
|
|
|
1153
1202
|
unable_to_detect: Не удалось определить
|
|
1154
1203
|
no_user_model: Модель User не обнаружена
|
|
1155
1204
|
unable_to_query_count: Не удалось получить количество
|
|
1156
|
-
|
|
1205
|
+
retention_enforced_by_job: "Удаляются RetentionCleanupJob, когда его запускает ваш планировщик"
|
|
1157
1206
|
keep_forever: Хранить всегда
|
|
1158
1207
|
no_automatic_deletion: Автоматическое удаление отключено
|
|
1159
1208
|
run_command: 'Выполните:'
|
|
@@ -1161,8 +1210,7 @@ ru:
|
|
|
1161
1210
|
options:
|
|
1162
1211
|
enable_middleware: Перехватывает необработанные исключения
|
|
1163
1212
|
enable_error_subscriber: Подписывается на события ошибок Rails
|
|
1164
|
-
retention_days:
|
|
1165
|
-
DAYS=90)'
|
|
1213
|
+
retention_days: "Удалять ошибки, не встречавшиеся столько дней. Выполняет RetentionCleanupJob, который гем сам не планирует"
|
|
1166
1214
|
max_backtrace_lines: Ограничение глубины backtrace
|
|
1167
1215
|
sampling_rate: Доля захватываемых ошибок
|
|
1168
1216
|
application_name: Имя этого приложения (определяется автоматически, если не
|
|
@@ -1180,7 +1228,7 @@ ru:
|
|
|
1180
1228
|
если не задано)
|
|
1181
1229
|
async_logging: Обработка в фоновых задачах
|
|
1182
1230
|
async_adapter: Адаптер очереди задач
|
|
1183
|
-
enable_rate_limiting: Ограничивать
|
|
1231
|
+
enable_rate_limiting: "Ограничивать запросы к панели по IP и пути"
|
|
1184
1232
|
rate_limit_per_minute: Запросов в минуту на IP
|
|
1185
1233
|
enable_slack_notifications: Уведомления в реальном времени
|
|
1186
1234
|
slack_webhook_url: Адрес webhook Slack
|
|
@@ -1189,10 +1237,15 @@ ru:
|
|
|
1189
1237
|
notification_email_from: Адрес отправителя
|
|
1190
1238
|
enable_discord_notifications: Уведомления через webhook Discord
|
|
1191
1239
|
discord_webhook_url: Адрес webhook Discord
|
|
1240
|
+
enable_telegram_notifications: "Уведомления Telegram через Bot API"
|
|
1241
|
+
telegram_bot_token: "Токен бота от @BotFather (задайте переменную окружения TELEGRAM_BOT_TOKEN)"
|
|
1242
|
+
telegram_chat_id: "Чат, группа или канал, куда пишет бот"
|
|
1243
|
+
telegram_api_base_url: "Сервер Bot API (менять только для прокси или собственного сервера)"
|
|
1192
1244
|
enable_pagerduty_notifications: Эскалация критических ошибок
|
|
1193
1245
|
pagerduty_integration_key: API-ключ PagerDuty
|
|
1194
1246
|
enable_webhook_notifications: Произвольные webhook-адреса
|
|
1195
1247
|
webhook_urls: Свои webhook-адреса
|
|
1248
|
+
webhook_signing_secret: Подписывает исходящие webhook-запросы HMAC-SHA256 (задайте переменную окружения WEBHOOK_SIGNING_SECRET)
|
|
1196
1249
|
enable_scheduled_digests: Ежедневные/еженедельные сводки. Планирование через
|
|
1197
1250
|
SolidQueue, Sidekiq или cron
|
|
1198
1251
|
digest_frequency: Как часто отправлять сводки
|
|
@@ -1211,7 +1264,7 @@ ru:
|
|
|
1211
1264
|
source_code_context_lines: Строк до и после целевой строки
|
|
1212
1265
|
enable_git_blame: Показывать сведения git blame
|
|
1213
1266
|
source_code_cache_ttl: Время жизни кэша исходного кода
|
|
1214
|
-
only_show_app_code_source: Скрывать
|
|
1267
|
+
only_show_app_code_source: "Скрывать код гемов и vendor в просмотрщике исходников"
|
|
1215
1268
|
git_branch_strategy: Стратегия определения ветки
|
|
1216
1269
|
enable_breadcrumbs: Записывать след активности запроса
|
|
1217
1270
|
breadcrumb_buffer_size: Максимум breadcrumbs на запрос
|
|
@@ -1241,6 +1294,7 @@ ru:
|
|
|
1241
1294
|
enable_crash_capture: Хук at_exit для необработанных аварийных завершений
|
|
1242
1295
|
enable_coverage_tracking: Диагностический режим — включите в панели, чтобы
|
|
1243
1296
|
видеть выполненные строки в исходном коде (Ruby 3.2+)
|
|
1297
|
+
enable_missing_translation_tracking: "Считает промахи I18n приложения по локали и ключу (оборачивает I18n.exception_handler)"
|
|
1244
1298
|
enable_rack_attack_tracking: Записывать события throttle/blocklist в отдельную
|
|
1245
1299
|
таблицу
|
|
1246
1300
|
enable_actioncable_tracking: Отслеживать события каналов WebSocket как breadcrumbs
|
|
@@ -1300,6 +1354,8 @@ ru:
|
|
|
1300
1354
|
breadcrumbs: Breadcrumbs
|
|
1301
1355
|
system_health: Состояние системы
|
|
1302
1356
|
swallowed_exceptions: Обнаружение подавленных исключений (swallowed exception)
|
|
1357
|
+
missing_translations: "Отслеживание отсутствующих переводов"
|
|
1358
|
+
boot_errors: "Перехват ошибок запуска"
|
|
1303
1359
|
rack_attack: Отслеживание Rack Attack
|
|
1304
1360
|
actioncable: Отслеживание ActionCable
|
|
1305
1361
|
activestorage: Отслеживание ActiveStorage
|
|
@@ -1713,6 +1769,13 @@ ru:
|
|
|
1713
1769
|
guide_link: Руководство по ActionCable
|
|
1714
1770
|
activestorage:
|
|
1715
1771
|
title: Состояние ActiveStorage
|
|
1772
|
+
probe:
|
|
1773
|
+
title: "Доступность сервиса"
|
|
1774
|
+
reachable: "Доступен"
|
|
1775
|
+
unreachable: "Недоступен"
|
|
1776
|
+
service: "Сервис: %{name}"
|
|
1777
|
+
latency: "%{ms} мс туда и обратно"
|
|
1778
|
+
how: "Одна проверка существования ключа, который никогда не сохраняется, при загрузке этой страницы. GET /health выполняет ту же проверку."
|
|
1716
1779
|
empty:
|
|
1717
1780
|
title: События ActiveStorage не найдены
|
|
1718
1781
|
message: За последние %{days} дн. в breadcrumbs ошибок не обнаружено операций
|
data/config/locales/uk.yml
CHANGED
|
@@ -60,6 +60,8 @@ uk:
|
|
|
60
60
|
llm: LLM
|
|
61
61
|
n_plus_one: Запити N+1
|
|
62
62
|
deprecations: Deprecations
|
|
63
|
+
missing_translations: "Переклади"
|
|
64
|
+
boot_errors: "Помилки запуску"
|
|
63
65
|
swallowed: Придушені
|
|
64
66
|
diagnostic_dumps: Діагностика
|
|
65
67
|
storms: Шторми
|
|
@@ -866,6 +868,53 @@ uk:
|
|
|
866
868
|
до error_log
|
|
867
869
|
footer_tip: Придушені винятки піднімаються, а потім мовчки перехоплюються.
|
|
868
870
|
Вони можуть приховувати справжні помилки.
|
|
871
|
+
missing_translations_page:
|
|
872
|
+
title: "Відсутні переклади"
|
|
873
|
+
empty_title: "Відсутні переклади не зафіксовано"
|
|
874
|
+
empty_body: "За останні %{days} дн. відсутніх ключів перекладу не зафіксовано."
|
|
875
|
+
how_title: "Як відстежуються відсутні переклади:"
|
|
876
|
+
how_enabled_html: "Відстеження має бути ввімкнено (%{option})"
|
|
877
|
+
how_hooked: "RED обгортає I18n.exception_handler і передає виклик обробнику, який уже був у застосунку; більше нічого в налаштуваннях I18n не змінюється"
|
|
878
|
+
how_recorded: "Кожен запит, що дійшов до обробника — як через I18n.t, так і через хелпер t() у view — рахується за локаллю та ключем разом із першим поміченим місцем виклику"
|
|
879
|
+
how_not_seen: "Запит із :default ніколи не промахується, а запит із raise_on_missing_translations кидає виняток до виклику будь-якого обробника, тому тут не враховуються ні той, ні інший"
|
|
880
|
+
how_buffered: "Промахи рахуються в пам'яті й записуються наприкінці запиту або завдання, тож вони з'являться з невеликою затримкою"
|
|
881
|
+
missing_keys: "Відсутні ключі"
|
|
882
|
+
total_misses: "Усього промахів"
|
|
883
|
+
locales_affected: "Зачеплені локалі"
|
|
884
|
+
all_title: "Відсутні ключі перекладу"
|
|
885
|
+
column_key: "Ключ"
|
|
886
|
+
column_locale: "Локаль"
|
|
887
|
+
column_source: "Уперше помічено в"
|
|
888
|
+
column_misses: "Промахи"
|
|
889
|
+
column_first_seen: "Уперше помічено"
|
|
890
|
+
overflow_notice: "%{count} промахів не вдалося віднести до ключа: буфер трекера (%{limit} ключів на потік) був заповнений."
|
|
891
|
+
footer_tip: "Додайте ключ до файлу локалі або передайте :default. Ключі, на які справді натрапили користувачі, йдуть першими."
|
|
892
|
+
docs: "Посібник Rails з i18n"
|
|
893
|
+
|
|
894
|
+
boot_errors_page:
|
|
895
|
+
title: "Помилки запуску"
|
|
896
|
+
empty_title: "Помилки запуску не зафіксовано"
|
|
897
|
+
empty_body: "За останні %{days} дн. жоден процес не впав під час запуску."
|
|
898
|
+
how_title: "Як перехоплюються помилки запуску:"
|
|
899
|
+
how_enabled_html: "Перехоплення аварій має бути ввімкнено (%{option})"
|
|
900
|
+
how_hooked: "RED реєструє свій хук at_exit одразу після ваших ініціалізаторів і до eager loading у Rails, тому аварія під час запуску видима, навіть якщо застосунок так і не запустився"
|
|
901
|
+
how_captured_html: "%{zeitwerk} із файлу, що визначає не ту константу, %{syntax} у моделі, ініціалізатор з винятком: усе, що вбиває процес до обробки першого запиту"
|
|
902
|
+
how_imported: "Аварія записується на диск, бо бази даних ще немає, і імпортується під час наступного успішного запуску"
|
|
903
|
+
how_never: "Процес, убитий SIGKILL або segfault, at_exit не побачить у жодному інструменті"
|
|
904
|
+
unresolved: "Невирішені"
|
|
905
|
+
boot_crashes: "Аварії під час запуску"
|
|
906
|
+
failed_boots: "Невдалі запуски"
|
|
907
|
+
all_title: "Аварії під час запуску за помилкою"
|
|
908
|
+
column_error: "Помилка"
|
|
909
|
+
column_file: "Файл"
|
|
910
|
+
column_constant: "Константа"
|
|
911
|
+
column_boots: "Запуски"
|
|
912
|
+
column_first_seen: "Уперше помічено"
|
|
913
|
+
column_status: "Статус"
|
|
914
|
+
status_open: "Відкрита"
|
|
915
|
+
status_resolved: "Вирішена"
|
|
916
|
+
footer_tip: "Аварія під час запуску означає, що процес не обробив жодного запиту. Виправте її до наступного розгортання; рядок закривається як будь-яка інша помилка."
|
|
917
|
+
|
|
869
918
|
rack_attack_page:
|
|
870
919
|
title: Події обмеження запитів
|
|
871
920
|
missing_title: Rack Attack не встановлено
|
|
@@ -1149,7 +1198,7 @@ uk:
|
|
|
1149
1198
|
unable_to_detect: Не вдалося визначити
|
|
1150
1199
|
no_user_model: Модель User не виявлено
|
|
1151
1200
|
unable_to_query_count: Не вдалося отримати кількість
|
|
1152
|
-
|
|
1201
|
+
retention_enforced_by_job: "Видаляються RetentionCleanupJob, коли його запускає ваш планувальник"
|
|
1153
1202
|
keep_forever: Зберігати назавжди
|
|
1154
1203
|
no_automatic_deletion: Без автоматичного видалення
|
|
1155
1204
|
run_command: 'Виконайте:'
|
|
@@ -1157,8 +1206,7 @@ uk:
|
|
|
1157
1206
|
options:
|
|
1158
1207
|
enable_middleware: Перехоплює необроблені винятки
|
|
1159
1208
|
enable_error_subscriber: Підписується на події помилок Rails
|
|
1160
|
-
retention_days:
|
|
1161
|
-
DAYS=90)'
|
|
1209
|
+
retention_days: "Видаляти помилки, яких не було стільки днів. Виконує RetentionCleanupJob, який гем сам не планує"
|
|
1162
1210
|
max_backtrace_lines: Обмеження глибини стеку викликів
|
|
1163
1211
|
sampling_rate: Відсоток захоплених помилок
|
|
1164
1212
|
application_name: Назва цього застосунку (визначається автоматично, якщо не
|
|
@@ -1176,7 +1224,7 @@ uk:
|
|
|
1176
1224
|
якщо не задано)
|
|
1177
1225
|
async_logging: Обробка у фонових завданнях
|
|
1178
1226
|
async_adapter: Адаптер черги завдань
|
|
1179
|
-
enable_rate_limiting: Обмежувати запити до
|
|
1227
|
+
enable_rate_limiting: "Обмежувати запити до панелі за IP і шляхом"
|
|
1180
1228
|
rate_limit_per_minute: Запитів за хвилину з однієї IP-адреси
|
|
1181
1229
|
enable_slack_notifications: Сповіщення в реальному часі
|
|
1182
1230
|
slack_webhook_url: Кінцева точка webhook у Slack
|
|
@@ -1185,10 +1233,15 @@ uk:
|
|
|
1185
1233
|
notification_email_from: Адреса відправника
|
|
1186
1234
|
enable_discord_notifications: Сповіщення через webhook у Discord
|
|
1187
1235
|
discord_webhook_url: Кінцева точка webhook у Discord
|
|
1236
|
+
enable_telegram_notifications: "Сповіщення Telegram через Bot API"
|
|
1237
|
+
telegram_bot_token: "Токен бота від @BotFather (задайте змінну середовища TELEGRAM_BOT_TOKEN)"
|
|
1238
|
+
telegram_chat_id: "Чат, група або канал, куди пише бот"
|
|
1239
|
+
telegram_api_base_url: "Сервер Bot API (змінюйте лише для проксі або власного сервера)"
|
|
1188
1240
|
enable_pagerduty_notifications: Ескалація критичних помилок
|
|
1189
1241
|
pagerduty_integration_key: Ключ API PagerDuty
|
|
1190
1242
|
enable_webhook_notifications: Довільні кінцеві точки webhook
|
|
1191
1243
|
webhook_urls: Власні кінцеві точки webhook
|
|
1244
|
+
webhook_signing_secret: Підписує вихідні webhook-запити HMAC-SHA256 (задайте змінну середовища WEBHOOK_SIGNING_SECRET)
|
|
1192
1245
|
enable_scheduled_digests: Щоденні/щотижневі підсумкові листи. Плануйте через
|
|
1193
1246
|
SolidQueue, Sidekiq або cron
|
|
1194
1247
|
digest_frequency: Як часто надсилати підсумкові листи
|
|
@@ -1209,7 +1262,7 @@ uk:
|
|
|
1209
1262
|
source_code_context_lines: Рядків до та після цільового рядка
|
|
1210
1263
|
enable_git_blame: Показувати дані git blame
|
|
1211
1264
|
source_code_cache_ttl: Тривалість кешування вихідного коду
|
|
1212
|
-
only_show_app_code_source:
|
|
1265
|
+
only_show_app_code_source: "Приховувати код гемів і vendor у переглядачі коду"
|
|
1213
1266
|
git_branch_strategy: Стратегія визначення гілки
|
|
1214
1267
|
enable_breadcrumbs: Захоплювати послідовність дій у запиті
|
|
1215
1268
|
breadcrumb_buffer_size: Максимум breadcrumbs на запит
|
|
@@ -1240,6 +1293,7 @@ uk:
|
|
|
1240
1293
|
enable_crash_capture: Хук at_exit для необроблених аварійних завершень
|
|
1241
1294
|
enable_coverage_tracking: Діагностичний режим — увімкніть через панель, щоб
|
|
1242
1295
|
бачити виконані рядки у перегляді коду (Ruby 3.2+)
|
|
1296
|
+
enable_missing_translation_tracking: "Рахує промахи I18n застосунку за локаллю та ключем (обгортає I18n.exception_handler)"
|
|
1243
1297
|
enable_rack_attack_tracking: Записувати події throttle/blocklist в окрему
|
|
1244
1298
|
таблицю
|
|
1245
1299
|
enable_actioncable_tracking: Відстежувати події каналів WebSocket як breadcrumbs
|
|
@@ -1299,6 +1353,8 @@ uk:
|
|
|
1299
1353
|
breadcrumbs: Breadcrumbs
|
|
1300
1354
|
system_health: Стан системи
|
|
1301
1355
|
swallowed_exceptions: Виявлення придушених винятків
|
|
1356
|
+
missing_translations: "Відстеження відсутніх перекладів"
|
|
1357
|
+
boot_errors: "Перехоплення помилок запуску"
|
|
1302
1358
|
rack_attack: Відстеження Rack Attack
|
|
1303
1359
|
actioncable: Відстеження ActionCable
|
|
1304
1360
|
activestorage: Відстеження ActiveStorage
|
|
@@ -1712,6 +1768,13 @@ uk:
|
|
|
1712
1768
|
guide_link: Посібник з ActionCable
|
|
1713
1769
|
activestorage:
|
|
1714
1770
|
title: Стан ActiveStorage
|
|
1771
|
+
probe:
|
|
1772
|
+
title: "Доступність сервісу"
|
|
1773
|
+
reachable: "Доступний"
|
|
1774
|
+
unreachable: "Недоступний"
|
|
1775
|
+
service: "Сервіс: %{name}"
|
|
1776
|
+
latency: "%{ms} мс туди й назад"
|
|
1777
|
+
how: "Одна перевірка існування ключа, який ніколи не зберігається, під час завантаження цієї сторінки. GET /health виконує ту саму перевірку."
|
|
1715
1778
|
empty:
|
|
1716
1779
|
title: Подій ActiveStorage не знайдено
|
|
1717
1780
|
message: За останні %{days} днів у breadcrumbs помилок не виявлено операцій
|
data/config/locales/zh-CN.yml
CHANGED
|
@@ -60,6 +60,8 @@ zh-CN:
|
|
|
60
60
|
llm: LLM
|
|
61
61
|
n_plus_one: N+1 查询
|
|
62
62
|
deprecations: Deprecations
|
|
63
|
+
missing_translations: "翻译"
|
|
64
|
+
boot_errors: "启动错误"
|
|
63
65
|
swallowed: 被吞异常
|
|
64
66
|
diagnostic_dumps: 诊断
|
|
65
67
|
storms: 风暴
|
|
@@ -753,6 +755,53 @@ zh-CN:
|
|
|
753
755
|
column_ratio: 比例
|
|
754
756
|
view_unrescued: 查看未被捕获、已进入 error_log 的 %{exception} 错误
|
|
755
757
|
footer_tip: 被吞异常先被抛出,随后被静默捕获,可能掩盖真正的缺陷。
|
|
758
|
+
missing_translations_page:
|
|
759
|
+
title: "缺失的翻译"
|
|
760
|
+
empty_title: "未记录到缺失的翻译"
|
|
761
|
+
empty_body: "最近 %{days} 天内未记录到缺失的翻译键。"
|
|
762
|
+
how_title: "缺失翻译的跟踪方式:"
|
|
763
|
+
how_enabled_html: "必须启用跟踪(%{option})"
|
|
764
|
+
how_hooked: "RED 会包装 I18n.exception_handler,并把调用交给应用原有的处理器;I18n 配置的其他部分不会改变"
|
|
765
|
+
how_recorded: "每一次到达处理器的查找——无论来自 I18n.t 还是视图助手 t()——都会按语言区域和键计数,并记录首次观测到的调用位置"
|
|
766
|
+
how_not_seen: "提供了 :default 的查找永远不会缺失;使用 raise_on_missing_translations 的查找会在任何处理器运行前抛出异常,因此两者都不会在此计数"
|
|
767
|
+
how_buffered: "缺失在内存中计数,并在请求或任务结束时写入,因此显示会有短暂延迟"
|
|
768
|
+
missing_keys: "缺失的键"
|
|
769
|
+
total_misses: "缺失总数"
|
|
770
|
+
locales_affected: "受影响的语言区域"
|
|
771
|
+
all_title: "缺失的翻译键"
|
|
772
|
+
column_key: "键"
|
|
773
|
+
column_locale: "语言区域"
|
|
774
|
+
column_source: "首次出现于"
|
|
775
|
+
column_misses: "缺失次数"
|
|
776
|
+
column_first_seen: "首次出现"
|
|
777
|
+
overflow_notice: "由于跟踪器的缓冲区(每线程 %{limit} 个键)已满,有 %{count} 次缺失无法归到具体的键。"
|
|
778
|
+
footer_tip: "把该键加入语言文件,或传入 :default。用户实际遇到的键排在最前。"
|
|
779
|
+
docs: "Rails i18n 指南"
|
|
780
|
+
|
|
781
|
+
boot_errors_page:
|
|
782
|
+
title: "启动错误"
|
|
783
|
+
empty_title: "未记录到启动错误"
|
|
784
|
+
empty_body: "最近 %{days} 天内没有进程在启动时崩溃。"
|
|
785
|
+
how_title: "启动错误的捕获方式:"
|
|
786
|
+
how_enabled_html: "必须启用崩溃捕获(%{option})"
|
|
787
|
+
how_hooked: "RED 在你的 initializer 运行之后、Rails 预加载之前注册 at_exit 钩子,因此即使应用从未完成启动,启动期间的崩溃也会被捕获"
|
|
788
|
+
how_captured_html: "文件定义了错误常量导致的 %{zeitwerk}、模型中的 %{syntax}、抛出异常的 initializer:任何在处理请求之前就终止进程的问题"
|
|
789
|
+
how_imported: "此时还没有数据库,所以崩溃先写入磁盘,并在下一次成功启动时导入"
|
|
790
|
+
how_never: "被 SIGKILL 或段错误终止的进程,任何工具的 at_exit 都看不到"
|
|
791
|
+
unresolved: "未解决"
|
|
792
|
+
boot_crashes: "启动崩溃"
|
|
793
|
+
failed_boots: "失败的启动"
|
|
794
|
+
all_title: "按错误分组的启动崩溃"
|
|
795
|
+
column_error: "错误"
|
|
796
|
+
column_file: "文件"
|
|
797
|
+
column_constant: "常量"
|
|
798
|
+
column_boots: "启动次数"
|
|
799
|
+
column_first_seen: "首次出现"
|
|
800
|
+
column_status: "状态"
|
|
801
|
+
status_open: "未处理"
|
|
802
|
+
status_resolved: "已解决"
|
|
803
|
+
footer_tip: "启动崩溃意味着进程从未处理过请求。请在下次部署前修复;该行会像其他错误一样被标记为已解决。"
|
|
804
|
+
|
|
756
805
|
rack_attack_page:
|
|
757
806
|
title: 限流事件
|
|
758
807
|
missing_title: 尚未安装 Rack Attack
|
|
@@ -967,7 +1016,7 @@ zh-CN:
|
|
|
967
1016
|
unable_to_detect: 无法检测
|
|
968
1017
|
no_user_model: 未检测到 User 模型
|
|
969
1018
|
unable_to_query_count: 无法查询数量
|
|
970
|
-
|
|
1019
|
+
retention_enforced_by_job: "由 RetentionCleanupJob 在您的调度器运行它时删除"
|
|
971
1020
|
keep_forever: 永久保留
|
|
972
1021
|
no_automatic_deletion: 不自动删除
|
|
973
1022
|
run_command: 执行:
|
|
@@ -975,7 +1024,7 @@ zh-CN:
|
|
|
975
1024
|
options:
|
|
976
1025
|
enable_middleware: 捕获未处理的异常
|
|
977
1026
|
enable_error_subscriber: 订阅 Rails 错误事件
|
|
978
|
-
retention_days:
|
|
1027
|
+
retention_days: "删除这么多天内未再出现的错误。由 RetentionCleanupJob 执行,gem 本身不会安排它运行"
|
|
979
1028
|
max_backtrace_lines: 堆栈跟踪深度上限
|
|
980
1029
|
sampling_rate: 错误捕获的采样比例
|
|
981
1030
|
application_name: 本应用的名称(未设置时自动检测)
|
|
@@ -989,7 +1038,7 @@ zh-CN:
|
|
|
989
1038
|
total_users_for_impact: 用于计算影响百分比(未设置时自动检测)
|
|
990
1039
|
async_logging: 在后台任务中处理
|
|
991
1040
|
async_adapter: 任务队列适配器
|
|
992
|
-
enable_rate_limiting:
|
|
1041
|
+
enable_rate_limiting: "按 IP 和路径限制仪表盘请求"
|
|
993
1042
|
rate_limit_per_minute: 每个 IP 每分钟的请求数
|
|
994
1043
|
enable_slack_notifications: 实时通知
|
|
995
1044
|
slack_webhook_url: Slack webhook 地址
|
|
@@ -998,10 +1047,15 @@ zh-CN:
|
|
|
998
1047
|
notification_email_from: 发件人地址
|
|
999
1048
|
enable_discord_notifications: 通过 Discord webhook 通知
|
|
1000
1049
|
discord_webhook_url: Discord webhook 地址
|
|
1050
|
+
enable_telegram_notifications: "Telegram Bot API 通知"
|
|
1051
|
+
telegram_bot_token: "来自 @BotFather 的机器人令牌(设置环境变量 TELEGRAM_BOT_TOKEN)"
|
|
1052
|
+
telegram_chat_id: "机器人发送消息的聊天、群组或频道"
|
|
1053
|
+
telegram_api_base_url: "Bot API 服务器(仅在使用代理或自建服务器时更改)"
|
|
1001
1054
|
enable_pagerduty_notifications: 严重错误升级
|
|
1002
1055
|
pagerduty_integration_key: PagerDuty API 密钥
|
|
1003
1056
|
enable_webhook_notifications: 通用 webhook 地址
|
|
1004
1057
|
webhook_urls: 自定义 webhook 地址
|
|
1058
|
+
webhook_signing_secret: 使用 HMAC-SHA256 签名发出的 webhook(设置环境变量 WEBHOOK_SIGNING_SECRET)
|
|
1005
1059
|
enable_scheduled_digests: 每日/每周摘要邮件。可通过 SolidQueue、Sidekiq 或 cron 调度
|
|
1006
1060
|
digest_frequency: 摘要邮件的发送频率
|
|
1007
1061
|
digest_recipients: 邮件地址(默认使用通知收件人)
|
|
@@ -1019,7 +1073,7 @@ zh-CN:
|
|
|
1019
1073
|
source_code_context_lines: 目标行前后显示的行数
|
|
1020
1074
|
enable_git_blame: 显示 git blame 信息
|
|
1021
1075
|
source_code_cache_ttl: 源代码缓存时长
|
|
1022
|
-
only_show_app_code_source:
|
|
1076
|
+
only_show_app_code_source: "在源码查看器中隐藏 gem 和 vendor 代码"
|
|
1023
1077
|
git_branch_strategy: 分支解析策略
|
|
1024
1078
|
enable_breadcrumbs: 记录请求的活动轨迹
|
|
1025
1079
|
breadcrumb_buffer_size: 每个请求最多记录的 breadcrumbs 数
|
|
@@ -1043,6 +1097,7 @@ zh-CN:
|
|
|
1043
1097
|
enable_diagnostic_dump: 按需生成系统状态快照
|
|
1044
1098
|
enable_crash_capture: 用 at_exit 钩子捕获未处理的崩溃
|
|
1045
1099
|
enable_coverage_tracking: 诊断模式 — 在面板中启用后,可在源码视图中看到已执行的行(Ruby 3.2+)
|
|
1100
|
+
enable_missing_translation_tracking: "按语言区域和键统计应用的 I18n 缺失(包装 I18n.exception_handler)"
|
|
1046
1101
|
enable_rack_attack_tracking: 将 throttle/blocklist 事件记录到独立数据表
|
|
1047
1102
|
enable_actioncable_tracking: 将 WebSocket 频道事件记录为 breadcrumbs
|
|
1048
1103
|
enable_activestorage_tracking: 将上传/下载/删除记录为 breadcrumbs
|
|
@@ -1088,6 +1143,8 @@ zh-CN:
|
|
|
1088
1143
|
breadcrumbs: Breadcrumbs
|
|
1089
1144
|
system_health: 系统状态
|
|
1090
1145
|
swallowed_exceptions: 被吞异常检测
|
|
1146
|
+
missing_translations: "缺失翻译跟踪"
|
|
1147
|
+
boot_errors: "启动错误捕获"
|
|
1091
1148
|
rack_attack: Rack Attack 跟踪
|
|
1092
1149
|
actioncable: ActionCable 跟踪
|
|
1093
1150
|
activestorage: ActiveStorage 跟踪
|
|
@@ -1450,6 +1507,13 @@ zh-CN:
|
|
|
1450
1507
|
guide_link: ActionCable 指南
|
|
1451
1508
|
activestorage:
|
|
1452
1509
|
title: ActiveStorage 状态
|
|
1510
|
+
probe:
|
|
1511
|
+
title: "服务可达性"
|
|
1512
|
+
reachable: "可达"
|
|
1513
|
+
unreachable: "不可达"
|
|
1514
|
+
service: "服务:%{name}"
|
|
1515
|
+
latency: "往返 %{ms} ms"
|
|
1516
|
+
how: "加载本页时对一个永远不会存储的键做一次存在性检查。GET /health 执行同样的探测。"
|
|
1453
1517
|
empty:
|
|
1454
1518
|
title: 未找到 ActiveStorage 事件
|
|
1455
1519
|
message: 最近 %{days} 天的错误 breadcrumbs 中未检测到 ActiveStorage 的服务操作。
|
data/config/routes.rb
CHANGED
|
@@ -7,6 +7,10 @@ RailsErrorDashboard::Engine.routes.draw do
|
|
|
7
7
|
# Settings page
|
|
8
8
|
get "settings", to: "errors#settings", as: :settings
|
|
9
9
|
|
|
10
|
+
# Health check (JSON): error database, queue, storm breaker, gem version.
|
|
11
|
+
# 200 when the dashboard can do its job, 503 when the error DB is unreachable.
|
|
12
|
+
get "health", to: "health#show", as: :health
|
|
13
|
+
|
|
10
14
|
# Per-user dashboard language, persisted in the session (P5-T1).
|
|
11
15
|
# POST only: changing it is a state change, and a GET would let any link or
|
|
12
16
|
# prefetch alter the user's language.
|
|
@@ -41,6 +45,8 @@ RailsErrorDashboard::Engine.routes.draw do
|
|
|
41
45
|
get :database_health_summary
|
|
42
46
|
get :swallowed_exceptions
|
|
43
47
|
get :rack_attack_summary
|
|
48
|
+
get :missing_translations
|
|
49
|
+
get :boot_errors
|
|
44
50
|
get :actioncable_health_summary
|
|
45
51
|
get :activestorage_health_summary
|
|
46
52
|
get :llm_health_summary
|
|
@@ -26,7 +26,7 @@ class CreateRailsErrorDashboardCompleteSchema < ActiveRecord::Migration[7.0]
|
|
|
26
26
|
t.string :error_type, null: false
|
|
27
27
|
t.text :message, null: false
|
|
28
28
|
t.text :backtrace
|
|
29
|
-
t.
|
|
29
|
+
t.column :user_id, user_id_type
|
|
30
30
|
t.text :request_url
|
|
31
31
|
t.text :request_params
|
|
32
32
|
t.text :user_agent
|
|
@@ -157,7 +157,7 @@ class CreateRailsErrorDashboardCompleteSchema < ActiveRecord::Migration[7.0]
|
|
|
157
157
|
create_table :rails_error_dashboard_error_occurrences do |t|
|
|
158
158
|
t.bigint :error_log_id, null: false
|
|
159
159
|
t.datetime :occurred_at, null: false
|
|
160
|
-
t.
|
|
160
|
+
t.column :user_id, user_id_type
|
|
161
161
|
t.string :request_id
|
|
162
162
|
t.string :session_id
|
|
163
163
|
t.timestamps
|
|
@@ -275,4 +275,12 @@ class CreateRailsErrorDashboardCompleteSchema < ActiveRecord::Migration[7.0]
|
|
|
275
275
|
drop_table :rails_error_dashboard_error_logs, if_exists: true
|
|
276
276
|
drop_table :rails_error_dashboard_applications, if_exists: true
|
|
277
277
|
end
|
|
278
|
+
|
|
279
|
+
private
|
|
280
|
+
|
|
281
|
+
# Same type as the app's primary keys, as ActiveStorage does for record_id.
|
|
282
|
+
def user_id_type
|
|
283
|
+
config = Rails.configuration.generators
|
|
284
|
+
config.options[config.orm][:primary_key_type] || :integer
|
|
285
|
+
end
|
|
278
286
|
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# One row per (locale, key, application) the host app failed to translate.
|
|
4
|
+
#
|
|
5
|
+
# A missing translation is not an error: Rails renders "translation missing"
|
|
6
|
+
# (or the humanized key) and the request succeeds, so it never reaches
|
|
7
|
+
# error_logs and nothing in the dashboard would otherwise show it. The
|
|
8
|
+
# tracker counts misses in memory and upserts them here at the end of the
|
|
9
|
+
# request or job that produced them -- a loop rendering a missing key a
|
|
10
|
+
# thousand times is one UPDATE, not a thousand INSERTs.
|
|
11
|
+
class CreateMissingTranslations < ActiveRecord::Migration[7.0]
|
|
12
|
+
def change
|
|
13
|
+
# Guard against the squashed schema migration having already created this
|
|
14
|
+
# table -- without it, every later migration is silently cancelled.
|
|
15
|
+
return if table_exists?(:rails_error_dashboard_missing_translations)
|
|
16
|
+
|
|
17
|
+
create_table :rails_error_dashboard_missing_translations do |t|
|
|
18
|
+
# BCP 47 tags ("pt-BR", "zh-Hans-CN", "en-US-x-twain") fit in 35.
|
|
19
|
+
t.string :locale, null: false, limit: 35
|
|
20
|
+
# The full dotted key as I18n normalised it ("users.show.greeting").
|
|
21
|
+
# Capped at 191 so the unique upsert index stays inside MySQL's
|
|
22
|
+
# 3072-byte utf8mb4 limit: (35 + 191) * 4 + application_id. The tracker
|
|
23
|
+
# truncates before the value reaches the index.
|
|
24
|
+
t.string :translation_key, null: false, limit: 191
|
|
25
|
+
# First host call site seen for this key ("app/views/users/show.html.erb:12").
|
|
26
|
+
# First-write-wins; not part of the row's identity.
|
|
27
|
+
t.string :source, limit: 250
|
|
28
|
+
t.bigint :miss_count, null: false, default: 0
|
|
29
|
+
t.datetime :first_seen_at, null: false
|
|
30
|
+
t.datetime :last_seen_at, null: false
|
|
31
|
+
# Nullable: a miss recorded before application scoping, or with no
|
|
32
|
+
# application_name configured, applies to the whole install.
|
|
33
|
+
t.bigint :application_id
|
|
34
|
+
t.timestamps
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Named explicitly: an auto-generated name would exceed PostgreSQL's
|
|
38
|
+
# 63-character limit and fail during the HOST app's deploy.
|
|
39
|
+
add_index :rails_error_dashboard_missing_translations,
|
|
40
|
+
[ :locale, :translation_key, :application_id ],
|
|
41
|
+
unique: true,
|
|
42
|
+
name: "index_red_missing_translations_upsert_key"
|
|
43
|
+
|
|
44
|
+
# The dashboard reads "misses seen in the last N days" and retention
|
|
45
|
+
# prunes by the same column.
|
|
46
|
+
add_index :rails_error_dashboard_missing_translations,
|
|
47
|
+
:last_seen_at,
|
|
48
|
+
name: "index_red_missing_translations_on_last_seen_at"
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -12,6 +12,7 @@ module RailsErrorDashboard
|
|
|
12
12
|
class_option :slack, type: :boolean, default: false, desc: "Enable Slack notifications"
|
|
13
13
|
class_option :email, type: :boolean, default: false, desc: "Enable email notifications"
|
|
14
14
|
class_option :discord, type: :boolean, default: false, desc: "Enable Discord notifications"
|
|
15
|
+
class_option :telegram, type: :boolean, default: false, desc: "Enable Telegram notifications"
|
|
15
16
|
class_option :pagerduty, type: :boolean, default: false, desc: "Enable PagerDuty notifications"
|
|
16
17
|
class_option :webhooks, type: :boolean, default: false, desc: "Enable webhook notifications"
|
|
17
18
|
# Performance options
|
|
@@ -71,13 +72,13 @@ module RailsErrorDashboard
|
|
|
71
72
|
@selected_features = {}
|
|
72
73
|
|
|
73
74
|
# =====================================================================
|
|
74
|
-
# QUESTION 1: Notifications (gated — one y/N opens
|
|
75
|
+
# QUESTION 1: Notifications (gated — one y/N opens 6 sub-questions)
|
|
75
76
|
# =====================================================================
|
|
76
|
-
notification_keys = %i[slack email discord pagerduty webhooks]
|
|
77
|
+
notification_keys = %i[slack email discord telegram pagerduty webhooks]
|
|
77
78
|
any_notification_cli_flag = notification_keys.any? { |k| options[k] }
|
|
78
79
|
|
|
79
80
|
say "[1/3] Notifications [background/dashboard only — zero request overhead]", :cyan
|
|
80
|
-
say " Alert your team via Slack, email, Discord, PagerDuty, or webhooks.", :white
|
|
81
|
+
say " Alert your team via Slack, email, Discord, Telegram, PagerDuty, or webhooks.", :white
|
|
81
82
|
|
|
82
83
|
if any_notification_cli_flag
|
|
83
84
|
# Individual CLI flags passed — respect them, skip the gate prompt
|
|
@@ -90,6 +91,7 @@ module RailsErrorDashboard
|
|
|
90
91
|
{ key: :slack, name: "Slack", hint: "SLACK_WEBHOOK_URL" },
|
|
91
92
|
{ key: :email, name: "Email", hint: "ERROR_NOTIFICATION_EMAILS" },
|
|
92
93
|
{ key: :discord, name: "Discord", hint: "DISCORD_WEBHOOK_URL" },
|
|
94
|
+
{ key: :telegram, name: "Telegram", hint: "TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID" },
|
|
93
95
|
{ key: :pagerduty, name: "PagerDuty", hint: "PAGERDUTY_INTEGRATION_KEY" },
|
|
94
96
|
{ key: :webhooks, name: "Webhooks", hint: "WEBHOOK_URLS" }
|
|
95
97
|
]
|
|
@@ -294,6 +296,7 @@ module RailsErrorDashboard
|
|
|
294
296
|
@enable_slack = @selected_features&.dig(:slack) || options[:slack]
|
|
295
297
|
@enable_email = @selected_features&.dig(:email) || options[:email]
|
|
296
298
|
@enable_discord = @selected_features&.dig(:discord) || options[:discord]
|
|
299
|
+
@enable_telegram = @selected_features&.dig(:telegram) || options[:telegram]
|
|
297
300
|
@enable_pagerduty = @selected_features&.dig(:pagerduty) || options[:pagerduty]
|
|
298
301
|
@enable_webhooks = @selected_features&.dig(:webhooks) || options[:webhooks]
|
|
299
302
|
|
|
@@ -417,6 +420,7 @@ module RailsErrorDashboard
|
|
|
417
420
|
notification_features << "Slack" if @enable_slack
|
|
418
421
|
notification_features << "Email" if @enable_email
|
|
419
422
|
notification_features << "Discord" if @enable_discord
|
|
423
|
+
notification_features << "Telegram" if @enable_telegram
|
|
420
424
|
notification_features << "PagerDuty" if @enable_pagerduty
|
|
421
425
|
notification_features << "Webhooks" if @enable_webhooks
|
|
422
426
|
|
|
@@ -481,6 +485,7 @@ module RailsErrorDashboard
|
|
|
481
485
|
say " → Set SLACK_WEBHOOK_URL in .env", :yellow if @enable_slack
|
|
482
486
|
say " → Set ERROR_NOTIFICATION_EMAILS in .env", :yellow if @enable_email
|
|
483
487
|
say " → Set DISCORD_WEBHOOK_URL in .env", :yellow if @enable_discord
|
|
488
|
+
say " → Set TELEGRAM_BOT_TOKEN and TELEGRAM_CHAT_ID in .env", :yellow if @enable_telegram
|
|
484
489
|
say " → Set PAGERDUTY_INTEGRATION_KEY in .env", :yellow if @enable_pagerduty
|
|
485
490
|
say " → Set WEBHOOK_URLS in .env", :yellow if @enable_webhooks
|
|
486
491
|
if @enable_async_logging
|
|
@@ -569,7 +574,7 @@ module RailsErrorDashboard
|
|
|
569
574
|
system_health: true, # ~1ms per error — GC, memory, threads at exact error moment
|
|
570
575
|
error_sampling: true, # 50% sampling on non-critical errors — halves storage, still shows patterns
|
|
571
576
|
# OFF — require credentials, config, or niche use case
|
|
572
|
-
slack: false, email: false, discord: false, pagerduty: false, webhooks: false,
|
|
577
|
+
slack: false, email: false, discord: false, telegram: false, pagerduty: false, webhooks: false,
|
|
573
578
|
source_code_integration: false,
|
|
574
579
|
git_blame: false,
|
|
575
580
|
swallowed_exceptions: false,
|