rails_error_dashboard 0.8.4 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +35 -0
- data/app/controllers/rails_error_dashboard/application_controller.rb +107 -4
- data/app/controllers/rails_error_dashboard/errors_controller.rb +91 -73
- data/app/controllers/rails_error_dashboard/locales_controller.rb +87 -0
- data/app/helpers/rails_error_dashboard/application_helper.rb +20 -14
- data/app/helpers/rails_error_dashboard/backtrace_helper.rb +15 -6
- data/app/helpers/rails_error_dashboard/i18n_helper.rb +154 -0
- data/app/helpers/rails_error_dashboard/mailer_i18n_helper.rb +69 -0
- data/app/helpers/rails_error_dashboard/overview_helper.rb +18 -6
- data/app/helpers/rails_error_dashboard/user_agent_helper.rb +25 -11
- data/app/jobs/rails_error_dashboard/application_job.rb +5 -0
- data/app/jobs/rails_error_dashboard/baseline_alert_job.rb +18 -16
- data/app/jobs/rails_error_dashboard/concerns/localized_job.rb +83 -0
- data/app/jobs/rails_error_dashboard/discord_error_notification_job.rb +4 -2
- data/app/jobs/rails_error_dashboard/email_error_notification_job.rb +4 -2
- data/app/jobs/rails_error_dashboard/pagerduty_error_notification_job.rb +6 -2
- data/app/jobs/rails_error_dashboard/scheduled_digest_job.rb +8 -3
- data/app/jobs/rails_error_dashboard/slack_error_notification_job.rb +6 -4
- data/app/jobs/rails_error_dashboard/storm_notification_job.rb +26 -8
- data/app/jobs/rails_error_dashboard/webhook_error_notification_job.rb +4 -2
- data/app/mailers/rails_error_dashboard/application_mailer.rb +14 -0
- data/app/mailers/rails_error_dashboard/digest_mailer.rb +18 -2
- data/app/mailers/rails_error_dashboard/error_notification_mailer.rb +19 -2
- data/app/views/layouts/rails_error_dashboard.html.erb +255 -92
- data/app/views/rails_error_dashboard/digest_mailer/digest_summary.html.erb +23 -22
- data/app/views/rails_error_dashboard/digest_mailer/digest_summary.text.erb +30 -19
- data/app/views/rails_error_dashboard/error_notification_mailer/error_alert.html.erb +18 -16
- data/app/views/rails_error_dashboard/error_notification_mailer/error_alert.text.erb +21 -14
- data/app/views/rails_error_dashboard/errors/_ai_help_panel.html.erb +11 -7
- data/app/views/rails_error_dashboard/errors/_breadcrumbs_group.html.erb +45 -38
- data/app/views/rails_error_dashboard/errors/_co_occurring_errors.html.erb +17 -14
- data/app/views/rails_error_dashboard/errors/_discussion.html.erb +27 -9
- data/app/views/rails_error_dashboard/errors/_error_cascades.html.erb +25 -21
- data/app/views/rails_error_dashboard/errors/_error_info.html.erb +25 -22
- data/app/views/rails_error_dashboard/errors/_error_row.html.erb +24 -12
- data/app/views/rails_error_dashboard/errors/_instance_variables.html.erb +12 -11
- data/app/views/rails_error_dashboard/errors/_issue_section.html.erb +19 -13
- data/app/views/rails_error_dashboard/errors/_llm_summary.html.erb +14 -14
- data/app/views/rails_error_dashboard/errors/_local_variables.html.erb +8 -8
- data/app/views/rails_error_dashboard/errors/_modals.html.erb +60 -52
- data/app/views/rails_error_dashboard/errors/_pattern_insights.html.erb +59 -49
- data/app/views/rails_error_dashboard/errors/_request_context.html.erb +23 -20
- data/app/views/rails_error_dashboard/errors/_show_scripts.html.erb +14 -14
- data/app/views/rails_error_dashboard/errors/_sidebar_metadata.html.erb +118 -93
- data/app/views/rails_error_dashboard/errors/_similar_errors.html.erb +18 -12
- data/app/views/rails_error_dashboard/errors/_source_code.html.erb +20 -5
- data/app/views/rails_error_dashboard/errors/_stats.html.erb +5 -5
- data/app/views/rails_error_dashboard/errors/_timeline.html.erb +7 -7
- data/app/views/rails_error_dashboard/errors/_user_errors_table.html.erb +15 -12
- data/app/views/rails_error_dashboard/errors/actioncable_health_summary.html.erb +25 -25
- data/app/views/rails_error_dashboard/errors/activestorage_health_summary.html.erb +28 -28
- data/app/views/rails_error_dashboard/errors/analytics.html.erb +82 -82
- data/app/views/rails_error_dashboard/errors/cache_health_summary.html.erb +27 -27
- data/app/views/rails_error_dashboard/errors/correlation.html.erb +61 -57
- data/app/views/rails_error_dashboard/errors/database_health_summary.html.erb +64 -65
- data/app/views/rails_error_dashboard/errors/deprecations.html.erb +23 -23
- data/app/views/rails_error_dashboard/errors/diagnostic_dumps.html.erb +48 -36
- data/app/views/rails_error_dashboard/errors/index.html.erb +121 -70
- data/app/views/rails_error_dashboard/errors/job_health_summary.html.erb +30 -30
- data/app/views/rails_error_dashboard/errors/llm_health_summary.html.erb +38 -39
- data/app/views/rails_error_dashboard/errors/n_plus_one_summary.html.erb +28 -25
- data/app/views/rails_error_dashboard/errors/overview.html.erb +45 -39
- data/app/views/rails_error_dashboard/errors/platform_comparison.html.erb +45 -44
- data/app/views/rails_error_dashboard/errors/rack_attack_summary.html.erb +30 -29
- data/app/views/rails_error_dashboard/errors/releases.html.erb +46 -47
- data/app/views/rails_error_dashboard/errors/settings/_value_badge.html.erb +48 -44
- data/app/views/rails_error_dashboard/errors/settings.html.erb +122 -112
- data/app/views/rails_error_dashboard/errors/show.html.erb +44 -37
- data/app/views/rails_error_dashboard/errors/storms.html.erb +30 -24
- data/app/views/rails_error_dashboard/errors/swallowed_exceptions.html.erb +26 -26
- data/app/views/rails_error_dashboard/errors/user_impact.html.erb +31 -30
- data/config/locales/de.yml +2007 -0
- data/config/locales/en.yml +2719 -0
- data/config/locales/es.yml +2079 -0
- data/config/locales/fr.yml +2082 -0
- data/config/locales/it.yml +2060 -0
- data/config/locales/ja.yml +1802 -0
- data/config/locales/pl.yml +2108 -0
- data/config/locales/pt-BR.yml +2064 -0
- data/config/locales/ru.yml +2109 -0
- data/config/locales/uk.yml +2106 -0
- data/config/locales/zh-CN.yml +1791 -0
- data/config/routes.rb +5 -0
- data/db/migrate/20260325000001_fix_swallowed_exceptions_index_for_mysql.rb +9 -3
- data/lib/rails_error_dashboard/commands/batch_delete_errors.rb +3 -1
- data/lib/rails_error_dashboard/commands/batch_mute_errors.rb +4 -2
- data/lib/rails_error_dashboard/commands/batch_resolve_errors.rb +4 -2
- data/lib/rails_error_dashboard/commands/batch_unmute_errors.rb +4 -2
- data/lib/rails_error_dashboard/commands/create_issue.rb +5 -3
- data/lib/rails_error_dashboard/commands/link_existing_issue.rb +4 -2
- data/lib/rails_error_dashboard/commands/log_error.rb +1 -1
- data/lib/rails_error_dashboard/configuration.rb +23 -6
- data/lib/rails_error_dashboard/current.rb +56 -0
- data/lib/rails_error_dashboard/i18n_store.rb +293 -0
- data/lib/rails_error_dashboard/private_backend.rb +213 -0
- data/lib/rails_error_dashboard/services/baseline_alert_payload_builder.rb +89 -22
- data/lib/rails_error_dashboard/services/digest_builder.rb +21 -7
- data/lib/rails_error_dashboard/services/discord_payload_builder.rb +27 -15
- data/lib/rails_error_dashboard/services/error_notification_dispatcher.rb +10 -5
- data/lib/rails_error_dashboard/services/localized_time_formatter.rb +117 -0
- data/lib/rails_error_dashboard/services/notification_helpers.rb +87 -4
- data/lib/rails_error_dashboard/services/pagerduty_payload_builder.rb +22 -5
- data/lib/rails_error_dashboard/services/slack_payload_builder.rb +48 -28
- data/lib/rails_error_dashboard/services/storm_protection/gate.rb +2 -1
- data/lib/rails_error_dashboard/services/webhook_payload_builder.rb +15 -1
- data/lib/rails_error_dashboard/translation.rb +39 -0
- data/lib/rails_error_dashboard/version.rb +1 -1
- data/lib/rails_error_dashboard.rb +4 -0
- data/lib/tasks/error_dashboard.rake +5 -1
- metadata +35 -8
|
@@ -5,13 +5,15 @@ module RailsErrorDashboard
|
|
|
5
5
|
class DiscordErrorNotificationJob < ApplicationJob
|
|
6
6
|
queue_as :default
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
# @param locale [String, nil] resolved at enqueue time. nil for jobs
|
|
9
|
+
# enqueued by a pre-Phase-4 version still draining from the queue.
|
|
10
|
+
def perform(error_log_id, locale = nil)
|
|
9
11
|
error_log = ErrorLog.find(error_log_id)
|
|
10
12
|
webhook_url = RailsErrorDashboard.configuration.discord_webhook_url
|
|
11
13
|
|
|
12
14
|
return unless webhook_url.present?
|
|
13
15
|
|
|
14
|
-
payload = Services::DiscordPayloadBuilder.call(error_log)
|
|
16
|
+
payload = Services::DiscordPayloadBuilder.call(error_log, locale: job_locale(locale))
|
|
15
17
|
post_json(webhook_url, payload)
|
|
16
18
|
rescue StandardError => e
|
|
17
19
|
Rails.logger.error("[RailsErrorDashboard] Failed to send Discord notification: #{e.message}")
|
|
@@ -4,14 +4,16 @@ module RailsErrorDashboard
|
|
|
4
4
|
class EmailErrorNotificationJob < ApplicationJob
|
|
5
5
|
queue_as :error_notifications
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
# @param locale [String, nil] resolved at enqueue time. nil for jobs
|
|
8
|
+
# enqueued by a pre-Phase-4 version still draining from the queue.
|
|
9
|
+
def perform(error_log_id, locale = nil)
|
|
8
10
|
error_log = ErrorLog.find_by(id: error_log_id)
|
|
9
11
|
return unless error_log
|
|
10
12
|
|
|
11
13
|
recipients = RailsErrorDashboard.configuration.notification_email_recipients
|
|
12
14
|
return unless recipients.present?
|
|
13
15
|
|
|
14
|
-
ErrorNotificationMailer.error_alert(error_log, recipients).deliver_now
|
|
16
|
+
ErrorNotificationMailer.error_alert(error_log, recipients, locale: job_locale(locale)).deliver_now
|
|
15
17
|
rescue => e
|
|
16
18
|
Rails.logger.error("[RailsErrorDashboard] Failed to send email notification: #{e.message}")
|
|
17
19
|
Rails.logger.error(e.backtrace&.first(5)&.join("\n")) if e.backtrace
|
|
@@ -8,7 +8,9 @@ module RailsErrorDashboard
|
|
|
8
8
|
|
|
9
9
|
PAGERDUTY_EVENTS_API = "https://events.pagerduty.com/v2/enqueue"
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
# @param locale [String, nil] resolved at enqueue time. nil for jobs
|
|
12
|
+
# enqueued by a pre-Phase-4 version still draining from the queue.
|
|
13
|
+
def perform(error_log_id, locale = nil)
|
|
12
14
|
error_log = ErrorLog.find(error_log_id)
|
|
13
15
|
|
|
14
16
|
# Only trigger PagerDuty for critical errors
|
|
@@ -17,7 +19,9 @@ module RailsErrorDashboard
|
|
|
17
19
|
routing_key = RailsErrorDashboard.configuration.pagerduty_integration_key
|
|
18
20
|
return unless routing_key.present?
|
|
19
21
|
|
|
20
|
-
payload = Services::PagerdutyPayloadBuilder.call(
|
|
22
|
+
payload = Services::PagerdutyPayloadBuilder.call(
|
|
23
|
+
error_log, routing_key: routing_key, locale: job_locale(locale)
|
|
24
|
+
)
|
|
21
25
|
response = post_json(PAGERDUTY_EVENTS_API, payload)
|
|
22
26
|
|
|
23
27
|
unless response_success?(response)
|
|
@@ -12,18 +12,23 @@ module RailsErrorDashboard
|
|
|
12
12
|
class ScheduledDigestJob < ApplicationJob
|
|
13
13
|
queue_as :default
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
# @param locale [String, nil] resolved at enqueue time. nil for jobs
|
|
16
|
+
# enqueued by a pre-Phase-4 version still draining from the queue.
|
|
17
|
+
def perform(period: "daily", application_id: nil, locale: nil)
|
|
16
18
|
return unless RailsErrorDashboard.configuration.enable_scheduled_digests
|
|
17
19
|
|
|
18
20
|
recipients = effective_recipients
|
|
19
21
|
return if recipients.blank?
|
|
20
22
|
|
|
23
|
+
resolved_locale = job_locale(locale)
|
|
24
|
+
|
|
21
25
|
digest = Services::DigestBuilder.call(
|
|
22
26
|
period: period.to_sym,
|
|
23
|
-
application_id: application_id
|
|
27
|
+
application_id: application_id,
|
|
28
|
+
locale: resolved_locale
|
|
24
29
|
)
|
|
25
30
|
|
|
26
|
-
DigestMailer.digest_summary(digest, recipients).deliver_now
|
|
31
|
+
DigestMailer.digest_summary(digest, recipients, locale: resolved_locale).deliver_now
|
|
27
32
|
rescue => e
|
|
28
33
|
Rails.logger.error("[RailsErrorDashboard] ScheduledDigestJob failed: #{e.class}: #{e.message}")
|
|
29
34
|
end
|
|
@@ -4,21 +4,23 @@ module RailsErrorDashboard
|
|
|
4
4
|
class SlackErrorNotificationJob < ApplicationJob
|
|
5
5
|
queue_as :error_notifications
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
# @param locale [String, nil] resolved at enqueue time. nil for jobs
|
|
8
|
+
# enqueued by a pre-Phase-4 version still draining from the queue.
|
|
9
|
+
def perform(error_log_id, locale = nil)
|
|
8
10
|
error_log = ErrorLog.find_by(id: error_log_id)
|
|
9
11
|
return unless error_log
|
|
10
12
|
|
|
11
13
|
webhook_url = RailsErrorDashboard.configuration.slack_webhook_url
|
|
12
14
|
return unless webhook_url.present?
|
|
13
15
|
|
|
14
|
-
send_slack_notification(error_log, webhook_url)
|
|
16
|
+
send_slack_notification(error_log, webhook_url, job_locale(locale))
|
|
15
17
|
rescue => e
|
|
16
18
|
Rails.logger.error("Failed to send Slack notification: #{e.message}")
|
|
17
19
|
end
|
|
18
20
|
|
|
19
21
|
private
|
|
20
22
|
|
|
21
|
-
def send_slack_notification(error_log, webhook_url)
|
|
23
|
+
def send_slack_notification(error_log, webhook_url, locale)
|
|
22
24
|
require "net/http"
|
|
23
25
|
require "json"
|
|
24
26
|
|
|
@@ -31,7 +33,7 @@ module RailsErrorDashboard
|
|
|
31
33
|
http.read_timeout = 10 # 10 seconds to read response
|
|
32
34
|
|
|
33
35
|
request = Net::HTTP::Post.new(uri.path, { "Content-Type" => "application/json" })
|
|
34
|
-
request.body = Services::SlackPayloadBuilder.call(error_log).to_json
|
|
36
|
+
request.body = Services::SlackPayloadBuilder.call(error_log, locale: locale).to_json
|
|
35
37
|
|
|
36
38
|
response = http.request(request)
|
|
37
39
|
|
|
@@ -11,9 +11,11 @@ module RailsErrorDashboard
|
|
|
11
11
|
|
|
12
12
|
# @param started_at [String] ISO8601 episode start
|
|
13
13
|
# @param state [String] breaker state at notification time ("shedding"/"open")
|
|
14
|
-
|
|
14
|
+
# @param locale [String, nil] resolved at enqueue time. nil for jobs
|
|
15
|
+
# enqueued by a pre-Phase-4 version still draining from the queue.
|
|
16
|
+
def perform(started_at:, state: "shedding", locale: nil)
|
|
15
17
|
config = RailsErrorDashboard.configuration
|
|
16
|
-
message = build_message(started_at, state, config)
|
|
18
|
+
message = build_message(started_at, state, config, job_locale(locale))
|
|
17
19
|
|
|
18
20
|
if config.enable_slack_notifications && config.slack_webhook_url.present?
|
|
19
21
|
post_json(config.slack_webhook_url, { text: message })
|
|
@@ -38,14 +40,30 @@ module RailsErrorDashboard
|
|
|
38
40
|
|
|
39
41
|
private
|
|
40
42
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
# Assembled from four keys rather than one, because the dashboard link is
|
|
44
|
+
# conditional. Each key is a whole sentence — never a fragment joined to
|
|
45
|
+
# another, which would bake English word order into every translation.
|
|
46
|
+
#
|
|
47
|
+
# ":warning:" is Slack/Discord emoji shortcode, not text.
|
|
48
|
+
def build_message(started_at, state, config, locale)
|
|
49
|
+
mode_key = state == "open" ? "open" : "shedding"
|
|
50
|
+
mode = t("red.notifications.storm.mode.#{mode_key}", locale)
|
|
51
|
+
|
|
43
52
|
dashboard = (config.dashboard_base_url || "").chomp("/")
|
|
44
|
-
link = dashboard.present?
|
|
53
|
+
link = if dashboard.present?
|
|
54
|
+
" " + t("red.notifications.storm.dashboard", locale, url: "#{dashboard}/errors/storms")
|
|
55
|
+
else
|
|
56
|
+
""
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
":warning: " \
|
|
60
|
+
"#{t("red.notifications.storm.detected", locale, application: app_name(config), started_at: started_at)} " \
|
|
61
|
+
"#{t("red.notifications.storm.engaged", locale, mode: mode)} " \
|
|
62
|
+
"#{t("red.notifications.storm.suppressed", locale)}#{link}"
|
|
63
|
+
end
|
|
45
64
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
"suppressed until the storm subsides; exact counts are preserved.#{link}"
|
|
65
|
+
def t(key, locale, **options)
|
|
66
|
+
RailsErrorDashboard::I18nStore.translate(key, locale: locale, **options)
|
|
49
67
|
end
|
|
50
68
|
|
|
51
69
|
def app_name(config)
|
|
@@ -6,7 +6,9 @@ module RailsErrorDashboard
|
|
|
6
6
|
class WebhookErrorNotificationJob < ApplicationJob
|
|
7
7
|
queue_as :default
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
# @param locale [String, nil] resolved at enqueue time. nil for jobs
|
|
10
|
+
# enqueued by a pre-Phase-4 version still draining from the queue.
|
|
11
|
+
def perform(error_log_id, locale = nil)
|
|
10
12
|
error_log = ErrorLog.find(error_log_id)
|
|
11
13
|
webhook_urls = RailsErrorDashboard.configuration.webhook_urls
|
|
12
14
|
|
|
@@ -15,7 +17,7 @@ module RailsErrorDashboard
|
|
|
15
17
|
# Ensure webhook_urls is an array
|
|
16
18
|
urls = Array(webhook_urls)
|
|
17
19
|
|
|
18
|
-
payload = Services::WebhookPayloadBuilder.call(error_log)
|
|
20
|
+
payload = Services::WebhookPayloadBuilder.call(error_log, locale: job_locale(locale))
|
|
19
21
|
|
|
20
22
|
urls.each do |url|
|
|
21
23
|
send_webhook(url, payload, error_log)
|
|
@@ -4,5 +4,19 @@ module RailsErrorDashboard
|
|
|
4
4
|
class ApplicationMailer < ActionMailer::Base
|
|
5
5
|
default from: -> { RailsErrorDashboard.configuration.notification_email_from }
|
|
6
6
|
layout false
|
|
7
|
+
|
|
8
|
+
# Mailers do not pick up engine helpers the way controllers do, so these
|
|
9
|
+
# are included explicitly.
|
|
10
|
+
#
|
|
11
|
+
# I18nHelper gives the .html.erb parts red_t; MailerI18nHelper adds
|
|
12
|
+
# red_mail_t (unescaped, for the .text.erb parts) and red_mail_time (a
|
|
13
|
+
# localized timestamp that needs no JavaScript).
|
|
14
|
+
#
|
|
15
|
+
# The locale arrives as an explicit argument and is assigned to
|
|
16
|
+
# @red_locale, which I18nHelper#red_locale prefers over Current — a mailer
|
|
17
|
+
# renders outside the request that set Current, and on a reused thread
|
|
18
|
+
# Current holds an unrelated request's value (P4-T1).
|
|
19
|
+
helper RailsErrorDashboard::I18nHelper
|
|
20
|
+
helper RailsErrorDashboard::MailerI18nHelper
|
|
7
21
|
end
|
|
8
22
|
end
|
|
@@ -2,18 +2,34 @@
|
|
|
2
2
|
|
|
3
3
|
module RailsErrorDashboard
|
|
4
4
|
class DigestMailer < ApplicationMailer
|
|
5
|
-
|
|
5
|
+
# @param locale [String] resolved at enqueue time, never read from
|
|
6
|
+
# Current — a mailer renders outside the request that set it.
|
|
7
|
+
def digest_summary(digest, recipients, locale: I18nStore::DEFAULT_LOCALE)
|
|
6
8
|
@digest = digest
|
|
7
9
|
@dashboard_url = dashboard_base_url
|
|
10
|
+
@red_locale = locale
|
|
8
11
|
|
|
9
12
|
mail(
|
|
10
13
|
to: recipients,
|
|
11
|
-
subject:
|
|
14
|
+
subject: subject_for(digest, locale)
|
|
12
15
|
)
|
|
13
16
|
end
|
|
14
17
|
|
|
15
18
|
private
|
|
16
19
|
|
|
20
|
+
# "N new errors" was an English binary plural built by interpolation. It is
|
|
21
|
+
# now a real plural key, selected by the locale's CLDR rules (REQ-1).
|
|
22
|
+
def subject_for(digest, locale)
|
|
23
|
+
count = digest[:stats][:new_errors].to_i
|
|
24
|
+
|
|
25
|
+
I18nStore.translate(
|
|
26
|
+
"red.mailers.digest.subject",
|
|
27
|
+
locale: locale,
|
|
28
|
+
count: count,
|
|
29
|
+
period: digest[:period_label]
|
|
30
|
+
)
|
|
31
|
+
end
|
|
32
|
+
|
|
17
33
|
def dashboard_base_url
|
|
18
34
|
base = RailsErrorDashboard.configuration.dashboard_base_url || "http://localhost:3000"
|
|
19
35
|
mount_path = RailsErrorDashboard.configuration.engine_mount_path
|
|
@@ -2,18 +2,35 @@
|
|
|
2
2
|
|
|
3
3
|
module RailsErrorDashboard
|
|
4
4
|
class ErrorNotificationMailer < ApplicationMailer
|
|
5
|
-
|
|
5
|
+
# @param locale [String] resolved at enqueue time, never read from
|
|
6
|
+
# Current — a mailer renders outside the request that set it.
|
|
7
|
+
def error_alert(error_log, recipients, locale: I18nStore::DEFAULT_LOCALE)
|
|
6
8
|
@error_log = error_log
|
|
7
9
|
@dashboard_url = dashboard_url(error_log)
|
|
10
|
+
@red_locale = locale
|
|
8
11
|
|
|
9
12
|
mail(
|
|
10
13
|
to: recipients,
|
|
11
|
-
subject:
|
|
14
|
+
subject: subject_for(error_log, locale)
|
|
12
15
|
)
|
|
13
16
|
end
|
|
14
17
|
|
|
15
18
|
private
|
|
16
19
|
|
|
20
|
+
# The subject is assembled from a key rather than interpolated inline, so a
|
|
21
|
+
# locale can reorder or drop the emoji. error_type and message are verbatim
|
|
22
|
+
# error content and are never translated.
|
|
23
|
+
def subject_for(error_log, locale)
|
|
24
|
+
I18nStore.translate(
|
|
25
|
+
"red.mailers.error_alert.subject",
|
|
26
|
+
locale: locale,
|
|
27
|
+
application: error_log.application&.name ||
|
|
28
|
+
I18nStore.translate("red.mailers.shared.unknown_application", locale: locale),
|
|
29
|
+
error_type: error_log.error_type,
|
|
30
|
+
message: truncate_subject(error_log.message)
|
|
31
|
+
)
|
|
32
|
+
end
|
|
33
|
+
|
|
17
34
|
def dashboard_url(error_log)
|
|
18
35
|
base_url = RailsErrorDashboard.configuration.dashboard_base_url || "http://localhost:3000"
|
|
19
36
|
mount_path = RailsErrorDashboard.configuration.engine_mount_path
|