rails_error_dashboard 0.5.12 โ 0.5.14
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 +1 -1
- data/app/mailers/rails_error_dashboard/error_notification_mailer.rb +1 -1
- data/app/views/rails_error_dashboard/error_notification_mailer/error_alert.html.erb +3 -0
- data/app/views/rails_error_dashboard/error_notification_mailer/error_alert.text.erb +1 -0
- data/app/views/rails_error_dashboard/errors/_error_row.html.erb +10 -10
- data/lib/rails_error_dashboard/services/baseline_alert_payload_builder.rb +6 -0
- data/lib/rails_error_dashboard/services/curl_generator.rb +5 -1
- data/lib/rails_error_dashboard/services/discord_payload_builder.rb +5 -0
- data/lib/rails_error_dashboard/services/error_broadcaster.rb +26 -6
- data/lib/rails_error_dashboard/services/notification_helpers.rb +7 -0
- data/lib/rails_error_dashboard/services/pagerduty_payload_builder.rb +2 -1
- data/lib/rails_error_dashboard/services/slack_payload_builder.rb +4 -0
- data/lib/rails_error_dashboard/services/webhook_payload_builder.rb +1 -0
- data/lib/rails_error_dashboard/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3d5f1adc32eb6c1aa41f178cc07a1787a66ce3740e2aa55210e3de90c1cb2c42
|
|
4
|
+
data.tar.gz: 7f899e1133788ab3cc4a65246d995d4fedffdf5d9d357f1089b05d570ab5a77a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 11f7b9bec8eaa7b6f90025e27291a5d5fff523196dbb8564122d69319c69c162384b3b8d3a5cb9d647ae59b55c2bfb78f5a09f3ecbe900139ac945629e3f4939
|
|
7
|
+
data.tar.gz: f2dc12d460f41480cd879193f12556a4342541ebc0f6b57a494cc5347492289ab7531f6160d1fd0c9306ebebb148219f9f891c8f71e6dcb9321f257e198b9621
|
data/README.md
CHANGED
|
@@ -527,7 +527,7 @@ Built with [Rails](https://rubyonrails.org/) ยท UI by [Bootstrap 5](https://getb
|
|
|
527
527
|
|
|
528
528
|
[](https://github.com/AnjanJ/rails_error_dashboard/graphs/contributors)
|
|
529
529
|
|
|
530
|
-
Special thanks to [@bonniesimon](https://github.com/bonniesimon), [@gundestrup](https://github.com/gundestrup), [@midwire](https://github.com/midwire), [@RafaelTurtle](https://github.com/RafaelTurtle),
|
|
530
|
+
Special thanks to [@bonniesimon](https://github.com/bonniesimon), [@gundestrup](https://github.com/gundestrup), [@midwire](https://github.com/midwire), [@RafaelTurtle](https://github.com/RafaelTurtle), [@j4rs](https://github.com/j4rs), and [@gmarziou](https://github.com/gmarziou). See [CONTRIBUTORS.md](CONTRIBUTORS.md) for the full list.
|
|
531
531
|
|
|
532
532
|
---
|
|
533
533
|
|
|
@@ -8,7 +8,7 @@ module RailsErrorDashboard
|
|
|
8
8
|
|
|
9
9
|
mail(
|
|
10
10
|
to: recipients,
|
|
11
|
-
subject: "๐จ #{error_log.error_type}: #{truncate_subject(error_log.message)}"
|
|
11
|
+
subject: "๐จ [#{error_log.application&.name || 'Unknown'}] #{error_log.error_type}: #{truncate_subject(error_log.message)}"
|
|
12
12
|
)
|
|
13
13
|
end
|
|
14
14
|
|
|
@@ -133,6 +133,9 @@
|
|
|
133
133
|
|
|
134
134
|
<div class="content">
|
|
135
135
|
<div class="info-grid">
|
|
136
|
+
<div class="label">Application:</div>
|
|
137
|
+
<div class="value"><strong><%= @error_log.application&.name || 'Unknown' %></strong></div>
|
|
138
|
+
|
|
136
139
|
<div class="label">Error Type:</div>
|
|
137
140
|
<div class="value"><code><%= @error_log.error_type %></code></div>
|
|
138
141
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
๐จ ERROR ALERT
|
|
3
3
|
==========================================
|
|
4
4
|
|
|
5
|
+
Application: <%= @error_log.application&.name || 'Unknown' %>
|
|
5
6
|
Error Type: <%= @error_log.error_type %>
|
|
6
7
|
<% if @error_log.platform.present? %>Platform: <%= @error_log.platform %><% end %>
|
|
7
8
|
Occurred At: <%= @error_log.occurred_at.strftime('%B %d, %Y at %I:%M %p %Z') %>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<td onclick="event.stopPropagation();">
|
|
3
3
|
<input type="checkbox" class="error-checkbox form-check-input" value="<%= error.id %>" data-error-id="<%= error.id %>">
|
|
4
4
|
</td>
|
|
5
|
-
<td onclick="window.location='<%=
|
|
5
|
+
<td onclick="window.location='<%= error_path(error) %>';">
|
|
6
6
|
<% severity = error.severity %>
|
|
7
7
|
<% if severity == :critical %>
|
|
8
8
|
<span class="badge bg-danger" data-bs-toggle="tooltip" title="Critical severity - requires immediate attention">CRITICAL</span>
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
<br><small class="text-muted" data-bs-toggle="tooltip" title="Priority score (0-100) based on severity, frequency, recency, and user impact">P<%= error.priority_score %></small>
|
|
18
18
|
<% end %>
|
|
19
19
|
</td>
|
|
20
|
-
<td onclick="window.location='<%=
|
|
20
|
+
<td onclick="window.location='<%= error_path(error) %>';">
|
|
21
21
|
<code class="text-danger" data-bs-toggle="tooltip" title="<%= error.error_type %>"><%= error.error_type.split('::').last %></code>
|
|
22
22
|
<% if error.recent? %>
|
|
23
23
|
<span class="badge bg-success ms-1" data-bs-toggle="tooltip" title="Error occurred within the last hour">NEW</span>
|
|
@@ -26,29 +26,29 @@
|
|
|
26
26
|
<br><small class="badge bg-light text-dark" data-bs-toggle="tooltip" title="App version when error occurred">v<%= error.app_version %></small>
|
|
27
27
|
<% end %>
|
|
28
28
|
</td>
|
|
29
|
-
<td onclick="window.location='<%=
|
|
29
|
+
<td onclick="window.location='<%= error_path(error) %>';">
|
|
30
30
|
<div class="text-truncate" style="max-width: 300px;" title="<%= error.message %>">
|
|
31
31
|
<%= error.message %>
|
|
32
32
|
</div>
|
|
33
33
|
</td>
|
|
34
|
-
<td onclick="window.location='<%=
|
|
34
|
+
<td onclick="window.location='<%= error_path(error) %>';">
|
|
35
35
|
<span class="badge bg-primary"><%= error.occurrence_count %>x</span>
|
|
36
36
|
</td>
|
|
37
|
-
<td onclick="window.location='<%=
|
|
37
|
+
<td onclick="window.location='<%= error_path(error) %>';">
|
|
38
38
|
<small>
|
|
39
39
|
<strong>First:</strong> <%= local_time(error.first_seen_at, format: :short) %><br>
|
|
40
40
|
<strong>Last:</strong> <%= local_time(error.last_seen_at, format: :short) %>
|
|
41
41
|
</small>
|
|
42
42
|
</td>
|
|
43
43
|
<% if local_assigns[:show_application] %>
|
|
44
|
-
<td onclick="window.location='<%=
|
|
44
|
+
<td onclick="window.location='<%= error_path(error) %>';">
|
|
45
45
|
<span class="badge bg-info">
|
|
46
46
|
<%= error.application&.name || 'Unknown' %>
|
|
47
47
|
</span>
|
|
48
48
|
</td>
|
|
49
49
|
<% end %>
|
|
50
50
|
<% if local_assigns[:show_platform] %>
|
|
51
|
-
<td onclick="window.location='<%=
|
|
51
|
+
<td onclick="window.location='<%= error_path(error) %>';">
|
|
52
52
|
<% if error.platform == 'iOS' %>
|
|
53
53
|
<span class="badge badge-ios"><i class="bi bi-apple"></i> iOS</span>
|
|
54
54
|
<% elsif error.platform == 'Android' %>
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
<% end %>
|
|
61
61
|
</td>
|
|
62
62
|
<% end %>
|
|
63
|
-
<td onclick="window.location='<%=
|
|
63
|
+
<td onclick="window.location='<%= error_path(error) %>';">
|
|
64
64
|
<% if error.user_id %>
|
|
65
65
|
<small data-bs-toggle="tooltip" title="User affected by this error">User #<%= error.user_id %></small>
|
|
66
66
|
<% if error.respond_to?(:user_impact_percentage) %>
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
<small class="text-muted" data-bs-toggle="tooltip" title="No specific user affected">-</small>
|
|
74
74
|
<% end %>
|
|
75
75
|
</td>
|
|
76
|
-
<td onclick="window.location='<%=
|
|
76
|
+
<td onclick="window.location='<%= error_path(error) %>';">
|
|
77
77
|
<% if error.resolved? %>
|
|
78
78
|
<i class="bi bi-check-circle-fill text-success"
|
|
79
79
|
data-bs-toggle="tooltip"
|
|
@@ -95,7 +95,7 @@
|
|
|
95
95
|
<% end %>
|
|
96
96
|
</td>
|
|
97
97
|
<td onclick="event.stopPropagation();">
|
|
98
|
-
<%= link_to
|
|
98
|
+
<%= link_to error_path(error), class: "btn btn-sm btn-outline-primary" do %>
|
|
99
99
|
<i class="bi bi-eye"></i>
|
|
100
100
|
<% end %>
|
|
101
101
|
</td>
|
|
@@ -44,6 +44,10 @@ module RailsErrorDashboard
|
|
|
44
44
|
{
|
|
45
45
|
type: "section",
|
|
46
46
|
fields: [
|
|
47
|
+
{
|
|
48
|
+
type: "mrkdwn",
|
|
49
|
+
text: "*Application:*\n#{NotificationHelpers.app_name(error_log)}"
|
|
50
|
+
},
|
|
47
51
|
{
|
|
48
52
|
type: "mrkdwn",
|
|
49
53
|
text: "*Error Type:*\n#{error_log.error_type}"
|
|
@@ -104,6 +108,7 @@ module RailsErrorDashboard
|
|
|
104
108
|
title: "๐จ Baseline Anomaly Detected",
|
|
105
109
|
color: anomaly_color(anomaly_data[:level]),
|
|
106
110
|
fields: [
|
|
111
|
+
{ name: "Application", value: NotificationHelpers.app_name(error_log), inline: true },
|
|
107
112
|
{ name: "Error Type", value: error_log.error_type, inline: true },
|
|
108
113
|
{ name: "Platform", value: error_log.platform, inline: true },
|
|
109
114
|
{ name: "Severity", value: anomaly_data[:level].to_s.upcase, inline: true },
|
|
@@ -129,6 +134,7 @@ module RailsErrorDashboard
|
|
|
129
134
|
timestamp: Time.current.iso8601,
|
|
130
135
|
error: {
|
|
131
136
|
id: error_log.id,
|
|
137
|
+
application: NotificationHelpers.app_name(error_log),
|
|
132
138
|
type: error_log.error_type,
|
|
133
139
|
message: error_log.message,
|
|
134
140
|
platform: error_log.platform,
|
|
@@ -66,7 +66,7 @@ module RailsErrorDashboard
|
|
|
66
66
|
hostname = @error.respond_to?(:hostname) && @error.hostname.presence
|
|
67
67
|
return nil unless hostname
|
|
68
68
|
|
|
69
|
-
scheme =
|
|
69
|
+
scheme = local_host?(hostname) ? "http" : "https"
|
|
70
70
|
"#{scheme}://#{hostname}#{request_url}"
|
|
71
71
|
end
|
|
72
72
|
|
|
@@ -75,6 +75,10 @@ module RailsErrorDashboard
|
|
|
75
75
|
escaped = str.to_s.gsub("'") { "'\\''" }
|
|
76
76
|
"'#{escaped}'"
|
|
77
77
|
end
|
|
78
|
+
|
|
79
|
+
def local_host?(hostname)
|
|
80
|
+
hostname.match?(/\A(localhost|127\.\d+\.\d+\.\d+|::1|0\.0\.0\.0)(:\d+)?\z/)
|
|
81
|
+
end
|
|
78
82
|
end
|
|
79
83
|
end
|
|
80
84
|
end
|
|
@@ -26,6 +26,11 @@ module RailsErrorDashboard
|
|
|
26
26
|
description: NotificationHelpers.truncate_message(error_log.message, 200),
|
|
27
27
|
color: severity_color(error_log),
|
|
28
28
|
fields: [
|
|
29
|
+
{
|
|
30
|
+
name: "Application",
|
|
31
|
+
value: NotificationHelpers.app_name(error_log),
|
|
32
|
+
inline: true
|
|
33
|
+
},
|
|
29
34
|
{
|
|
30
35
|
name: "Platform",
|
|
31
36
|
value: error_log.platform || "Unknown",
|
|
@@ -9,6 +9,11 @@ module RailsErrorDashboard
|
|
|
9
9
|
#
|
|
10
10
|
# IMPORTANT: Broadcasting failures MUST NOT block error logging.
|
|
11
11
|
# All public methods rescue exceptions and log them.
|
|
12
|
+
#
|
|
13
|
+
# NOTE: Turbo broadcasts render partials via ApplicationController.render,
|
|
14
|
+
# which is the HOST app's controller โ engine route helpers (error_path, etc.)
|
|
15
|
+
# are NOT available there. We render via the engine's own controller renderer
|
|
16
|
+
# and pass pre-rendered HTML to the broadcast to ensure route helpers work.
|
|
12
17
|
class ErrorBroadcaster
|
|
13
18
|
# Broadcast a new error (prepend to error list + refresh stats)
|
|
14
19
|
# @param error_log [ErrorLog] The newly created error
|
|
@@ -19,11 +24,13 @@ module RailsErrorDashboard
|
|
|
19
24
|
platforms = ErrorLog.distinct.pluck(:platform).compact
|
|
20
25
|
show_platform = platforms.size > 1
|
|
21
26
|
|
|
27
|
+
html = render_partial("rails_error_dashboard/errors/error_row",
|
|
28
|
+
error: error_log, show_platform: show_platform)
|
|
29
|
+
|
|
22
30
|
Turbo::StreamsChannel.broadcast_prepend_to(
|
|
23
31
|
"error_list",
|
|
24
32
|
target: "error_list",
|
|
25
|
-
|
|
26
|
-
locals: { error: error_log, show_platform: show_platform }
|
|
33
|
+
html: html
|
|
27
34
|
)
|
|
28
35
|
broadcast_stats
|
|
29
36
|
rescue => e
|
|
@@ -40,11 +47,13 @@ module RailsErrorDashboard
|
|
|
40
47
|
platforms = ErrorLog.distinct.pluck(:platform).compact
|
|
41
48
|
show_platform = platforms.size > 1
|
|
42
49
|
|
|
50
|
+
html = render_partial("rails_error_dashboard/errors/error_row",
|
|
51
|
+
error: error_log, show_platform: show_platform)
|
|
52
|
+
|
|
43
53
|
Turbo::StreamsChannel.broadcast_replace_to(
|
|
44
54
|
"error_list",
|
|
45
55
|
target: "error_#{error_log.id}",
|
|
46
|
-
|
|
47
|
-
locals: { error: error_log, show_platform: show_platform }
|
|
56
|
+
html: html
|
|
48
57
|
)
|
|
49
58
|
broadcast_stats
|
|
50
59
|
rescue => e
|
|
@@ -59,17 +68,28 @@ module RailsErrorDashboard
|
|
|
59
68
|
stats = Queries::DashboardStats.call
|
|
60
69
|
return unless stats.is_a?(Hash) && stats.present?
|
|
61
70
|
|
|
71
|
+
html = render_partial("rails_error_dashboard/errors/stats", stats: stats)
|
|
72
|
+
|
|
62
73
|
Turbo::StreamsChannel.broadcast_replace_to(
|
|
63
74
|
"error_list",
|
|
64
75
|
target: "dashboard_stats",
|
|
65
|
-
|
|
66
|
-
locals: { stats: stats }
|
|
76
|
+
html: html
|
|
67
77
|
)
|
|
68
78
|
rescue => e
|
|
69
79
|
Rails.logger.error("[RailsErrorDashboard] Failed to broadcast stats update: #{e.class} - #{e.message}")
|
|
70
80
|
Rails.logger.debug("[RailsErrorDashboard] Backtrace: #{e.backtrace&.first(3)&.join("\n")}")
|
|
71
81
|
end
|
|
72
82
|
|
|
83
|
+
# Render a partial using the engine's controller renderer.
|
|
84
|
+
# This ensures engine route helpers (error_path, etc.) are available,
|
|
85
|
+
# unlike Turbo's default ApplicationController.render which uses the host app's context.
|
|
86
|
+
def self.render_partial(partial, **locals)
|
|
87
|
+
RailsErrorDashboard::ApplicationController.render(
|
|
88
|
+
partial: partial,
|
|
89
|
+
locals: locals
|
|
90
|
+
)
|
|
91
|
+
end
|
|
92
|
+
|
|
73
93
|
# Check if broadcasting infrastructure is available
|
|
74
94
|
# @return [Boolean]
|
|
75
95
|
def self.available?
|
|
@@ -82,6 +82,13 @@ module RailsErrorDashboard
|
|
|
82
82
|
{}
|
|
83
83
|
end
|
|
84
84
|
|
|
85
|
+
# Application name for notifications
|
|
86
|
+
# @param error_log [ErrorLog] The error
|
|
87
|
+
# @return [String] Application name or "Unknown"
|
|
88
|
+
def app_name(error_log)
|
|
89
|
+
error_log.application&.name || "Unknown"
|
|
90
|
+
end
|
|
91
|
+
|
|
85
92
|
# Error source description for PagerDuty
|
|
86
93
|
# @param error_log [ErrorLog] The error
|
|
87
94
|
# @return [String] Source description
|
|
@@ -18,13 +18,14 @@ module RailsErrorDashboard
|
|
|
18
18
|
routing_key: routing_key,
|
|
19
19
|
event_action: "trigger",
|
|
20
20
|
payload: {
|
|
21
|
-
summary: "Critical Error: #{error_log.error_type} in #{error_log.platform}",
|
|
21
|
+
summary: "[#{NotificationHelpers.app_name(error_log)}] Critical Error: #{error_log.error_type} in #{error_log.platform}",
|
|
22
22
|
severity: "critical",
|
|
23
23
|
source: NotificationHelpers.error_source(error_log),
|
|
24
24
|
component: error_log.controller_name || "Unknown",
|
|
25
25
|
group: error_log.error_type,
|
|
26
26
|
class: error_log.error_type,
|
|
27
27
|
custom_details: {
|
|
28
|
+
application: NotificationHelpers.app_name(error_log),
|
|
28
29
|
message: error_log.message,
|
|
29
30
|
controller: error_log.controller_name,
|
|
30
31
|
action: error_log.action_name,
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rails_error_dashboard
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.5.
|
|
4
|
+
version: 0.5.14
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Anjan Jagirdar
|
|
@@ -496,7 +496,7 @@ metadata:
|
|
|
496
496
|
funding_uri: https://github.com/sponsors/AnjanJ
|
|
497
497
|
post_install_message: |
|
|
498
498
|
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
499
|
-
RED (Rails Error Dashboard) v0.5.
|
|
499
|
+
RED (Rails Error Dashboard) v0.5.14
|
|
500
500
|
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
501
501
|
|
|
502
502
|
First install:
|