rails_error_dashboard 0.12.0 → 0.12.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
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d504b1e375f3af3cb25e5fd636730f1f6e71cc74f98f9c2608bbd7ac042e1575
|
|
4
|
+
data.tar.gz: e6e8e5a078803978e9a93d5f0b2c71e6ec3a1b2ae7ee9c97fb4693a8f339ea98
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3f64b74befa82818242fe0b38e1c399b2a683e0f464b6533fe62c9eac4de7503d9c18db124b05ddadedbfc3347c1edaddd49edfd845ff2a9eff8f5e2ddc68b45
|
|
7
|
+
data.tar.gz: 42e42075a4b4375fb71e8efe6eb6d85585a6c176c160ede254d1e4a937d8501fc102f40cacf74c9737745a6ca1700c6568d8986d7c78ed327a31008f0ce6522e
|
|
@@ -295,6 +295,12 @@
|
|
|
295
295
|
<div class="card">
|
|
296
296
|
<div class="card-header">
|
|
297
297
|
<h5 class="mb-0"><i class="bi bi-people"></i> <%= red_t("red.analytics.overview.top_users.title") %></h5>
|
|
298
|
+
<%# Storm protection sheds per-event rows, and this table is built
|
|
299
|
+
from them, so the counts are a floor when that happened. The
|
|
300
|
+
Overview labels the same condition with the same key. %>
|
|
301
|
+
<% if @error_stats[:affected_users_incomplete] %>
|
|
302
|
+
<small style="display: block; color: var(--text-tertiary);"><%= red_t("red.errors.overview_page.affected_users_incomplete") %></small>
|
|
303
|
+
<% end %>
|
|
298
304
|
</div>
|
|
299
305
|
<div class="card-body p-0">
|
|
300
306
|
<%= render partial: 'user_errors_table',
|
|
@@ -64,29 +64,45 @@ module RailsErrorDashboard
|
|
|
64
64
|
base_scope.where("occurred_at >= ?", @start_date)
|
|
65
65
|
end
|
|
66
66
|
|
|
67
|
+
# Two counting units, kept distinct on purpose.
|
|
68
|
+
#
|
|
69
|
+
# An ErrorLog row is a GROUP; its occurrence_count says how many times
|
|
70
|
+
# that error actually happened. Volume figures are EVENTS (the sum), so
|
|
71
|
+
# this page agrees with the Overview, which counts the same way. Resolved
|
|
72
|
+
# and unresolved stay GROUP counts -- a group is the thing that gets
|
|
73
|
+
# resolved, and an event cannot be.
|
|
67
74
|
def error_statistics
|
|
68
75
|
{
|
|
69
|
-
total:
|
|
76
|
+
total: event_count,
|
|
77
|
+
total_groups: base_query.count,
|
|
70
78
|
unresolved: base_query.unresolved.count,
|
|
71
|
-
|
|
72
|
-
|
|
79
|
+
resolved: base_query.resolved.count,
|
|
80
|
+
by_type: base_query.group(:error_type).sum(:occurrence_count).sort_by { |_, count| -count }.to_h,
|
|
81
|
+
by_day: base_query.group("DATE(occurred_at)").sum(:occurrence_count),
|
|
82
|
+
affected_users_incomplete: affected_users_incomplete?
|
|
73
83
|
}
|
|
74
84
|
end
|
|
75
85
|
|
|
86
|
+
# Total EVENTS in the window. dashboard_stats.rb and
|
|
87
|
+
# platform_comparison.rb:165 count the same way.
|
|
88
|
+
def event_count
|
|
89
|
+
base_query.sum(:occurrence_count)
|
|
90
|
+
end
|
|
91
|
+
|
|
76
92
|
def errors_over_time
|
|
77
|
-
base_query.group_by_day(:occurred_at).
|
|
93
|
+
base_query.group_by_day(:occurred_at).sum(:occurrence_count)
|
|
78
94
|
end
|
|
79
95
|
|
|
80
96
|
def errors_by_type
|
|
81
97
|
base_query.group(:error_type)
|
|
82
|
-
.
|
|
98
|
+
.sum(:occurrence_count)
|
|
83
99
|
.sort_by { |_, count| -count }
|
|
84
100
|
.first(10)
|
|
85
101
|
.to_h
|
|
86
102
|
end
|
|
87
103
|
|
|
88
104
|
def errors_by_platform
|
|
89
|
-
base_query.group(:platform).
|
|
105
|
+
base_query.group(:platform).sum(:occurrence_count)
|
|
90
106
|
end
|
|
91
107
|
|
|
92
108
|
# NULL (captured before the column existed) is reported under :unknown
|
|
@@ -94,25 +110,81 @@ module RailsErrorDashboard
|
|
|
94
110
|
def errors_by_environment
|
|
95
111
|
return {} unless ErrorLog.column_names.include?("environment")
|
|
96
112
|
|
|
97
|
-
base_query.group(:environment).
|
|
113
|
+
base_query.group(:environment).sum(:occurrence_count).transform_keys { |env| env.nil? ? :unknown : env }
|
|
98
114
|
end
|
|
99
115
|
|
|
100
116
|
def errors_by_hour
|
|
101
117
|
# group_by_hour_of_day buckets into 0..23 to show diurnal patterns
|
|
102
118
|
# (when in the day errors peak). The chart title says "Errors by Hour
|
|
103
119
|
# of Day" — group_by_hour produced a chronological time series instead.
|
|
104
|
-
base_query.group_by_hour_of_day(:occurred_at).
|
|
120
|
+
base_query.group_by_hour_of_day(:occurred_at).sum(:occurrence_count)
|
|
105
121
|
end
|
|
106
122
|
|
|
123
|
+
# Events per user, counted from OCCURRENCE rows.
|
|
124
|
+
#
|
|
125
|
+
# The group's user_id is overwritten by each new occurrence, so grouping
|
|
126
|
+
# ErrorLog by it attributed a whole group to whoever happened to hit it
|
|
127
|
+
# last -- at most one user per group, and their "count" was a number of
|
|
128
|
+
# groups. Occurrence rows carry the user of each individual event.
|
|
129
|
+
#
|
|
130
|
+
# Storm count-only events create no occurrence row, so during a storm
|
|
131
|
+
# this is a floor; affected_users_incomplete? says when.
|
|
107
132
|
def top_affected_users
|
|
108
133
|
user_model = RailsErrorDashboard.configuration.user_model
|
|
109
134
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
135
|
+
counts = user_event_counts
|
|
136
|
+
counts.sort_by { |_, count| -count }
|
|
137
|
+
.first(10)
|
|
138
|
+
.map { |user_id, count| { user_id: user_id, email: find_user_email(user_id, user_model), count: count } }
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def user_event_counts
|
|
142
|
+
return group_user_counts unless occurrences_available?
|
|
143
|
+
|
|
144
|
+
occurrences = ErrorOccurrence.table_name
|
|
145
|
+
counts = occurrence_scope.where("#{occurrences}.occurred_at >= ?", @start_date)
|
|
146
|
+
.where.not(occurrences => { user_id: nil })
|
|
147
|
+
.group("#{occurrences}.user_id")
|
|
148
|
+
.count
|
|
149
|
+
|
|
150
|
+
# A user whose events predate occurrence tracking -- or whose events
|
|
151
|
+
# were shed by storm protection, which writes no occurrence row -- still
|
|
152
|
+
# belongs in the table. Fall back to the group's own user for those,
|
|
153
|
+
# taking whichever count is larger. UserImpactSummary merges the same way.
|
|
154
|
+
group_user_counts.merge(counts) { |_user, group_count, occurrence_count| [ group_count, occurrence_count ].max }
|
|
155
|
+
rescue StandardError
|
|
156
|
+
group_user_counts
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def group_user_counts
|
|
160
|
+
base_query.where.not(user_id: nil).group(:user_id).sum(:occurrence_count)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# Occurrence rows joined back to error_logs, so the application filter
|
|
164
|
+
# (which the occurrence table has no column for) still applies.
|
|
165
|
+
def occurrence_scope
|
|
166
|
+
scope = ErrorOccurrence.joins(:error_log)
|
|
167
|
+
scope = scope.where(ErrorLog.table_name => { application_id: @application_id }) if @application_id.present?
|
|
168
|
+
scope
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def occurrences_available?
|
|
172
|
+
defined?(ErrorOccurrence) && ErrorOccurrence.table_exists?
|
|
173
|
+
rescue StandardError
|
|
174
|
+
false
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# True when the window holds more events than recorded occurrences --
|
|
178
|
+
# storm shedding dropped per-event rows, so any occurrence-derived
|
|
179
|
+
# figure (the affected-user table) is a floor, not a total.
|
|
180
|
+
def affected_users_incomplete?
|
|
181
|
+
return false unless occurrences_available?
|
|
182
|
+
|
|
183
|
+
occurrences = ErrorOccurrence.table_name
|
|
184
|
+
recorded = occurrence_scope.where("#{occurrences}.occurred_at >= ?", @start_date).count
|
|
185
|
+
recorded < event_count
|
|
186
|
+
rescue StandardError
|
|
187
|
+
false
|
|
116
188
|
end
|
|
117
189
|
|
|
118
190
|
def find_user_email(user_id, user_model)
|
|
@@ -122,23 +194,31 @@ module RailsErrorDashboard
|
|
|
122
194
|
"User ##{user_id}"
|
|
123
195
|
end
|
|
124
196
|
|
|
197
|
+
# Resolution rate is GROUPS over GROUPS.
|
|
198
|
+
#
|
|
199
|
+
# Volume is now measured in events, but resolving is something that
|
|
200
|
+
# happens to a group, so dividing resolved groups by total events would
|
|
201
|
+
# collapse the rate toward zero the moment any error recurred. The
|
|
202
|
+
# Overview computes this the same way (resolved / resolved + unresolved),
|
|
203
|
+
# so both pages report one rate.
|
|
204
|
+
#
|
|
205
|
+
# Same scoped relation on both sides: an unscoped numerator counted every
|
|
206
|
+
# application's resolved errors against one application's total, and the
|
|
207
|
+
# "rate" went past 100%.
|
|
125
208
|
def resolution_rate
|
|
126
|
-
total = error_statistics[:total]
|
|
127
|
-
return 0 if total.zero?
|
|
128
|
-
|
|
129
|
-
# Same scoped relation as the denominator: an unscoped numerator
|
|
130
|
-
# counted every application's resolved errors against one
|
|
131
|
-
# application's total, and the "rate" went past 100%.
|
|
132
209
|
resolved_count = base_query.resolved.count
|
|
133
|
-
|
|
210
|
+
total_groups = resolved_count + base_query.unresolved.count
|
|
211
|
+
return 0 if total_groups.zero?
|
|
212
|
+
|
|
213
|
+
((resolved_count.to_f / total_groups) * 100).round(1)
|
|
134
214
|
end
|
|
135
215
|
|
|
136
216
|
def mobile_errors_count
|
|
137
|
-
base_query.where(platform: [ "iOS", "Android" ]).
|
|
217
|
+
base_query.where(platform: [ "iOS", "Android" ]).sum(:occurrence_count)
|
|
138
218
|
end
|
|
139
219
|
|
|
140
220
|
def api_errors_count
|
|
141
|
-
base_query.where("platform IS NULL OR platform = ?", "API").
|
|
221
|
+
base_query.where("platform IS NULL OR platform = ?", "API").sum(:occurrence_count)
|
|
142
222
|
end
|
|
143
223
|
|
|
144
224
|
# Pattern insights for top error types
|
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.12.
|
|
4
|
+
version: 0.12.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Anjan Jagirdar
|
|
@@ -585,7 +585,7 @@ metadata:
|
|
|
585
585
|
funding_uri: https://github.com/sponsors/AnjanJ
|
|
586
586
|
post_install_message: |
|
|
587
587
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
588
|
-
RED (Rails Error Dashboard) v0.12.
|
|
588
|
+
RED (Rails Error Dashboard) v0.12.1
|
|
589
589
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
590
590
|
|
|
591
591
|
First install:
|