catpm 0.6.5 → 0.6.6

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: '0938b1a8e37174b8c0415de3303614b40657302ac1cf4d366214fe9dd0fd769c'
4
- data.tar.gz: cc9308558a8a7065ff99d225fb18244ab8f51492af67f3d7ba83fa2e48923b35
3
+ metadata.gz: 584e9923c1e96355460ab405299df1d35e2116b4ca81b07bb350ae6d8ec773cf
4
+ data.tar.gz: c972d35aad27e3a6da12029192fbbb25e5674fd29ab4994b5c8f6baed0995c6f
5
5
  SHA512:
6
- metadata.gz: b5c7af3130bf87eb185ca324214dfefc2e5c4bd1ecf5a180200ade47847c3f9fa710bc8bc108055f969344e76134f5369bcd82441193ac9199bcbe072093d0e9
7
- data.tar.gz: 1c47ef33465c2eaa31a92c7cf538afc9cc9b055ef21128181888c94c1363b886e6bc81c4cabfb229d856b4d500856ac189820c020326615a460698737578cf1b
6
+ metadata.gz: 9fc17e982f9f39197c8398db38b601860c0977bb311b48204016fed327d7cc58c95bc897d74fe0b8e7bc72f75421eb95319bf64f007485348ef4b62179dbd2e8
7
+ data.tar.gz: 688688d4f266af7950c70bb7377d9846ebf3377550446d0761fc20426b7081ce5006d7ef567a6a589d79bc9cb9eb29a3b0b77c314832ce17c383f355f435e1f7
@@ -121,8 +121,9 @@
121
121
 
122
122
  <tr><td colspan="2" style="font-weight:600;color:var(--text-2);font-size:11px;text-transform:uppercase;letter-spacing:0.5px;padding-top:12px">Sampling</td></tr>
123
123
  <tr><td>Random Sample Rate</td><td class="mono">1 in <%= @config.random_sample_rate %></td></tr>
124
- <tr><td>Max Random Samples / Endpoint</td><td class="mono"><%= @config.max_random_samples_per_endpoint %></td></tr>
125
- <tr><td>Max Slow Samples / Endpoint</td><td class="mono"><%= @config.max_slow_samples_per_endpoint %></td></tr>
124
+ <tr><td>Max Random Samples / Endpoint</td><td class="mono"><%= @config.max_random_samples_per_endpoint || "unlimited" %></td></tr>
125
+ <tr><td>Max Slow Samples / Endpoint</td><td class="mono"><%= @config.max_slow_samples_per_endpoint || "unlimited" %></td></tr>
126
+ <tr><td>Max Error Samples / Fingerprint</td><td class="mono"><%= @config.max_error_samples_per_fingerprint || "unlimited" %></td></tr>
126
127
 
127
128
  <tr><td colspan="2" style="font-weight:600;color:var(--text-2);font-size:11px;text-transform:uppercase;letter-spacing:0.5px;padding-top:12px">Buffer & Flush</td></tr>
128
129
  <tr><td>Max Buffer Memory</td><td class="mono"><%= number_to_human_size(@config.max_buffer_memory) %></td></tr>
data/lib/catpm/flusher.rb CHANGED
@@ -83,8 +83,8 @@ module Catpm
83
83
  adapter.persist_buckets(buckets)
84
84
 
85
85
  bucket_map = build_bucket_map(buckets)
86
- samples = rotate_samples(samples)
87
86
  adapter.persist_samples(samples, bucket_map)
87
+ trim_samples(samples)
88
88
  adapter.persist_errors(errors)
89
89
  end
90
90
 
@@ -227,75 +227,43 @@ module Catpm
227
227
  end
228
228
 
229
229
 
230
- def rotate_samples(samples)
231
- return samples if samples.empty?
230
+ # Trim excess samples AFTER insert. Simpler and guaranteed correct —
231
+ # no stale-cache issues when a single flush batch crosses the limit.
232
+ def trim_samples(samples)
233
+ return if samples.empty?
232
234
 
233
- # Pre-fetch counts for all endpoints and types in bulk
234
235
  endpoint_keys = samples.map { |s| s[:bucket_key][0..2] }.uniq
235
- error_fps = samples.filter_map { |s| s[:error_fingerprint] }.uniq
236
-
237
- # Build counts cache: { [kind, target, op, type] => count }
238
- counts_cache = {}
239
- if endpoint_keys.any?
240
- Catpm::Sample.joins(:bucket)
241
- .where(catpm_buckets: { kind: endpoint_keys.map(&:first), target: endpoint_keys.map { |k| k[1] }, operation: endpoint_keys.map { |k| k[2] } })
242
- .where(sample_type: %w[random slow])
243
- .group('catpm_buckets.kind', 'catpm_buckets.target', 'catpm_buckets.operation', 'catpm_samples.sample_type')
244
- .count
245
- .each { |(kind, target, op, type), cnt| counts_cache[[kind, target, op, type]] = cnt }
246
- end
247
236
 
248
- error_counts = {}
249
- if error_fps.any?
250
- Catpm::Sample.where(sample_type: 'error', error_fingerprint: error_fps)
251
- .group(:error_fingerprint).count
252
- .each { |fp, cnt| error_counts[fp] = cnt }
237
+ endpoint_keys.each do |kind, target, operation|
238
+ endpoint_scope = Catpm::Sample.joins(:bucket)
239
+ .where(catpm_buckets: { kind: kind, target: target, operation: operation })
240
+
241
+ # Random: keep newest N
242
+ max_random = Catpm.config.max_random_samples_per_endpoint
243
+ trim_by_column(endpoint_scope.where(sample_type: 'random'), max_random, :recorded_at) if max_random
244
+
245
+ # Slow: keep highest-duration N
246
+ max_slow = Catpm.config.max_slow_samples_per_endpoint
247
+ trim_by_column(endpoint_scope.where(sample_type: 'slow'), max_slow, :duration) if max_slow
248
+
253
249
  end
254
250
 
255
- samples.each do |sample|
256
- kind, target, operation = sample[:bucket_key][0..2]
257
-
258
- case sample[:sample_type]
259
- when 'random'
260
- max_random = Catpm.config.max_random_samples_per_endpoint
261
- if max_random
262
- cache_key = [kind, target, operation, 'random']
263
- if (counts_cache[cache_key] || 0) >= max_random
264
- oldest = Catpm::Sample.joins(:bucket)
265
- .where(catpm_buckets: { kind: kind, target: target, operation: operation })
266
- .where(sample_type: 'random').order(recorded_at: :asc).first
267
- oldest&.destroy
268
- end
269
- end
270
- when 'slow'
271
- max_slow = Catpm.config.max_slow_samples_per_endpoint
272
- if max_slow
273
- cache_key = [kind, target, operation, 'slow']
274
- if (counts_cache[cache_key] || 0) >= max_slow
275
- weakest = Catpm::Sample.joins(:bucket)
276
- .where(catpm_buckets: { kind: kind, target: target, operation: operation })
277
- .where(sample_type: 'slow').order(duration: :asc).first
278
- if weakest && sample[:duration] > weakest.duration
279
- weakest.destroy
280
- else
281
- sample[:_skip] = true
282
- end
283
- end
284
- end
285
- when 'error'
286
- max_err = Catpm.config.max_error_samples_per_fingerprint
287
- if max_err
288
- fp = sample[:error_fingerprint]
289
- if fp && (error_counts[fp] || 0) >= max_err
290
- oldest = Catpm::Sample.where(sample_type: 'error', error_fingerprint: fp)
291
- .order(recorded_at: :asc).first
292
- oldest&.destroy
293
- end
294
- end
251
+ # Errors: per-fingerprint cap (keep newest within each fingerprint)
252
+ max_err_fp = Catpm.config.max_error_samples_per_fingerprint
253
+ if max_err_fp
254
+ fps = samples.filter_map { |s| s[:error_fingerprint] }.uniq
255
+ fps.each do |fp|
256
+ trim_by_column(Catpm::Sample.where(sample_type: 'error', error_fingerprint: fp), max_err_fp, :recorded_at)
295
257
  end
296
258
  end
259
+ end
260
+
261
+ def trim_by_column(scope, max, keep_column)
262
+ count = scope.count
263
+ return if count <= max
297
264
 
298
- samples.reject { |s| s.delete(:_skip) }
265
+ excess_ids = scope.order(keep_column => :asc).limit(count - max).pluck(:id)
266
+ Catpm::Sample.where(id: excess_ids).delete_all if excess_ids.any?
299
267
  end
300
268
 
301
269
  def build_error_context(event)
data/lib/catpm/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Catpm
4
- VERSION = '0.6.5'
4
+ VERSION = '0.6.6'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: catpm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.5
4
+ version: 0.6.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - ''