railscope 0.1.8 → 0.1.10

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: 0e9ec16b5594be5149c2eb5c788341639e877834078254dfb4cf60e710f5d5da
4
- data.tar.gz: 87c0eee66e2348ddd5de721266f202fffa9d2e648d487000950e7cdbc8feb7ea
3
+ metadata.gz: '02218f15b1789991595d3aad2ee44e995246ac00be8cc2b10f3769c40b2305d5'
4
+ data.tar.gz: d17a705f4afc714006ca408a08342ba9798e993dc1ced98c6449ab36e913378d
5
5
  SHA512:
6
- metadata.gz: 9305e62918875b960fa46478b0d92d26c5180e6842e2ded5fd9a3bb58502f93824f5dcd07ac1f1bf9fad6e9c056bd1e0e2fe145917f39aec176d3653efc1fa19
7
- data.tar.gz: 7efb34240a018c7ce5abf3a595008b981f1f01df1b951f148ef1c5f3adb51511ff12fc914cef824f5bdf904acf3fe4d5b6ca52aac0221e9d8c0733398f00ef46
6
+ metadata.gz: d18a4366d4a67a0f1a84f7ef105b164551e02a85fadf20c540f25591b6b8504712410567967ef99400d3e6976568f87132bc974462693a8b74fc902fd922fde9
7
+ data.tar.gz: 4b0e0e2c93a415ce579f0f0b3983fd4937c9c9d1bf1c49c93294c318c76292da963d6a3aadd960afe49c980fb025cad3b5e8c88b2a6be2f01397a583ef8226ef
data/README.md CHANGED
@@ -65,6 +65,15 @@ Railscope.configure do |config|
65
65
  # Paths to ignore (defaults: /railscope, /assets, /packs, /cable)
66
66
  config.add_ignore_paths("/health", "/ping", "/metrics")
67
67
 
68
+ # Jobs to ignore (class names or regex patterns)
69
+ config.add_ignore_jobs("SomeFrequentJob", "Turbo::Streams::.*")
70
+
71
+ # Rake tasks to ignore (task names or regex patterns)
72
+ config.add_ignore_commands("db:.*", "assets:.*", "tmp:.*")
73
+
74
+ # Use an existing Redis connection (useful for SSL/connection sharing)
75
+ # config.redis = $redis
76
+
68
77
  # Additional sensitive keys to filter
69
78
  config.add_sensitive_keys(:cpf, :ssn, :bank_account)
70
79
  end
@@ -208,6 +217,51 @@ Railscope::PurgeJob.perform_now
208
217
  Railscope::PurgeJob.perform_later
209
218
  ```
210
219
 
220
+ ## Filtering Entries
221
+
222
+ ### Ignore Paths
223
+
224
+ Requests matching these path prefixes will not be recorded:
225
+
226
+ ```ruby
227
+ # Defaults: /railscope, /assets, /packs, /cable
228
+ config.add_ignore_paths("/health", "/ping", "/metrics", "/up")
229
+ ```
230
+
231
+ ### Ignore Jobs
232
+
233
+ Background jobs matching these patterns will not be recorded (enqueue, perform, or exceptions). Accepts exact class names or regex patterns:
234
+
235
+ ```ruby
236
+ # Exact match
237
+ config.add_ignore_jobs("HeartbeatJob")
238
+
239
+ # Regex patterns
240
+ config.add_ignore_jobs("SolidQueue::.*", "Turbo::Streams::.*", "ActionMailbox::.*")
241
+ ```
242
+
243
+ ### Ignore Commands
244
+
245
+ Rake tasks matching these patterns will not be instrumented. Accepts exact task names or regex patterns:
246
+
247
+ ```ruby
248
+ # Exact match
249
+ config.add_ignore_commands("db:migrate")
250
+
251
+ # Regex patterns — ignore entire namespaces
252
+ config.add_ignore_commands("db:.*", "assets:.*", "tmp:.*", "log:.*")
253
+ ```
254
+
255
+ ### Custom Redis Connection
256
+
257
+ By default, Railscope creates its own Redis connection from `RAILSCOPE_REDIS_URL` or `REDIS_URL`. If your app already has a configured Redis instance (e.g., with SSL on Heroku), you can pass it directly:
258
+
259
+ ```ruby
260
+ config.redis = $redis
261
+ ```
262
+
263
+ This avoids SSL certificate issues and shares the existing connection configuration.
264
+
211
265
  ## Filtered Parameters
212
266
 
213
267
  Railscope automatically filters sensitive data:
@@ -279,8 +333,11 @@ Railscope is designed to have minimal impact:
279
333
  For high-traffic production environments, consider:
280
334
  - Using `:redis` backend for lower request latency
281
335
  - Shorter retention periods
282
- - Adding high-traffic paths to ignore list
336
+ - Ignoring noisy paths (`/health`, `/ping`, polling endpoints)
337
+ - Ignoring high-frequency jobs (`SolidQueue::.*`, `Turbo::Streams::.*`)
338
+ - Ignoring routine rake tasks (`db:.*`, `assets:.*`)
283
339
  - Running purge job more frequently
340
+ - Using `config.redis = $redis` to share the app's existing Redis connection
284
341
 
285
342
  ## License
286
343
 
@@ -49,6 +49,28 @@ Railscope.configure do |config|
49
49
  #
50
50
  # config.add_ignore_paths("/health", "/ping", "/metrics")
51
51
 
52
+ # Ignored Jobs
53
+ # ------------
54
+ # Jobs matching these patterns will not be recorded.
55
+ # Accepts class names or regex patterns.
56
+ #
57
+ # config.add_ignore_jobs("SomeFrequentJob", "Turbo::Streams::.*")
58
+
59
+ # Ignored Commands
60
+ # ----------------
61
+ # Rake tasks matching these patterns will not be recorded.
62
+ # Accepts task names or regex patterns.
63
+ #
64
+ # config.add_ignore_commands("db:.*", "assets:.*", "tmp:.*")
65
+
66
+ # Redis Connection
67
+ # ----------------
68
+ # By default, Railscope creates its own Redis connection from
69
+ # RAILSCOPE_REDIS_URL or REDIS_URL. You can pass an existing
70
+ # Redis instance instead (useful for SSL/connection sharing):
71
+ #
72
+ # config.redis = $redis
73
+
52
74
  # Sensitive Keys
53
75
  # --------------
54
76
  # Additional parameter names to filter from payloads.
@@ -4,7 +4,8 @@ module Railscope
4
4
  class FlushService
5
5
  BUFFER_KEY = "railscope:buffer"
6
6
  UPDATES_KEY = "railscope:buffer:updates"
7
- BATCH_SIZE = 1000
7
+ BATCH_SIZE = 100
8
+ MAX_RETRIES = 3
8
9
 
9
10
  def self.call
10
11
  new.call
@@ -20,6 +21,7 @@ module Railscope
20
21
 
21
22
  def flush_entries
22
23
  total = 0
24
+ retries = 0
23
25
 
24
26
  loop do
25
27
  batch = pop_batch(BUFFER_KEY)
@@ -28,12 +30,25 @@ module Railscope
28
30
  entries = batch.map { |json| JSON.parse(json, symbolize_names: true) }
29
31
  batch_insert_to_database(entries)
30
32
  total += entries.size
33
+ retries = 0
34
+ rescue Redis::BaseError => e
35
+ retries += 1
36
+ if retries <= MAX_RETRIES
37
+ Rails.logger.warn("[Railscope] Redis connection lost during flush, reconnecting (attempt #{retries}/#{MAX_RETRIES})...")
38
+ reconnect_redis!
39
+ retry
40
+ else
41
+ Rails.logger.error("[Railscope] Redis flush failed after #{MAX_RETRIES} retries (flushed #{total} entries): #{e.message}")
42
+ break
43
+ end
31
44
  end
32
45
 
33
46
  total
34
47
  end
35
48
 
36
49
  def apply_pending_updates
50
+ retries = 0
51
+
37
52
  loop do
38
53
  batch = pop_batch(UPDATES_KEY)
39
54
  break if batch.empty?
@@ -42,6 +57,17 @@ module Railscope
42
57
  update = JSON.parse(json, symbolize_names: true)
43
58
  apply_update(update)
44
59
  end
60
+ retries = 0
61
+ rescue Redis::BaseError => e
62
+ retries += 1
63
+ if retries <= MAX_RETRIES
64
+ Rails.logger.warn("[Railscope] Redis connection lost during updates, reconnecting (attempt #{retries}/#{MAX_RETRIES})...")
65
+ reconnect_redis!
66
+ retry
67
+ else
68
+ Rails.logger.error("[Railscope] Redis updates failed after #{MAX_RETRIES} retries: #{e.message}")
69
+ break
70
+ end
45
71
  end
46
72
  end
47
73
 
@@ -85,6 +111,14 @@ module Railscope
85
111
  redis.lpop(key, BATCH_SIZE) || []
86
112
  end
87
113
 
114
+ def reconnect_redis!
115
+ Railscope.redis&.close
116
+ rescue StandardError
117
+ # ignore
118
+ ensure
119
+ Railscope.instance_variable_set(:@redis, nil)
120
+ end
121
+
88
122
  def redis
89
123
  Railscope.redis
90
124
  end
@@ -23,6 +23,7 @@ module Railscope
23
23
 
24
24
  def instrument_task(task)
25
25
  return if task.name.start_with?("railscope:")
26
+ return if Railscope.ignore_command?(task.name)
26
27
  return if instrumented_tasks.include?(task.name)
27
28
 
28
29
  instrumented_tasks << task.name
@@ -199,7 +199,7 @@ module Railscope
199
199
  end
200
200
 
201
201
  def ignore_job?(job)
202
- job.class.name.start_with?("Railscope::")
202
+ job.class.name.start_with?("Railscope::") || Railscope.ignore_job?(job.class.name)
203
203
  end
204
204
 
205
205
  def setup_job_context(job)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Railscope
4
- VERSION = "0.1.8"
4
+ VERSION = "0.1.10"
5
5
  end
data/lib/railscope.rb CHANGED
@@ -27,7 +27,7 @@ module Railscope
27
27
  STORAGE_REDIS = :redis
28
28
 
29
29
  class << self
30
- attr_writer :retention_days, :redis, :storage_backend, :ignore_paths
30
+ attr_writer :retention_days, :redis, :storage_backend, :ignore_paths, :ignore_jobs, :ignore_commands
31
31
  attr_accessor :authenticate_with
32
32
 
33
33
  def enabled=(value)
@@ -99,6 +99,30 @@ module Railscope
99
99
  @ignore_paths = ignore_paths.concat(paths.flatten).uniq
100
100
  end
101
101
 
102
+ def ignore_jobs
103
+ @ignore_jobs ||= []
104
+ end
105
+
106
+ def add_ignore_jobs(*job_classes)
107
+ @ignore_jobs = ignore_jobs.concat(job_classes.flatten.map(&:to_s)).uniq
108
+ end
109
+
110
+ def ignore_job?(job_class_name)
111
+ ignore_jobs.any? { |pattern| job_class_name.match?(pattern) }
112
+ end
113
+
114
+ def ignore_commands
115
+ @ignore_commands ||= []
116
+ end
117
+
118
+ def add_ignore_commands(*commands)
119
+ @ignore_commands = ignore_commands.concat(commands.flatten.map(&:to_s)).uniq
120
+ end
121
+
122
+ def ignore_command?(command_name)
123
+ ignore_commands.any? { |pattern| command_name.match?(pattern) }
124
+ end
125
+
102
126
  def context
103
127
  Context.current
104
128
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: railscope
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8
4
+ version: 0.1.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Phelipe Tussolini