solarwinds_apm 7.1.0 → 7.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d565e746144994b5c3a81ee19665ee9b2d4e81fbad2e21da567465455c37e6c0
4
- data.tar.gz: 949351c94748745d2ba19268a531ba5b4f805568132772dcfb9749b0af3698a8
3
+ metadata.gz: '082c952e4514335f3f4b5371745bc77c371592d8f4473b65149bdcd2613281a2'
4
+ data.tar.gz: 9ee34f536ac6580862f9b97cfed9942d36b235a533e0f75c55181de30a80d69f
5
5
  SHA512:
6
- metadata.gz: 209a50b78aa94dc85805ef8c6c08db7584966ca62293c53aa9744852170c3c84ac4ef24b2e43e508bad5d1e505f4cd82d72d984a00823232b9a9e13bddb061c6
7
- data.tar.gz: '0962ab7325e66d3f330361b9f0187f75c07eabcd2d0d400db0d55e75c2124aefa2fe630cbe2eef506f48f58f6e6d3cb6ad1d36f1a816845618b6bd2649e8b951'
6
+ metadata.gz: b35526de0b456a81e53feb19ec84a48d592f48077cb52cdef3f9ca2e0cfa8cc341bbc41904255de6550c5484bb4da85ca555ada74f48461cd9817858bf4c6ac2
7
+ data.tar.gz: '0549ec00da3f0f6940baec1049072c6a5ef96b7ac9c90c2f7a3078ed52f51ff50eeee93e5fe6b12a2ce08cd8f71b39341ed6ffa2b5cf249762d5d9477ac9462b'
@@ -192,29 +192,14 @@ module SolarWindsAPM
192
192
  case key
193
193
  when :sampling_rate
194
194
  SolarWindsAPM.logger.warn do
195
- "[#{name}/#{__method__}] sampling_rate is not a supported setting for SolarWindsAPM::Config. Please use :sample_rate."
195
+ '[Deprecated] sampling_rate is not a supported setting for SolarWindsAPM::Config.'
196
196
  end
197
197
 
198
198
  when :sample_rate
199
- unless value.is_a?(Integer) || value.is_a?(Float)
200
- SolarWindsAPM.logger.warn do
201
- "[#{name}/#{__method__}] :sample_rate must be a number between 0 and 1000000 (1m) (provided: #{value}), corrected to 0"
202
- end
203
- value = 0
204
- end
205
-
206
- # Validate :sample_rate value
207
- unless value.between?(0, 1e6)
208
- new_value = value.negative? ? 0 : 1_000_000
209
- SolarWindsAPM.logger.warn do
210
- "[#{name}/#{__method__}] :sample_rate must be between 0 and 1000000 (1m) (provided: #{value}), corrected to #{new_value}"
211
- end
199
+ SolarWindsAPM.logger.warn do
200
+ '[Deprecated] sample_rate is not a supported setting for SolarWindsAPM::Config.'
212
201
  end
213
202
 
214
- # Assure value is an integer
215
- @@config[key.to_sym] = new_value.to_i
216
- SolarWindsAPM.sample_rate(new_value)
217
-
218
203
  when :transaction_settings
219
204
  compile_settings(value)
220
205
 
@@ -18,7 +18,6 @@ module SolarWindsAPM
18
18
  TRIGGERED_TRACE_ATTRIBUTE = 'TriggeredTrace'
19
19
 
20
20
  TRACESTATE_REGEXP = /^[0-9a-f]{16}-[0-9a-f]{2}$/
21
- BUCKET_INTERVAL = 1000
22
21
  DICE_SCALE = 1_000_000
23
22
 
24
23
  OTEL_SAMPLING_DECISION = ::OpenTelemetry::SDK::Trace::Samplers::Decision
@@ -30,16 +29,14 @@ module SolarWindsAPM
30
29
  @counters = SolarWindsAPM::Metrics::Counter.new
31
30
  @buckets = {
32
31
  SolarWindsAPM::BucketType::DEFAULT =>
33
- SolarWindsAPM::TokenBucket.new(SolarWindsAPM::TokenBucketSettings.new(nil, nil, BUCKET_INTERVAL, 'DEFUALT')),
32
+ SolarWindsAPM::TokenBucket.new(SolarWindsAPM::TokenBucketSettings.new(nil, nil, 'DEFUALT')),
34
33
  SolarWindsAPM::BucketType::TRIGGER_RELAXED =>
35
- SolarWindsAPM::TokenBucket.new(SolarWindsAPM::TokenBucketSettings.new(nil, nil, BUCKET_INTERVAL, 'TRIGGER_RELAXED')),
34
+ SolarWindsAPM::TokenBucket.new(SolarWindsAPM::TokenBucketSettings.new(nil, nil, 'TRIGGER_RELAXED')),
36
35
  SolarWindsAPM::BucketType::TRIGGER_STRICT =>
37
- SolarWindsAPM::TokenBucket.new(SolarWindsAPM::TokenBucketSettings.new(nil, nil, BUCKET_INTERVAL, 'TRIGGER_STRICT'))
36
+ SolarWindsAPM::TokenBucket.new(SolarWindsAPM::TokenBucketSettings.new(nil, nil, 'TRIGGER_STRICT'))
38
37
  }
39
38
  @settings = {} # parsed setting from swo backend
40
39
  @settings_mutex = ::Mutex.new
41
-
42
- @buckets.each_value(&:start)
43
40
  end
44
41
 
45
42
  # return sampling result
@@ -289,9 +286,9 @@ module SolarWindsAPM
289
286
  end
290
287
 
291
288
  def update_settings(settings)
292
- return unless settings[:timestamp] > (@settings[:timestamp] || 0)
293
-
294
289
  @settings_mutex.synchronize do
290
+ return unless settings[:timestamp] > (@settings[:timestamp] || 0)
291
+
295
292
  @settings = settings
296
293
  @buckets.each do |type, bucket|
297
294
  bucket.update(@settings[:buckets][type]) if @settings[:buckets][type]
@@ -324,18 +321,20 @@ module SolarWindsAPM
324
321
  end
325
322
 
326
323
  def get_settings(params)
327
- return if @settings.empty?
328
-
329
- expiry = (@settings[:timestamp] + @settings[:ttl]) * 1000
330
- time_now = Time.now.to_i * 1000
331
- if time_now > expiry
332
- @logger.debug { "[#{self.class}/#{__method__}] settings expired, removing" }
333
- @settings = {}
334
- return
324
+ @settings_mutex.synchronize do
325
+ return if @settings.empty?
326
+
327
+ expiry = (@settings[:timestamp] + @settings[:ttl]) * 1000
328
+ time_now = Time.now.to_i * 1000
329
+ if time_now > expiry
330
+ @logger.debug { "[#{self.class}/#{__method__}] settings expired, removing" }
331
+ @settings = {}
332
+ return
333
+ end
334
+ sampling_setting = SolarWindsAPM::SamplingSettings.merge(@settings, local_settings(params))
335
+ @logger.debug { "[#{self.class}/#{__method__}] sampling_setting: #{sampling_setting.inspect}" }
336
+ sampling_setting
335
337
  end
336
- sampling_setting = SolarWindsAPM::SamplingSettings.merge(@settings, local_settings(params))
337
- @logger.debug { "[#{self.class}/#{__method__}] sampling_setting: #{sampling_setting.inspect}" }
338
- sampling_setting
339
338
  end
340
339
  end
341
340
  end
@@ -55,7 +55,6 @@ module SolarWindsAPM
55
55
 
56
56
  TokenBucketSettings = Struct.new(:capacity, # Number
57
57
  :rate, # Number
58
- :interval, # Number
59
58
  :type) # String
60
59
 
61
60
  module SampleSource
@@ -10,126 +10,88 @@
10
10
  # capacity is updated through update_settings
11
11
  module SolarWindsAPM
12
12
  class TokenBucket
13
- # Maximum value of a signed 32-bit integer
14
- MAX_INTERVAL = (2**31) - 1
15
-
16
- attr_reader :capacity, :rate, :interval, :tokens, :type
13
+ attr_reader :type
17
14
 
18
15
  def initialize(token_bucket_settings)
19
- self.capacity = token_bucket_settings.capacity || 0
20
- self.rate = token_bucket_settings.rate || 0
21
- self.interval = token_bucket_settings.interval || MAX_INTERVAL
22
- self.tokens = @capacity
16
+ @capacity = token_bucket_settings.capacity || 0
17
+ @rate = token_bucket_settings.rate || 0
18
+ @tokens = @capacity
19
+ @last_update_time = Time.now.to_f
23
20
  @type = token_bucket_settings.type
24
- @timer = nil
21
+ @lock = ::Mutex.new
25
22
  end
26
23
 
27
- # oboe sampler update_settings will update the token
28
- # (thread safe as update_settings is guarded by mutex from oboe sampler)
29
- def update(settings)
30
- settings.instance_of?(Hash) ? update_from_hash(settings) : update_from_token_bucket_settings(settings)
24
+ def capacity
25
+ @lock.synchronize { @capacity }
31
26
  end
32
27
 
33
- def update_from_hash(settings)
34
- if settings[:capacity]
35
- difference = settings[:capacity] - @capacity
36
- self.capacity = settings[:capacity]
37
- self.tokens = @tokens + difference
38
- end
39
-
40
- self.rate = settings[:rate] if settings[:rate]
41
-
42
- return unless settings[:interval]
43
-
44
- self.interval = settings[:interval]
45
- return unless running
46
-
47
- stop
48
- start
28
+ def rate
29
+ @lock.synchronize { @rate }
49
30
  end
50
31
 
51
- def update_from_token_bucket_settings(settings)
52
- if settings.capacity
53
- difference = settings.capacity - @capacity
54
- self.capacity = settings.capacity
55
- self.tokens = @tokens + difference
32
+ def tokens
33
+ @lock.synchronize do
34
+ calculate_tokens
35
+ @tokens
56
36
  end
57
-
58
- self.rate = settings.rate if settings.rate
59
-
60
- return unless settings.interval
61
-
62
- self.interval = settings.interval
63
- return unless running
64
-
65
- stop
66
- start
67
- end
68
-
69
- def capacity=(capacity)
70
- @capacity = [0, capacity].max
71
- end
72
-
73
- def rate=(rate)
74
- @rate = [0, rate].max
75
- end
76
-
77
- # self.interval= sets the @interval and @sleep_interval
78
- # @sleep_interval is used in the timer thread to sleep between replenishing the bucket
79
- def interval=(interval)
80
- @interval = interval.clamp(0, MAX_INTERVAL)
81
- @sleep_interval = @interval / 1000.0
82
37
  end
83
38
 
84
- def tokens=(tokens)
85
- @tokens = tokens.clamp(0, @capacity)
39
+ # oboe sampler update_settings will update the token
40
+ def update(settings)
41
+ settings.instance_of?(Hash) ? update_from_hash(settings) : update_from_hash(tb_to_hash(settings))
86
42
  end
87
43
 
88
44
  # Attempts to consume tokens from the bucket
89
- # @param n [Integer] Number of tokens to consume
45
+ # @param token [Integer] Number of tokens to consume
90
46
  # @return [Boolean] Whether there were enough tokens
91
- # TODO: we need to include thread-safety here since sampler is shared across threads
92
- # and we may have multiple threads trying to consume tokens at the same time
93
47
  def consume(token = 1)
94
- if @tokens >= token
95
- self.tokens = @tokens - token
96
- SolarWindsAPM.logger.debug { "[#{self.class}/#{__method__}] #{@type} Consumed #{token} from total #{@tokens} (#{(@tokens.to_f / @capacity * 100).round(1)}% remaining)" }
97
- true
98
- else
99
- SolarWindsAPM.logger.debug { "[#{self.class}/#{__method__}] #{@type} Token consumption failed: requested=#{token}, available=#{@tokens}, capacity=#{@capacity}" }
100
- false
101
- end
102
- end
103
-
104
- # Starts replenishing the bucket
105
- def start
106
- return if running
107
-
108
- @timer = Thread.new do
109
- loop do
110
- task
111
- sleep(@sleep_interval)
48
+ @lock.synchronize do
49
+ calculate_tokens
50
+ if @tokens >= token
51
+ @tokens -= token
52
+ SolarWindsAPM.logger.debug { "[#{self.class}/#{__method__}] #{@type} Consumed #{token} (#{(@tokens.to_f / @capacity * 100).round(1)}% remaining)" }
53
+ true
54
+ else
55
+ SolarWindsAPM.logger.debug { "[#{self.class}/#{__method__}] #{@type} Token consumption failed: requested=#{token}, available=#{@tokens}, capacity=#{@capacity}" }
56
+ false
112
57
  end
113
58
  end
114
59
  end
115
60
 
116
- # Stops replenishing the bucket
117
- def stop
118
- return unless running
61
+ private
119
62
 
120
- @timer.kill
121
- @timer = nil
63
+ def calculate_tokens
64
+ now = Time.now.to_f
65
+ elapsed = now - @last_update_time
66
+ @last_update_time = now
67
+ @tokens += elapsed * @rate
68
+ @tokens = [@tokens, @capacity].min
122
69
  end
123
70
 
124
- # Whether the bucket is actively being replenished
125
- def running
126
- !@timer.nil?
127
- end
71
+ # settings is from json sampler
72
+ def update_from_hash(settings)
73
+ @lock.synchronize do
74
+ calculate_tokens
75
+
76
+ if settings[:capacity]
77
+ new_capacity = [0, settings[:capacity]].max
78
+ difference = new_capacity - @capacity
79
+ @capacity = new_capacity
80
+ @tokens += difference
81
+ @tokens = [0, @tokens].max
82
+ end
128
83
 
129
- private
84
+ @rate = [0, settings[:rate]].max if settings[:rate]
85
+ end
86
+ end
130
87
 
131
- def task
132
- self.tokens = tokens + @rate
88
+ # settings is from http sampler
89
+ def tb_to_hash(settings)
90
+ tb_hash = {}
91
+ tb_hash[:capacity] = settings.capacity if settings.respond_to?(:capacity)
92
+ tb_hash[:rate] = settings.rate if settings.respond_to?(:rate)
93
+ tb_hash[:type] = settings.type if settings.respond_to?(:type)
94
+ tb_hash
133
95
  end
134
96
  end
135
97
  end
@@ -13,7 +13,7 @@ module SolarWindsAPM
13
13
  module Version
14
14
  MAJOR = 7 # breaking,
15
15
  MINOR = 1 # feature,
16
- PATCH = 0 # fix => BFF
16
+ PATCH = 1 # fix => BFF
17
17
  PRE = nil
18
18
 
19
19
  STRING = [MAJOR, MINOR, PATCH, PRE].compact.join('.')
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solarwinds_apm
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.1.0
4
+ version: 7.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maia Engeli
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2025-10-21 00:00:00.000000000 Z
14
+ date: 2026-01-20 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: opentelemetry-exporter-otlp