catpm 0.6.2 → 0.6.4
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/app/controllers/catpm/endpoints_controller.rb +3 -3
- data/lib/catpm/collector.rb +55 -0
- data/lib/catpm/configuration.rb +39 -30
- data/lib/catpm/event.rb +20 -4
- data/lib/catpm/flusher.rb +1 -0
- data/lib/catpm/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: 3085a527e26332fa08ecca7de2efaa10b43cedc80b0505c88edae91edd7ec66f
|
|
4
|
+
data.tar.gz: 396130a945ff87931a1abea5c9b287b2529416f95a19aee47b5d8daa4e3812ca
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4a043995497b5b3046cdee78037f0a89b9801d84f6d58df30a06b2380b866d7d9157c9d33f823e0a50c643b734d37339dcfab3f3a4b3d7cce70a381eb61c8432
|
|
7
|
+
data.tar.gz: 5e9be269fae7cc4dae79427c8d77284631bda64a25a10235da3755d8a9ec194eb85ff4e0fded2690aa633d1100295734081116d5484bd4be6ae6b69b1f7b21d4
|
|
@@ -81,9 +81,9 @@ module Catpm
|
|
|
81
81
|
.joins(:bucket)
|
|
82
82
|
.where(catpm_buckets: { kind: @kind, target: @target, operation: @operation })
|
|
83
83
|
|
|
84
|
-
@slow_samples = endpoint_samples.where(sample_type: 'slow').order(duration: :desc)
|
|
85
|
-
@samples = endpoint_samples.where(sample_type: 'random').order(recorded_at: :desc)
|
|
86
|
-
@error_samples = endpoint_samples.where(sample_type: 'error').order(recorded_at: :desc)
|
|
84
|
+
@slow_samples = endpoint_samples.where(sample_type: 'slow').order(duration: :desc)
|
|
85
|
+
@samples = endpoint_samples.where(sample_type: 'random').order(recorded_at: :desc)
|
|
86
|
+
@error_samples = endpoint_samples.where(sample_type: 'error').order(recorded_at: :desc)
|
|
87
87
|
|
|
88
88
|
@pref = Catpm::EndpointPref.find_by(kind: @kind, target: @target, operation: @operation)
|
|
89
89
|
@active_error_count = Catpm::ErrorRecord.unresolved.count
|
data/lib/catpm/collector.rb
CHANGED
|
@@ -45,6 +45,7 @@ module Catpm
|
|
|
45
45
|
|
|
46
46
|
if req_segments
|
|
47
47
|
segments = segment_data[:segments]
|
|
48
|
+
collapse_code_wrappers(segments)
|
|
48
49
|
|
|
49
50
|
# Inject root request segment with full duration
|
|
50
51
|
root_segment = {
|
|
@@ -227,6 +228,7 @@ module Catpm
|
|
|
227
228
|
|
|
228
229
|
if req_segments && segment_data
|
|
229
230
|
segments = segment_data[:segments]
|
|
231
|
+
collapse_code_wrappers(segments)
|
|
230
232
|
|
|
231
233
|
# Inject root request segment
|
|
232
234
|
root_segment = {
|
|
@@ -331,6 +333,55 @@ module Catpm
|
|
|
331
333
|
|
|
332
334
|
private
|
|
333
335
|
|
|
336
|
+
# Remove near-zero-duration "code" spans that merely wrap a "controller" span.
|
|
337
|
+
# This happens when CallTracer (TracePoint) captures a thin dispatch method
|
|
338
|
+
# (e.g. Telegram::WebhookController#process) whose :return fires before the
|
|
339
|
+
# ActiveSupport controller notification finishes.
|
|
340
|
+
# Mutates segments in place: removes the wrapper and re-indexes parent references.
|
|
341
|
+
def collapse_code_wrappers(segments)
|
|
342
|
+
# Identify code spans to collapse: near-zero duration wrapping a controller child
|
|
343
|
+
collapse = {}
|
|
344
|
+
segments.each_with_index do |seg, i|
|
|
345
|
+
next unless seg[:type] == 'code'
|
|
346
|
+
next unless (seg[:duration] || 0).to_f < 1.0
|
|
347
|
+
|
|
348
|
+
has_controller_child = segments.any? { |s| s[:parent_index] == i && s[:type] == 'controller' }
|
|
349
|
+
next unless has_controller_child
|
|
350
|
+
|
|
351
|
+
collapse[i] = seg[:parent_index]
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
return if collapse.empty?
|
|
355
|
+
|
|
356
|
+
# Reparent children of collapsed spans
|
|
357
|
+
segments.each do |seg|
|
|
358
|
+
pi = seg[:parent_index]
|
|
359
|
+
next unless pi && collapse.key?(pi)
|
|
360
|
+
new_parent = collapse[pi]
|
|
361
|
+
if new_parent.nil?
|
|
362
|
+
seg.delete(:parent_index)
|
|
363
|
+
else
|
|
364
|
+
seg[:parent_index] = new_parent
|
|
365
|
+
end
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
# Build old→new index mapping, remove collapsed spans
|
|
369
|
+
old_to_new = {}
|
|
370
|
+
kept = []
|
|
371
|
+
segments.each_with_index do |seg, i|
|
|
372
|
+
next if collapse.key?(i)
|
|
373
|
+
old_to_new[i] = kept.size
|
|
374
|
+
kept << seg
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
# Rewrite parent references to new indices
|
|
378
|
+
kept.each do |seg|
|
|
379
|
+
seg[:parent_index] = old_to_new[seg[:parent_index]] if seg[:parent_index]
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
segments.replace(kept)
|
|
383
|
+
end
|
|
384
|
+
|
|
334
385
|
# Determine sample type at event creation time so only sampled events
|
|
335
386
|
# carry full context in the buffer. Includes filling phase via
|
|
336
387
|
# process-level counter (resets on restart — acceptable approximation).
|
|
@@ -355,6 +406,10 @@ module Catpm
|
|
|
355
406
|
@random_sample_counts ||= Hash.new(0)
|
|
356
407
|
end
|
|
357
408
|
|
|
409
|
+
def reset_sample_counts!
|
|
410
|
+
@random_sample_counts = nil
|
|
411
|
+
end
|
|
412
|
+
|
|
358
413
|
def inject_gap_segments(segments, req_segments, gap, ctrl_idx, ctrl_seg)
|
|
359
414
|
sampler_groups = req_segments&.sampler_segments || []
|
|
360
415
|
|
data/lib/catpm/configuration.rb
CHANGED
|
@@ -2,57 +2,66 @@
|
|
|
2
2
|
|
|
3
3
|
module Catpm
|
|
4
4
|
class Configuration
|
|
5
|
+
# Boolean / non-numeric settings — plain attr_accessor
|
|
5
6
|
attr_accessor :enabled,
|
|
6
7
|
:instrument_http,
|
|
7
8
|
:instrument_jobs,
|
|
8
9
|
:instrument_segments,
|
|
9
10
|
:instrument_net_http,
|
|
10
11
|
:instrument_stack_sampler,
|
|
11
|
-
:
|
|
12
|
-
:
|
|
13
|
-
:max_sql_length,
|
|
14
|
-
:slow_threshold,
|
|
12
|
+
:instrument_middleware_stack,
|
|
13
|
+
:instrument_call_tree,
|
|
15
14
|
:slow_threshold_per_kind,
|
|
16
15
|
:ignored_targets,
|
|
17
|
-
:retention_period,
|
|
18
|
-
:max_buffer_memory,
|
|
19
|
-
:flush_interval,
|
|
20
|
-
:flush_jitter,
|
|
21
|
-
:max_error_contexts,
|
|
22
16
|
:bucket_sizes,
|
|
23
17
|
:error_handler,
|
|
24
18
|
:http_basic_auth_user,
|
|
25
19
|
:http_basic_auth_password,
|
|
26
20
|
:access_policy,
|
|
27
21
|
:additional_filter_parameters,
|
|
28
|
-
:instrument_middleware_stack,
|
|
29
22
|
:auto_instrument_methods,
|
|
30
23
|
:service_base_classes,
|
|
31
|
-
:random_sample_rate,
|
|
32
|
-
:max_random_samples_per_endpoint,
|
|
33
|
-
:max_slow_samples_per_endpoint,
|
|
34
|
-
:max_error_samples_per_fingerprint,
|
|
35
|
-
:cleanup_interval,
|
|
36
|
-
:circuit_breaker_failure_threshold,
|
|
37
|
-
:circuit_breaker_recovery_timeout,
|
|
38
|
-
:sqlite_busy_timeout,
|
|
39
|
-
:persistence_batch_size,
|
|
40
|
-
:backtrace_lines,
|
|
41
|
-
:shutdown_timeout,
|
|
42
24
|
:events_enabled,
|
|
43
|
-
:events_max_samples_per_name,
|
|
44
25
|
:track_own_requests,
|
|
45
|
-
:stack_sample_interval,
|
|
46
|
-
:max_stack_samples_per_request,
|
|
47
26
|
:downsampling_thresholds,
|
|
48
|
-
:max_error_detail_length,
|
|
49
|
-
:max_fingerprint_app_frames,
|
|
50
|
-
:max_fingerprint_gem_frames,
|
|
51
|
-
:cleanup_batch_size,
|
|
52
|
-
:caller_scan_depth,
|
|
53
|
-
:instrument_call_tree,
|
|
54
27
|
:show_untracked_segments
|
|
55
28
|
|
|
29
|
+
# Numeric settings that must be positive numbers (nil not allowed)
|
|
30
|
+
REQUIRED_NUMERIC = %i[
|
|
31
|
+
max_sql_length slow_threshold max_buffer_memory flush_interval
|
|
32
|
+
flush_jitter max_error_contexts random_sample_rate cleanup_interval
|
|
33
|
+
circuit_breaker_failure_threshold circuit_breaker_recovery_timeout
|
|
34
|
+
sqlite_busy_timeout persistence_batch_size shutdown_timeout
|
|
35
|
+
events_max_samples_per_name stack_sample_interval
|
|
36
|
+
max_stack_samples_per_request max_error_detail_length
|
|
37
|
+
max_fingerprint_app_frames max_fingerprint_gem_frames
|
|
38
|
+
cleanup_batch_size caller_scan_depth segment_source_threshold
|
|
39
|
+
].freeze
|
|
40
|
+
|
|
41
|
+
# Numeric settings where nil means "unlimited"
|
|
42
|
+
OPTIONAL_NUMERIC = %i[
|
|
43
|
+
max_segments_per_request retention_period backtrace_lines
|
|
44
|
+
max_random_samples_per_endpoint max_slow_samples_per_endpoint
|
|
45
|
+
max_error_samples_per_fingerprint
|
|
46
|
+
].freeze
|
|
47
|
+
|
|
48
|
+
(REQUIRED_NUMERIC + OPTIONAL_NUMERIC).each do |attr|
|
|
49
|
+
attr_reader attr
|
|
50
|
+
|
|
51
|
+
define_method(:"#{attr}=") do |value|
|
|
52
|
+
if REQUIRED_NUMERIC.include?(attr)
|
|
53
|
+
unless value.is_a?(Numeric)
|
|
54
|
+
raise ArgumentError, "catpm config.#{attr} must be a number, got #{value.inspect}"
|
|
55
|
+
end
|
|
56
|
+
else
|
|
57
|
+
unless value.nil? || value.is_a?(Numeric)
|
|
58
|
+
raise ArgumentError, "catpm config.#{attr} must be a number or nil, got #{value.inspect}"
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
instance_variable_set(:"@#{attr}", value)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
56
65
|
def initialize
|
|
57
66
|
@enabled = true
|
|
58
67
|
@instrument_http = true
|
data/lib/catpm/event.rb
CHANGED
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
module Catpm
|
|
4
4
|
class Event
|
|
5
|
-
OBJECT_OVERHEAD = 40
|
|
6
|
-
REF_SIZE = 8
|
|
5
|
+
OBJECT_OVERHEAD = 40 # bytes, Ruby object header
|
|
6
|
+
REF_SIZE = 8 # bytes, pointer on 64-bit
|
|
7
|
+
HASH_ENTRY_SIZE = 80 # bytes, per key-value pair in a Hash (bucket + key obj + value obj)
|
|
7
8
|
NUMERIC_FIELDS_SIZE = 64 # fixed numeric fields (duration, timestamps, etc.)
|
|
8
9
|
|
|
9
10
|
attr_accessor :kind, :target, :operation, :duration, :started_at,
|
|
@@ -69,13 +70,28 @@ module Catpm
|
|
|
69
70
|
def context_bytes
|
|
70
71
|
return 0 if context.nil? || context.empty?
|
|
71
72
|
|
|
72
|
-
context
|
|
73
|
+
estimate_hash_bytes(context)
|
|
73
74
|
end
|
|
74
75
|
|
|
75
76
|
def metadata_bytes
|
|
76
77
|
return 0 if metadata.nil? || metadata.empty?
|
|
77
78
|
|
|
78
|
-
metadata
|
|
79
|
+
estimate_hash_bytes(metadata)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def estimate_hash_bytes(obj)
|
|
83
|
+
case obj
|
|
84
|
+
when Hash
|
|
85
|
+
OBJECT_OVERHEAD + obj.sum { |k, v| HASH_ENTRY_SIZE + estimate_hash_bytes(k) + estimate_hash_bytes(v) }
|
|
86
|
+
when Array
|
|
87
|
+
OBJECT_OVERHEAD + obj.sum { |v| REF_SIZE + estimate_hash_bytes(v) }
|
|
88
|
+
when String
|
|
89
|
+
OBJECT_OVERHEAD + obj.bytesize
|
|
90
|
+
when Symbol, Integer, Float, TrueClass, FalseClass, NilClass
|
|
91
|
+
REF_SIZE
|
|
92
|
+
else
|
|
93
|
+
OBJECT_OVERHEAD + REF_SIZE
|
|
94
|
+
end
|
|
79
95
|
end
|
|
80
96
|
end
|
|
81
97
|
end
|
data/lib/catpm/flusher.rb
CHANGED
data/lib/catpm/version.rb
CHANGED