rails_event_viewer 0.2.0 → 0.2.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 +8 -0
- data/README.md +1 -1
- data/lib/rails_event_viewer/batch_writer.rb +2 -2
- data/lib/rails_event_viewer/flusher.rb +34 -9
- data/lib/rails_event_viewer/subscriber.rb +10 -3
- 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: 5d1fae32fbd34187f3531ab552271d62005f6c8877bd814ca08207053d349178
|
|
4
|
+
data.tar.gz: 05b561609b0ad4d7d7065e61e0a67891a8d9b4f2b970366869097a38a4d17293
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 38ee32bc44c4fd20adf78b42e8d9110c1328615fe0072bfe00325d9c76fc7eba4ed3f909a98cabf0e6c345b4f8fb64cca6802255c5c7ab3721731bef3bfc91ee
|
|
7
|
+
data.tar.gz: 0040bd1d2ce832bc80e35cac7248bc6461375f703f3ae299913264b43955d07e2b8a947bb0b9b349128f0aa45d352a5e5cc4b52401554943141e3fe5eec06962
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.1 (2026-10-01)
|
|
4
|
+
|
|
5
|
+
- Forked workers no longer duplicate the parent's buffered events on exit.
|
|
6
|
+
- Payload, tags and context are snapshotted at emit time as JSON values (`Time` becomes a string).
|
|
7
|
+
- Unserializable payloads are stored via `inspect` instead of raising.
|
|
8
|
+
- The flusher writes inside the Rails executor.
|
|
9
|
+
- Shutdown has a deadline and logs buffered and dropped events.
|
|
10
|
+
|
|
3
11
|
## 0.2.0 (2026-10-01)
|
|
4
12
|
|
|
5
13
|
- Pluggable buffers: `config.buffer` accepts any object implementing `RailsEventViewer::Buffer` (`push`, `drain`, `commit`, `revert`, `dead`, `size`, `after_fork`). `push` returns the new size. The in-memory buffer remains the default.
|
data/README.md
CHANGED
|
@@ -63,7 +63,7 @@ RailsEventViewer.configure do |config|
|
|
|
63
63
|
end
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
-
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.
|
|
66
|
+
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. On a normal shutdown, buffered events are written for up to 5 seconds. Anything left is logged and lost. If the process is killed, the whole buffer is lost.
|
|
67
67
|
|
|
68
68
|
Internal Rails events such as `active_record.*` and `action_controller.*` are ignored by default. Remove a pattern from `ignored_events` to capture it.
|
|
69
69
|
|
|
@@ -17,7 +17,7 @@ module RailsEventViewer
|
|
|
17
17
|
@strikes = Hash.new(0)
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
-
def write(events)
|
|
20
|
+
def write(events, split: true)
|
|
21
21
|
RailsEventViewer.adapter.write_events(events)
|
|
22
22
|
@buffer.commit(events)
|
|
23
23
|
forget(events)
|
|
@@ -26,7 +26,7 @@ module RailsEventViewer
|
|
|
26
26
|
rescue => e
|
|
27
27
|
log_error("[RailsEventViewer] Failed to write #{events.size} events: #{e.message}")
|
|
28
28
|
@failed_attempts += 1
|
|
29
|
-
return write_individually(events) if @failed_attempts >= MAX_ATTEMPTS
|
|
29
|
+
return write_individually(events) if split && @failed_attempts >= MAX_ATTEMPTS
|
|
30
30
|
|
|
31
31
|
@buffer.revert(events)
|
|
32
32
|
false
|
|
@@ -13,6 +13,7 @@ module RailsEventViewer
|
|
|
13
13
|
@thread = nil
|
|
14
14
|
@shutdown_requested = false
|
|
15
15
|
@dropped_count = 0
|
|
16
|
+
@writing = 0
|
|
16
17
|
@pid = Process.pid
|
|
17
18
|
end
|
|
18
19
|
|
|
@@ -28,23 +29,34 @@ module RailsEventViewer
|
|
|
28
29
|
end
|
|
29
30
|
|
|
30
31
|
def flush!
|
|
31
|
-
|
|
32
|
-
return true if
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
32
|
+
handle_fork_if_needed
|
|
33
|
+
return true if @buffer.size.zero?
|
|
34
|
+
|
|
35
|
+
Rails.application.executor.wrap(source: "application.rails_event_viewer") do
|
|
36
|
+
events = @buffer.drain([@buffer.size, max_buffer_size].min)
|
|
37
|
+
next true if events.empty?
|
|
38
|
+
|
|
39
|
+
@writing = events.size
|
|
40
|
+
written = @writer.write(events, split: !shutdown_requested?)
|
|
41
|
+
report_dropped_events if written
|
|
42
|
+
written
|
|
43
|
+
ensure
|
|
44
|
+
@writing = 0
|
|
45
|
+
end
|
|
37
46
|
rescue => e
|
|
38
47
|
log_error("[RailsEventViewer] Failed to flush: #{e.message}")
|
|
39
48
|
false
|
|
40
49
|
end
|
|
41
50
|
|
|
42
51
|
def stop!
|
|
52
|
+
handle_fork_if_needed
|
|
53
|
+
deadline = Process.clock_gettime(Process::CLOCK_MONOTONIC) + shutdown_timeout
|
|
43
54
|
@mutex.synchronize { @shutdown_requested = true }
|
|
44
55
|
|
|
45
56
|
if @thread&.alive?
|
|
46
57
|
@flush_requests << true
|
|
47
|
-
@thread.join(
|
|
58
|
+
@thread.join(shutdown_timeout)
|
|
59
|
+
effective_logger&.warn("[RailsEventViewer] Flusher thread still busy after #{shutdown_timeout}s writing #{@writing} events") if @thread.alive?
|
|
48
60
|
end
|
|
49
61
|
|
|
50
62
|
@mutex.synchronize { @thread = nil }
|
|
@@ -52,10 +64,15 @@ module RailsEventViewer
|
|
|
52
64
|
loop do
|
|
53
65
|
remaining = @buffer.size
|
|
54
66
|
break if remaining.zero?
|
|
67
|
+
break if Process.clock_gettime(Process::CLOCK_MONOTONIC) >= deadline
|
|
55
68
|
|
|
56
69
|
flush!
|
|
57
|
-
break if @buffer.size >= remaining
|
|
70
|
+
break if @buffer.size >= remaining # no progress, stop retrying
|
|
58
71
|
end
|
|
72
|
+
|
|
73
|
+
report_dropped_events
|
|
74
|
+
leftover = @buffer.size
|
|
75
|
+
effective_logger&.warn("[RailsEventViewer] #{leftover} events still buffered at shutdown") if leftover.positive?
|
|
59
76
|
end
|
|
60
77
|
|
|
61
78
|
def running?
|
|
@@ -82,6 +99,10 @@ module RailsEventViewer
|
|
|
82
99
|
end
|
|
83
100
|
end
|
|
84
101
|
|
|
102
|
+
def shutdown_timeout
|
|
103
|
+
SHUTDOWN_TIMEOUT_SECONDS
|
|
104
|
+
end
|
|
105
|
+
|
|
85
106
|
def max_buffer_size
|
|
86
107
|
RailsEventViewer.buffer_size * MAX_BUFFER_MULTIPLIER
|
|
87
108
|
end
|
|
@@ -98,7 +119,11 @@ module RailsEventViewer
|
|
|
98
119
|
end
|
|
99
120
|
|
|
100
121
|
def report_dropped_events
|
|
101
|
-
dropped = @mutex.synchronize
|
|
122
|
+
dropped = @mutex.synchronize do
|
|
123
|
+
count = @dropped_count
|
|
124
|
+
@dropped_count = 0
|
|
125
|
+
count
|
|
126
|
+
end
|
|
102
127
|
return if dropped.zero?
|
|
103
128
|
|
|
104
129
|
effective_logger&.warn("[RailsEventViewer] Dropped #{dropped} events because the buffer was full")
|
|
@@ -82,9 +82,9 @@ module RailsEventViewer
|
|
|
82
82
|
|
|
83
83
|
{
|
|
84
84
|
name: event[:name],
|
|
85
|
-
payload: serialize_payload(event[:payload]),
|
|
86
|
-
tags: event[:tags] || {},
|
|
87
|
-
context: event[:context] || {},
|
|
85
|
+
payload: snapshot(serialize_payload(event[:payload])),
|
|
86
|
+
tags: snapshot(event[:tags] || {}),
|
|
87
|
+
context: snapshot(event[:context] || {}),
|
|
88
88
|
source_file: event.dig(:source_location, :filepath),
|
|
89
89
|
source_line: event.dig(:source_location, :lineno),
|
|
90
90
|
source_label: event.dig(:source_location, :label),
|
|
@@ -92,6 +92,13 @@ module RailsEventViewer
|
|
|
92
92
|
}
|
|
93
93
|
end
|
|
94
94
|
|
|
95
|
+
def snapshot(value)
|
|
96
|
+
json = value.as_json
|
|
97
|
+
json.is_a?(Hash) ? json.deep_symbolize_keys : json
|
|
98
|
+
rescue SystemStackError, StandardError
|
|
99
|
+
{ value: value.inspect }
|
|
100
|
+
end
|
|
101
|
+
|
|
95
102
|
def serialize_payload(payload)
|
|
96
103
|
case payload
|
|
97
104
|
when Hash
|