rails_event_viewer 0.1.2 → 0.1.3
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 +9 -0
- data/README.md +2 -0
- data/lib/rails_event_viewer/subscriber.rb +47 -33
- data/lib/rails_event_viewer/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: df70eeee67ca7c67116c852f98659be2d9ee3803a1bd4b949d3190f0aed1d40b
|
|
4
|
+
data.tar.gz: 0a83f0ce0b0504c7ba9823a1e2c3eaa1e9a4f79297aae5ff35e8f742c01b51ea
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 23eaca12170699b79b5fd635204e24a25bfc6a8eb8bbef0605aeaea40fab2701dda65ca4101fb9d64fea1a5c57fc77a9f94d6362a90f91fea587b196b5d38667
|
|
7
|
+
data.tar.gz: 8d981f6fe1a2673e91453ddf400be91537bd8b3686217c471e783939f9814ecc0b6240c368689c45219011e6d19ccdfed2e98ea19b61f7dcfcd2e0b5095267a9
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.3 (2026-10-01)
|
|
4
|
+
|
|
5
|
+
- The flusher thread starts on the first buffered event, not at boot, so consoles and rake tasks no longer run an idle thread.
|
|
6
|
+
- Flusher start/stop messages log at debug level.
|
|
7
|
+
- Events emitted after shutdown are written immediately instead of lost.
|
|
8
|
+
- Web requests never write to storage. A full buffer wakes the flusher thread instead.
|
|
9
|
+
- The buffer is capped at 10 times `buffer_size`. Overflow drops the oldest events and logs a warning.
|
|
10
|
+
- Removed the unused ActionCable broadcast.
|
|
11
|
+
|
|
3
12
|
## 0.1.2 (2026-09-30)
|
|
4
13
|
|
|
5
14
|
- Removed the `pagy` dependency. Pagination is handled by a small built-in class, so host apps on any Pagy version, or none, can install the gem.
|
data/README.md
CHANGED
|
@@ -61,6 +61,8 @@ RailsEventViewer.configure do |config|
|
|
|
61
61
|
end
|
|
62
62
|
```
|
|
63
63
|
|
|
64
|
+
With `async`, events are written by a background thread, never by your web requests. The buffer holds at most 10 times `buffer_size` events. If storage can't keep up, the oldest are dropped and a warning is logged. Events still in the buffer are written on a normal shutdown but lost if the process is killed.
|
|
65
|
+
|
|
64
66
|
Internal Rails events such as `active_record.*` and `action_controller.*` are ignored by default. Remove a pattern from `ignored_events` to capture it.
|
|
65
67
|
|
|
66
68
|
## Authentication
|
|
@@ -4,16 +4,16 @@ module RailsEventViewer
|
|
|
4
4
|
class Subscriber
|
|
5
5
|
NANOSECONDS_PER_SECOND = 1_000_000_000.0
|
|
6
6
|
SHUTDOWN_TIMEOUT_SECONDS = 5
|
|
7
|
-
|
|
7
|
+
MAX_BUFFER_MULTIPLIER = 10
|
|
8
8
|
|
|
9
9
|
def initialize
|
|
10
10
|
@buffer = Queue.new
|
|
11
|
+
@flush_requests = Queue.new
|
|
11
12
|
@mutex = Mutex.new
|
|
12
13
|
@flusher_thread = nil
|
|
13
14
|
@shutdown_requested = false
|
|
15
|
+
@dropped_count = 0
|
|
14
16
|
@pid = Process.pid
|
|
15
|
-
|
|
16
|
-
ensure_flusher_thread!
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def emit(event)
|
|
@@ -41,7 +41,7 @@ module RailsEventViewer
|
|
|
41
41
|
return if events_to_write.empty?
|
|
42
42
|
|
|
43
43
|
write_immediately(events_to_write)
|
|
44
|
-
|
|
44
|
+
report_dropped_events
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
def stop!
|
|
@@ -50,7 +50,7 @@ module RailsEventViewer
|
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
if @flusher_thread&.alive?
|
|
53
|
-
@
|
|
53
|
+
@flush_requests << true
|
|
54
54
|
@flusher_thread.join(SHUTDOWN_TIMEOUT_SECONDS)
|
|
55
55
|
end
|
|
56
56
|
|
|
@@ -58,7 +58,7 @@ module RailsEventViewer
|
|
|
58
58
|
@flusher_thread = nil
|
|
59
59
|
end
|
|
60
60
|
|
|
61
|
-
flush!
|
|
61
|
+
flush! until @buffer.empty?
|
|
62
62
|
end
|
|
63
63
|
|
|
64
64
|
def running?
|
|
@@ -77,25 +77,56 @@ module RailsEventViewer
|
|
|
77
77
|
if @pid != Process.pid
|
|
78
78
|
@pid = Process.pid
|
|
79
79
|
@buffer = Queue.new
|
|
80
|
+
@flush_requests = Queue.new
|
|
80
81
|
@flusher_thread = nil
|
|
81
82
|
@shutdown_requested = false
|
|
83
|
+
@dropped_count = 0
|
|
82
84
|
end
|
|
83
85
|
end
|
|
84
|
-
ensure_flusher_thread!
|
|
85
86
|
end
|
|
86
87
|
|
|
87
88
|
def drain_buffer
|
|
88
89
|
events = []
|
|
89
|
-
|
|
90
|
+
[@buffer.size, max_buffer_size].min.times { events << @buffer.pop(true) }
|
|
91
|
+
events
|
|
90
92
|
rescue ThreadError
|
|
91
93
|
events
|
|
92
94
|
end
|
|
93
95
|
|
|
94
96
|
def buffer_event(entry)
|
|
95
97
|
@buffer << entry
|
|
98
|
+
return flush! if shutdown_requested?
|
|
99
|
+
|
|
96
100
|
ensure_flusher_thread!
|
|
101
|
+
drop_oldest_events if @buffer.size > max_buffer_size
|
|
102
|
+
request_flush if @buffer.size >= RailsEventViewer.buffer_size
|
|
103
|
+
end
|
|
97
104
|
|
|
98
|
-
|
|
105
|
+
def max_buffer_size
|
|
106
|
+
RailsEventViewer.buffer_size * MAX_BUFFER_MULTIPLIER
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def drop_oldest_events
|
|
110
|
+
dropped = 0
|
|
111
|
+
while @buffer.size > max_buffer_size
|
|
112
|
+
@buffer.pop(true)
|
|
113
|
+
dropped += 1
|
|
114
|
+
end
|
|
115
|
+
rescue ThreadError
|
|
116
|
+
nil
|
|
117
|
+
ensure
|
|
118
|
+
@mutex.synchronize { @dropped_count += dropped } if dropped.positive?
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def report_dropped_events
|
|
122
|
+
dropped = @mutex.synchronize { @dropped_count.tap { @dropped_count = 0 } }
|
|
123
|
+
return if dropped.zero?
|
|
124
|
+
|
|
125
|
+
effective_logger&.warn("[RailsEventViewer] Dropped #{dropped} events because the buffer was full")
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def request_flush
|
|
129
|
+
@flush_requests << true if @flush_requests.empty?
|
|
99
130
|
end
|
|
100
131
|
|
|
101
132
|
def ensure_flusher_thread!
|
|
@@ -110,18 +141,21 @@ module RailsEventViewer
|
|
|
110
141
|
end
|
|
111
142
|
|
|
112
143
|
def run_flusher_loop
|
|
113
|
-
|
|
144
|
+
effective_logger&.debug("[RailsEventViewer] Flusher thread started (PID: #{Process.pid})")
|
|
114
145
|
|
|
115
146
|
until shutdown_requested?
|
|
116
147
|
begin
|
|
117
|
-
|
|
118
|
-
|
|
148
|
+
@flush_requests.pop(timeout: RailsEventViewer.flush_interval)
|
|
149
|
+
loop do
|
|
150
|
+
flush!
|
|
151
|
+
break if @buffer.size < RailsEventViewer.buffer_size || shutdown_requested?
|
|
152
|
+
end
|
|
119
153
|
rescue => e
|
|
120
154
|
log_error("[RailsEventViewer] Flusher error: #{e.message}")
|
|
121
155
|
end
|
|
122
156
|
end
|
|
123
157
|
|
|
124
|
-
|
|
158
|
+
effective_logger&.debug("[RailsEventViewer] Flusher thread stopped (PID: #{Process.pid})")
|
|
125
159
|
end
|
|
126
160
|
|
|
127
161
|
def shutdown_requested?
|
|
@@ -136,22 +170,6 @@ module RailsEventViewer
|
|
|
136
170
|
log_error("[RailsEventViewer] Failed to write #{events.size} events: #{e.message}")
|
|
137
171
|
end
|
|
138
172
|
|
|
139
|
-
def broadcast_events(events)
|
|
140
|
-
return unless defined?(ActionCable)
|
|
141
|
-
return unless events.any?
|
|
142
|
-
|
|
143
|
-
ActionCable.server.broadcast(
|
|
144
|
-
ACTION_CABLE_CHANNEL,
|
|
145
|
-
{
|
|
146
|
-
action: "new_events",
|
|
147
|
-
count: events.size,
|
|
148
|
-
events: events.map { |e| { name: e[:name], occurred_at: e[:occurred_at]&.iso8601 } }
|
|
149
|
-
}
|
|
150
|
-
)
|
|
151
|
-
rescue => e
|
|
152
|
-
log_error("[RailsEventViewer] Broadcast error: #{e.message}")
|
|
153
|
-
end
|
|
154
|
-
|
|
155
173
|
def should_capture?(event)
|
|
156
174
|
return false unless event.is_a?(Hash)
|
|
157
175
|
return false if event[:name].blank?
|
|
@@ -234,10 +252,6 @@ module RailsEventViewer
|
|
|
234
252
|
log_error("[RailsEventViewer] Failed to capture event '#{event[:name]}': #{error.message}")
|
|
235
253
|
end
|
|
236
254
|
|
|
237
|
-
def log_info(message)
|
|
238
|
-
effective_logger&.info(message)
|
|
239
|
-
end
|
|
240
|
-
|
|
241
255
|
def log_error(message)
|
|
242
256
|
logger = effective_logger
|
|
243
257
|
|