rails_event_viewer 0.3.1 → 0.4.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/CHANGELOG.md +28 -0
- data/README.md +7 -0
- data/app/assets/stylesheets/rails_event_viewer/application.css +1 -1
- data/app/controllers/rails_event_viewer/application_controller.rb +1 -11
- data/app/controllers/rails_event_viewer/events_controller.rb +6 -6
- data/app/helpers/rails_event_viewer/application_helper.rb +21 -75
- data/app/models/rails_event_viewer/entry.rb +0 -26
- data/app/models/rails_event_viewer/page.rb +9 -0
- data/app/views/layouts/rails_event_viewer/application.html.erb +3 -4
- data/app/views/rails_event_viewer/analytics/overview.html.erb +11 -9
- data/app/views/rails_event_viewer/dashboard/index.html.erb +13 -13
- data/app/views/rails_event_viewer/event_types/index.html.erb +6 -6
- data/app/views/rails_event_viewer/event_types/show.html.erb +14 -14
- data/app/views/rails_event_viewer/events/_event_row.html.erb +8 -8
- data/app/views/rails_event_viewer/events/_filters_sidebar.html.erb +16 -14
- data/app/views/rails_event_viewer/events/index.html.erb +6 -6
- data/app/views/rails_event_viewer/events/show.html.erb +22 -22
- data/app/views/rails_event_viewer/groups/index.html.erb +7 -7
- data/app/views/rails_event_viewer/groups/show.html.erb +11 -11
- data/app/views/rails_event_viewer/shared/_navigation.html.erb +8 -14
- data/app/views/rails_event_viewer/shared/_pagination.html.erb +10 -10
- data/app/views/rails_event_viewer/shared/_stat_card.html.erb +5 -5
- data/db/migrate/20261002121337_create_rails_event_viewer_entries.rb +0 -1
- data/lib/generators/rails_event_viewer/install/templates/create_rails_event_viewer_entries.rb.erb +0 -1
- data/lib/generators/rails_event_viewer/install/templates/initializer.rb.erb +4 -0
- data/lib/rails_event_viewer/adapter.rb +0 -8
- data/lib/rails_event_viewer/adapters/active_record.rb +10 -44
- data/lib/rails_event_viewer/adapters/concerns/in_memory_filtering.rb +0 -7
- data/lib/rails_event_viewer/adapters/memory.rb +0 -4
- data/lib/rails_event_viewer/adapters/null.rb +0 -8
- data/lib/rails_event_viewer/adapters/redis.rb +3 -17
- data/lib/rails_event_viewer/flusher.rb +5 -5
- data/lib/rails_event_viewer/logging.rb +1 -11
- data/lib/rails_event_viewer/version.rb +1 -1
- data/lib/rails_event_viewer.rb +6 -5
- metadata +7 -2
- data/app/assets/stylesheets/rails_event_viewer/tailwind.css +0 -29
|
@@ -10,10 +10,6 @@ module RailsEventViewer
|
|
|
10
10
|
true
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
def supports_retention?
|
|
14
|
-
true
|
|
15
|
-
end
|
|
16
|
-
|
|
17
13
|
def write_events(events)
|
|
18
14
|
raise NotImplementedError, "#{self.class} must implement #write_events"
|
|
19
15
|
end
|
|
@@ -59,10 +55,6 @@ module RailsEventViewer
|
|
|
59
55
|
end.sort_by { |s| -s[:count] }
|
|
60
56
|
end
|
|
61
57
|
|
|
62
|
-
def distinct_group_values(key, source: :context)
|
|
63
|
-
raise NotImplementedError, "#{self.class} must implement #distinct_group_values"
|
|
64
|
-
end
|
|
65
|
-
|
|
66
58
|
def group_instances(key, source: :context, limit: 100)
|
|
67
59
|
raise NotImplementedError, "#{self.class} must implement #group_instances"
|
|
68
60
|
end
|
|
@@ -3,10 +3,6 @@ module RailsEventViewer
|
|
|
3
3
|
class ActiveRecord
|
|
4
4
|
include Adapter
|
|
5
5
|
|
|
6
|
-
def initialize(**options)
|
|
7
|
-
@options = options
|
|
8
|
-
end
|
|
9
|
-
|
|
10
6
|
def table_exists?
|
|
11
7
|
Entry.table_exists?
|
|
12
8
|
rescue ::ActiveRecord::NoDatabaseError
|
|
@@ -16,7 +12,6 @@ module RailsEventViewer
|
|
|
16
12
|
def write_events(events)
|
|
17
13
|
return if events.empty?
|
|
18
14
|
|
|
19
|
-
# Use insert_all for bulk inserts (more efficient)
|
|
20
15
|
records = events.map do |event|
|
|
21
16
|
{
|
|
22
17
|
name: event[:name],
|
|
@@ -32,7 +27,9 @@ module RailsEventViewer
|
|
|
32
27
|
}
|
|
33
28
|
end
|
|
34
29
|
|
|
35
|
-
Entry.
|
|
30
|
+
Entry.transaction(requires_new: !RailsEventViewer.transactional) do
|
|
31
|
+
Entry.insert_all(records, returning: false)
|
|
32
|
+
end
|
|
36
33
|
end
|
|
37
34
|
|
|
38
35
|
def fetch_events(relation)
|
|
@@ -88,16 +85,6 @@ module RailsEventViewer
|
|
|
88
85
|
end
|
|
89
86
|
end
|
|
90
87
|
|
|
91
|
-
def distinct_group_values(key, source: :context)
|
|
92
|
-
column = source == :tags ? :tags : :context
|
|
93
|
-
json_path = JsonQuery.extract_path(column, key)
|
|
94
|
-
|
|
95
|
-
Entry
|
|
96
|
-
.where(JsonQuery.extract_path_present(column, key))
|
|
97
|
-
.distinct
|
|
98
|
-
.pluck(Arel.sql(json_path))
|
|
99
|
-
end
|
|
100
|
-
|
|
101
88
|
def group_instances(key, source: :context, limit: 100)
|
|
102
89
|
column = source == :tags ? :tags : :context
|
|
103
90
|
json_path = JsonQuery.extract_path(column, key)
|
|
@@ -148,39 +135,18 @@ module RailsEventViewer
|
|
|
148
135
|
end
|
|
149
136
|
|
|
150
137
|
def build_scope(relation)
|
|
151
|
-
scope = Entry.order(occurred_at: :desc)
|
|
152
|
-
scope =
|
|
153
|
-
scope =
|
|
154
|
-
scope =
|
|
138
|
+
scope = Entry.order(occurred_at: :desc, id: :desc)
|
|
139
|
+
scope = scope.where(name: relation.names) if relation.names.present?
|
|
140
|
+
scope = apply_json_filters(scope, :tags, relation.tags)
|
|
141
|
+
scope = apply_json_filters(scope, :context, relation.contexts)
|
|
155
142
|
scope = apply_time_filters(scope, relation)
|
|
156
143
|
scope = apply_search(scope, relation)
|
|
157
144
|
scope
|
|
158
145
|
end
|
|
159
146
|
|
|
160
|
-
def
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
if relation.names.size == 1
|
|
164
|
-
scope.where(name: relation.names.first)
|
|
165
|
-
else
|
|
166
|
-
scope.where(name: relation.names)
|
|
167
|
-
end
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
def apply_tag_filters(scope, relation)
|
|
171
|
-
return scope if relation.tags.blank?
|
|
172
|
-
|
|
173
|
-
relation.tags.each do |key, value|
|
|
174
|
-
scope = scope.where(*JsonQuery.contains(:tags, key, value))
|
|
175
|
-
end
|
|
176
|
-
scope
|
|
177
|
-
end
|
|
178
|
-
|
|
179
|
-
def apply_context_filters(scope, relation)
|
|
180
|
-
return scope if relation.contexts.blank?
|
|
181
|
-
|
|
182
|
-
relation.contexts.each do |key, value|
|
|
183
|
-
scope = scope.where(*JsonQuery.contains(:context, key, value))
|
|
147
|
+
def apply_json_filters(scope, column, filters)
|
|
148
|
+
filters.each do |key, value|
|
|
149
|
+
scope = scope.where(*JsonQuery.contains(column, key, value))
|
|
184
150
|
end
|
|
185
151
|
scope
|
|
186
152
|
end
|
|
@@ -6,13 +6,6 @@ module RailsEventViewer
|
|
|
6
6
|
module InMemoryFiltering
|
|
7
7
|
extend ActiveSupport::Concern
|
|
8
8
|
|
|
9
|
-
def distinct_group_values(key, source: :context)
|
|
10
|
-
in_memory_events
|
|
11
|
-
.map { |e| group_value_for(e, key, source) }
|
|
12
|
-
.compact
|
|
13
|
-
.uniq
|
|
14
|
-
end
|
|
15
|
-
|
|
16
9
|
def group_instances(key, source: :context, limit: 100)
|
|
17
10
|
in_memory_events
|
|
18
11
|
.group_by { |e| group_value_for(e, key, source).to_s }
|
|
@@ -11,10 +11,6 @@ module RailsEventViewer
|
|
|
11
11
|
false
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
def supports_retention?
|
|
15
|
-
false
|
|
16
|
-
end
|
|
17
|
-
|
|
18
14
|
def write_events(events)
|
|
19
15
|
nil
|
|
20
16
|
end
|
|
@@ -51,10 +47,6 @@ module RailsEventViewer
|
|
|
51
47
|
0
|
|
52
48
|
end
|
|
53
49
|
|
|
54
|
-
def distinct_group_values(key, source: :context)
|
|
55
|
-
[]
|
|
56
|
-
end
|
|
57
|
-
|
|
58
50
|
def group_instances(key, source: :context, limit: 100)
|
|
59
51
|
[]
|
|
60
52
|
end
|
|
@@ -26,10 +26,6 @@ module RailsEventViewer
|
|
|
26
26
|
@max_events = max_events
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
def supports_analytics?
|
|
30
|
-
true
|
|
31
|
-
end
|
|
32
|
-
|
|
33
29
|
def write_events(events)
|
|
34
30
|
return if events.empty?
|
|
35
31
|
|
|
@@ -57,7 +53,7 @@ module RailsEventViewer
|
|
|
57
53
|
|
|
58
54
|
def fetch_events(relation)
|
|
59
55
|
if relation.filtered?
|
|
60
|
-
return
|
|
56
|
+
return filter_events(in_memory_events, relation).drop(relation.offset_value).take(relation.limit_value)
|
|
61
57
|
end
|
|
62
58
|
|
|
63
59
|
start_idx = relation.offset_value
|
|
@@ -68,7 +64,7 @@ module RailsEventViewer
|
|
|
68
64
|
|
|
69
65
|
def count_events(relation)
|
|
70
66
|
if relation.filtered?
|
|
71
|
-
|
|
67
|
+
filter_events(in_memory_events, relation).size
|
|
72
68
|
else
|
|
73
69
|
@redis.with { |conn| conn.zcard(events_key) }
|
|
74
70
|
end
|
|
@@ -171,18 +167,8 @@ module RailsEventViewer
|
|
|
171
167
|
data
|
|
172
168
|
end
|
|
173
169
|
|
|
174
|
-
def fetch_all_events
|
|
175
|
-
serialized_events = @redis.with { |conn| conn.zrevrange(events_key, 0, -1) }
|
|
176
|
-
serialized_events.map { |json| deserialize_event(json) }
|
|
177
|
-
end
|
|
178
|
-
|
|
179
|
-
def fetch_all_filtered(relation)
|
|
180
|
-
events = fetch_all_events
|
|
181
|
-
filter_events(events, relation)
|
|
182
|
-
end
|
|
183
|
-
|
|
184
170
|
def in_memory_events
|
|
185
|
-
|
|
171
|
+
@redis.with { |conn| conn.zrevrange(events_key, 0, -1) }.map { |json| deserialize_event(json) }
|
|
186
172
|
end
|
|
187
173
|
end
|
|
188
174
|
end
|
|
@@ -56,7 +56,7 @@ module RailsEventViewer
|
|
|
56
56
|
if @thread&.alive?
|
|
57
57
|
@flush_requests << true
|
|
58
58
|
@thread.join(shutdown_timeout)
|
|
59
|
-
effective_logger
|
|
59
|
+
RailsEventViewer.effective_logger.warn("[RailsEventViewer] Flusher thread still busy after #{shutdown_timeout}s writing #{@writing} events") if @thread.alive?
|
|
60
60
|
end
|
|
61
61
|
|
|
62
62
|
@mutex.synchronize { @thread = nil }
|
|
@@ -72,7 +72,7 @@ module RailsEventViewer
|
|
|
72
72
|
|
|
73
73
|
report_dropped_events
|
|
74
74
|
leftover = @buffer.size
|
|
75
|
-
effective_logger
|
|
75
|
+
RailsEventViewer.effective_logger.warn("[RailsEventViewer] #{leftover} events still buffered at shutdown") if leftover.positive?
|
|
76
76
|
end
|
|
77
77
|
|
|
78
78
|
def running?
|
|
@@ -126,7 +126,7 @@ module RailsEventViewer
|
|
|
126
126
|
end
|
|
127
127
|
return if dropped.zero?
|
|
128
128
|
|
|
129
|
-
effective_logger
|
|
129
|
+
RailsEventViewer.effective_logger.warn("[RailsEventViewer] Dropped #{dropped} events because the buffer was full")
|
|
130
130
|
end
|
|
131
131
|
|
|
132
132
|
def request_flush
|
|
@@ -143,7 +143,7 @@ module RailsEventViewer
|
|
|
143
143
|
end
|
|
144
144
|
|
|
145
145
|
def run_loop
|
|
146
|
-
effective_logger
|
|
146
|
+
RailsEventViewer.effective_logger.debug("[RailsEventViewer] Flusher thread started (PID: #{Process.pid})")
|
|
147
147
|
|
|
148
148
|
until shutdown_requested?
|
|
149
149
|
begin
|
|
@@ -157,7 +157,7 @@ module RailsEventViewer
|
|
|
157
157
|
end
|
|
158
158
|
end
|
|
159
159
|
|
|
160
|
-
effective_logger
|
|
160
|
+
RailsEventViewer.effective_logger.debug("[RailsEventViewer] Flusher thread stopped (PID: #{Process.pid})")
|
|
161
161
|
end
|
|
162
162
|
|
|
163
163
|
def wait_for_flush
|
|
@@ -3,17 +3,7 @@ module RailsEventViewer
|
|
|
3
3
|
private
|
|
4
4
|
|
|
5
5
|
def log_error(message)
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
if logger
|
|
9
|
-
logger.error(message)
|
|
10
|
-
else
|
|
11
|
-
warn message
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def effective_logger
|
|
16
|
-
RailsEventViewer.logger || (defined?(Rails) && Rails.logger)
|
|
6
|
+
RailsEventViewer.effective_logger.error(message)
|
|
17
7
|
end
|
|
18
8
|
end
|
|
19
9
|
end
|
data/lib/rails_event_viewer.rb
CHANGED
|
@@ -14,6 +14,7 @@ module RailsEventViewer
|
|
|
14
14
|
mattr_accessor :buffer_size, default: 100 # Flush after N events
|
|
15
15
|
mattr_accessor :flush_interval, default: 2 # Flush every N seconds
|
|
16
16
|
mattr_accessor :sample_rate, default: 1.0 # 1.0 = 100%, 0.1 = 10%
|
|
17
|
+
mattr_accessor :transactional, default: true # false = a failed sync write does not abort the caller's transaction
|
|
17
18
|
mattr_accessor :buffer, default: Buffers::Memory.new
|
|
18
19
|
|
|
19
20
|
mattr_accessor :retention_period, default: 7.days
|
|
@@ -76,6 +77,10 @@ module RailsEventViewer
|
|
|
76
77
|
subscriber.stop!
|
|
77
78
|
end
|
|
78
79
|
|
|
80
|
+
def effective_logger
|
|
81
|
+
logger || (defined?(Rails) && Rails.logger) || (@fallback_logger ||= Logger.new($stdout))
|
|
82
|
+
end
|
|
83
|
+
|
|
79
84
|
private
|
|
80
85
|
|
|
81
86
|
def build_adapter
|
|
@@ -101,7 +106,7 @@ module RailsEventViewer
|
|
|
101
106
|
|
|
102
107
|
if storage_adapter == :active_record && !adapter_instance.table_exists?
|
|
103
108
|
effective_logger.warn "[RailsEventViewer] Table 'rails_event_viewer_entries' not found. " \
|
|
104
|
-
"Run `rails rails_event_viewer:install
|
|
109
|
+
"Run `bin/rails generate rails_event_viewer:install` and `bin/rails db:migrate`. " \
|
|
105
110
|
"Falling back to NullAdapter (events will not be persisted)."
|
|
106
111
|
require "rails_event_viewer/adapters/null"
|
|
107
112
|
Adapters::Null.new
|
|
@@ -109,10 +114,6 @@ module RailsEventViewer
|
|
|
109
114
|
adapter_instance
|
|
110
115
|
end
|
|
111
116
|
end
|
|
112
|
-
|
|
113
|
-
def effective_logger
|
|
114
|
-
logger || (defined?(Rails) && Rails.logger) || Logger.new($stdout)
|
|
115
|
-
end
|
|
116
117
|
end
|
|
117
118
|
end
|
|
118
119
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rails_event_viewer
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Keshav Biswa
|
|
@@ -30,6 +30,9 @@ dependencies:
|
|
|
30
30
|
- - ">="
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
32
|
version: '5.0'
|
|
33
|
+
- - "<"
|
|
34
|
+
- !ruby/object:Gem::Version
|
|
35
|
+
version: '6'
|
|
33
36
|
type: :runtime
|
|
34
37
|
prerelease: false
|
|
35
38
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -37,6 +40,9 @@ dependencies:
|
|
|
37
40
|
- - ">="
|
|
38
41
|
- !ruby/object:Gem::Version
|
|
39
42
|
version: '5.0'
|
|
43
|
+
- - "<"
|
|
44
|
+
- !ruby/object:Gem::Version
|
|
45
|
+
version: '6'
|
|
40
46
|
- !ruby/object:Gem::Dependency
|
|
41
47
|
name: groupdate
|
|
42
48
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -69,7 +75,6 @@ files:
|
|
|
69
75
|
- app/assets/javascripts/rails_event_viewer/chartjs-adapter-date-fns.bundle.min.js
|
|
70
76
|
- app/assets/javascripts/rails_event_viewer/chartkick.min.js
|
|
71
77
|
- app/assets/stylesheets/rails_event_viewer/application.css
|
|
72
|
-
- app/assets/stylesheets/rails_event_viewer/tailwind.css
|
|
73
78
|
- app/controllers/rails_event_viewer/analytics_controller.rb
|
|
74
79
|
- app/controllers/rails_event_viewer/application_controller.rb
|
|
75
80
|
- app/controllers/rails_event_viewer/dashboard_controller.rb
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
@tailwind base;
|
|
2
|
-
@tailwind components;
|
|
3
|
-
@tailwind utilities;
|
|
4
|
-
|
|
5
|
-
.json-tree {
|
|
6
|
-
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
7
|
-
font-size: 0.875rem;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
.json-tree-key {
|
|
11
|
-
color: #4b5563;
|
|
12
|
-
font-weight: 500;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
.json-tree-string {
|
|
16
|
-
color: #059669;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
.json-tree-number {
|
|
20
|
-
color: #2563eb;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
.json-tree-boolean {
|
|
24
|
-
color: #7c3aed;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
.json-tree-null {
|
|
28
|
-
color: #9ca3af;
|
|
29
|
-
}
|