railscope 0.1.10 → 0.1.11

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: '02218f15b1789991595d3aad2ee44e995246ac00be8cc2b10f3769c40b2305d5'
4
- data.tar.gz: d17a705f4afc714006ca408a08342ba9798e993dc1ced98c6449ab36e913378d
3
+ metadata.gz: c7b44de114284ee8955d48c35c4966b45e8b798b1624d6a8abefb2212b9e4cd5
4
+ data.tar.gz: 44ba0061f1987733edf5a5dde93ce591fc9eb2ff63f3aae59854051313b59d84
5
5
  SHA512:
6
- metadata.gz: d18a4366d4a67a0f1a84f7ef105b164551e02a85fadf20c540f25591b6b8504712410567967ef99400d3e6976568f87132bc974462693a8b74fc902fd922fde9
7
- data.tar.gz: 4b0e0e2c93a415ce579f0f0b3983fd4937c9c9d1bf1c49c93294c318c76292da963d6a3aadd960afe49c980fb025cad3b5e8c88b2a6be2f01397a583ef8226ef
6
+ metadata.gz: 3b054e8e101d09dcd88c954eaf82452c9e18629398eb2270d2eddcd89769562eac8325a0c55c77505d5a1f2ecf5f2c7fa644d65e9eec318045c37832dbc3d92f
7
+ data.tar.gz: 9c7feb08613c99ef5fb206170dedb9e841a846e6d7077f4e06c8fa0673f19764f0ea5acff74da590e4879f7e78cb72213b9ceea35e76990f6b38e1aebabef26f
@@ -87,5 +87,30 @@ module Railscope
87
87
  end
88
88
 
89
89
  delegate :empty?, to: :@store
90
+
91
+ # Conditional recording: buffer entries until a trigger fires
92
+
93
+ def pending_entries
94
+ self[:pending_entries] ||= []
95
+ end
96
+
97
+ def triggered?
98
+ self[:triggered] == true
99
+ end
100
+
101
+ def trigger!
102
+ self[:triggered] = true
103
+ end
104
+
105
+ def buffer_entry(entry_data)
106
+ pending_entries << entry_data
107
+ end
108
+
109
+ def flush_pending!
110
+ pending_entries.each do |entry_data|
111
+ Railscope.storage.write(**entry_data)
112
+ end
113
+ pending_entries.clear
114
+ end
90
115
  end
91
116
  end
@@ -18,17 +18,20 @@ module Railscope
18
18
  # Capture response body for recording
19
19
  context = Context.current
20
20
  if context[:recording]
21
- # Read body from env (where Rails stores the response)
22
- body_content = extract_body_from_env(env)
23
-
24
- context_data = {
25
- batch_id: context.batch_id,
26
- env: env,
27
- headers: headers
28
- }
29
-
30
- # Update entry with response data
31
- update_entry_async(context_data, body_content)
21
+ # In conditional mode, skip persistence if trigger never fired
22
+ unless Railscope.conditional_recording? && !context.triggered?
23
+ # Read body from env (where Rails stores the response)
24
+ body_content = extract_body_from_env(env)
25
+
26
+ context_data = {
27
+ batch_id: context.batch_id,
28
+ env: env,
29
+ headers: headers
30
+ }
31
+
32
+ # Update entry with response data
33
+ update_entry_async(context_data, body_content)
34
+ end
32
35
  end
33
36
 
34
37
  [status, headers, response]
@@ -29,7 +29,7 @@ module Railscope
29
29
 
30
30
  filtered_payload = Railscope.filter(payload.merge(context_payload))
31
31
 
32
- Railscope.storage.write(
32
+ entry_data = {
33
33
  entry_type: entry_type,
34
34
  batch_id: context.batch_id,
35
35
  family_hash: family_hash,
@@ -37,7 +37,13 @@ module Railscope
37
37
  payload: filtered_payload,
38
38
  tags: (tags + context_tags).uniq,
39
39
  occurred_at: Time.current
40
- )
40
+ }
41
+
42
+ if Railscope.conditional_recording? && !context.triggered?
43
+ context.buffer_entry(entry_data)
44
+ else
45
+ Railscope.storage.write(**entry_data)
46
+ end
41
47
  end
42
48
 
43
49
  # Generate a family hash for grouping similar entries
@@ -76,7 +76,12 @@ module Railscope
76
76
  # Also create a separate exception entry if job failed
77
77
  create_exception_entry!(job, exception_object) if exception_object
78
78
 
79
- # Clear context after job completes
79
+ # In conditional mode: flush if triggered, otherwise entries are discarded with context
80
+ if Railscope.conditional_recording? && context.triggered?
81
+ # Response update for jobs is already in the entry payload, nothing extra needed
82
+ end
83
+
84
+ # Clear context after job completes (discards any unflushed buffer)
80
85
  Railscope::Context.clear!
81
86
  rescue StandardError => e
82
87
  Rails.logger.error("[Railscope] Failed to record job perform: #{e.message}")
@@ -42,6 +42,7 @@ module Railscope
42
42
  model_name = model.class.name
43
43
  return if model_name.nil?
44
44
  return if IGNORED_MODEL_PREFIXES.any? { |prefix| model_name.start_with?(prefix) }
45
+ return unless Railscope.should_track_model?(model_name)
45
46
 
46
47
  create_entry!(
47
48
  entry_type: "model",
@@ -50,6 +51,13 @@ module Railscope
50
51
  family_hash: build_family_hash(action, model),
51
52
  should_display_on_index: true
52
53
  )
54
+
55
+ # Conditional recording: flush buffered entries when trigger matches
56
+ if Railscope.conditional_recording? && !context.triggered? && Railscope.matches_trigger?(model_name, action)
57
+ context.trigger!
58
+ context.flush_pending!
59
+ end
60
+
53
61
  Rails.logger.debug("[Railscope] ModelSubscriber - entry created for #{model_name}")
54
62
  rescue StandardError => e
55
63
  Rails.logger.error("[Railscope] Failed to record model event: #{e.class}: #{e.message}")
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Railscope
4
- VERSION = "0.1.10"
4
+ VERSION = "0.1.11"
5
5
  end
data/lib/railscope.rb CHANGED
@@ -27,7 +27,8 @@ module Railscope
27
27
  STORAGE_REDIS = :redis
28
28
 
29
29
  class << self
30
- attr_writer :retention_days, :redis, :storage_backend, :ignore_paths, :ignore_jobs, :ignore_commands
30
+ attr_writer :retention_days, :redis, :storage_backend, :ignore_paths, :ignore_jobs, :ignore_commands,
31
+ :ignore_models
31
32
  attr_accessor :authenticate_with
32
33
 
33
34
  def enabled=(value)
@@ -123,6 +124,43 @@ module Railscope
123
124
  ignore_commands.any? { |pattern| command_name.match?(pattern) }
124
125
  end
125
126
 
127
+ # Model filtering (blocklist)
128
+
129
+ def ignore_models
130
+ @ignore_models ||= []
131
+ end
132
+
133
+ def add_ignore_models(*model_names)
134
+ @ignore_models = ignore_models.concat(model_names.flatten.map(&:to_s)).uniq
135
+ end
136
+
137
+ def should_track_model?(model_name)
138
+ return false if model_name.nil?
139
+
140
+ ignore_models.none? { |pattern| model_name.match?(pattern) }
141
+ end
142
+
143
+ # Conditional recording: only persist a batch when a watched model event fires
144
+
145
+ def watch_triggers
146
+ @watch_triggers ||= []
147
+ end
148
+
149
+ def add_watch_trigger(model_name, on:)
150
+ actions = Array(on).map(&:to_s)
151
+ @watch_triggers = watch_triggers.push({ model: model_name.to_s, on: actions }).uniq
152
+ end
153
+
154
+ def conditional_recording?
155
+ watch_triggers.any?
156
+ end
157
+
158
+ def matches_trigger?(model_name, action)
159
+ watch_triggers.any? do |trigger|
160
+ model_name.match?(trigger[:model]) && trigger[:on].include?(action.to_s)
161
+ end
162
+ end
163
+
126
164
  def context
127
165
  Context.current
128
166
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: railscope
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.10
4
+ version: 0.1.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Phelipe Tussolini
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 1980-01-02 00:00:00.000000000 Z
10
+ date: 2026-02-18 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: rails
@@ -155,7 +155,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
155
155
  - !ruby/object:Gem::Version
156
156
  version: '0'
157
157
  requirements: []
158
- rubygems_version: 3.6.9
158
+ rubygems_version: 3.6.2
159
159
  specification_version: 4
160
160
  summary: A debug assistant for Rails applications inspired by Laravel Telescope
161
161
  test_files: []