scout_apm 5.5.0 → 5.6.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 +4 -4
- data/CHANGELOG.markdown +13 -0
- data/lib/scout_apm/agent_context.rb +4 -0
- data/lib/scout_apm/config.rb +69 -34
- data/lib/scout_apm/sampling.rb +104 -0
- data/lib/scout_apm/tracked_request.rb +5 -1
- data/lib/scout_apm/version.rb +1 -1
- data/lib/scout_apm.rb +1 -0
- data/test/test_helper.rb +29 -0
- data/test/unit/config_test.rb +20 -0
- data/test/unit/sampling_test.rb +215 -0
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 351ed300191874b86b1c402a2696897d05006266c2c88716a15d8588aefa00b2
|
|
4
|
+
data.tar.gz: dcdc4fb47007eb665f7a4df6a3a9a7bcde78550656692fc5023020739b0974d9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8fe62cd0646f58ad535d3912cf9c023fb8d7c52116dd30b3359e7f33f50f51ba3457090fe2df8f0bec5e5194b02bcccb44feaa466d76fa14938b91f11f1f74c0
|
|
7
|
+
data.tar.gz: cd20a788b47c33be24c8ee88eb00d443bf3d20990ba3fb769ca64353b14b090b931c121d6f07aa40bd366381f3f77646b41206e66cb9507cb204ee3eaadf62fe
|
data/CHANGELOG.markdown
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Unreleased
|
|
2
2
|
|
|
3
|
+
# 5.6.1
|
|
4
|
+
- Fix `job_sample_rate` and `endpoint_sample_rate` default configuration values (#529)
|
|
5
|
+
|
|
6
|
+
# 5.6.0
|
|
7
|
+
- New options for sampling and ignore configurationn (#521)
|
|
8
|
+
- `sample_rate` - Set the rate at which requests are sampled globally (1-100, a percentage of requests to keep).
|
|
9
|
+
- `ignore_endpoints` - Ignore endpoints by regex matching prefix (Same as and replaces `ignore`)
|
|
10
|
+
- `sample_endpoints` - Sample endpoints by regex matching prefix (i.e. ['/foo:70']).
|
|
11
|
+
- `endpoint_sample_rate` - Set the rate at which all non-matching web requests are sampled.
|
|
12
|
+
- `ignore_jobs` - Ignore Jobs by explicit name match.
|
|
13
|
+
- `sample_jobs` - Sample Jobs by explicit name match (i.e. ['MyJob:70']).
|
|
14
|
+
- `job_sample_rate` - Set the rate at which all non-matching background jobs are sampled.
|
|
15
|
+
|
|
3
16
|
# 5.5.0
|
|
4
17
|
- Fix undeclared logger in grape instruments (#510)
|
|
5
18
|
- Drop guaranteed support for Rubies <= 2.4
|
data/lib/scout_apm/config.rb
CHANGED
|
@@ -42,6 +42,13 @@ require 'scout_apm/environment'
|
|
|
42
42
|
# any instruments listed in this array. Default: []
|
|
43
43
|
# prepend_instruments - If `use_prepend` is false, force using Module#prepend for any
|
|
44
44
|
# instruments listed in this array. Default: []
|
|
45
|
+
# ignore_endpoints - An array of endpoints to ignore. These are matched as regular expressions. (supercedes 'ignore')
|
|
46
|
+
# ignore_jobs - An array of job names to ignore.
|
|
47
|
+
# sample_rate - Rate to sample entire application. An integer between 0 and 100. 0 means no traces are sent, 100 means all traces are sent.
|
|
48
|
+
# sample_endpoints - An array of endpoints to sample. These are matched as regular expressions with individual sample rate of 0 to 100.
|
|
49
|
+
# sample_jobs - An array of job names with individual sample rate of 0 to 100.
|
|
50
|
+
# endpoint_sample_rate - Rate to sample all endpoints. An integer between 0 and 100. 0 means no traces are sent, 100 means all traces are sent. (supercedes 'sample_rate')
|
|
51
|
+
# job_sample_rate - Rate to sample all jobs. An integer between 0 and 100. 0 means no traces are sent, 100 means all traces are sent. (supercedes 'sample_rate')
|
|
45
52
|
#
|
|
46
53
|
# Any of these config settings can be set with an environment variable prefixed
|
|
47
54
|
# by SCOUT_ and uppercasing the key: SCOUT_LOG_LEVEL for instance.
|
|
@@ -67,6 +74,8 @@ module ScoutApm
|
|
|
67
74
|
'host',
|
|
68
75
|
'hostname',
|
|
69
76
|
'ignore',
|
|
77
|
+
'ignore_endpoints',
|
|
78
|
+
'ignore_jobs',
|
|
70
79
|
'key',
|
|
71
80
|
'log_class',
|
|
72
81
|
'log_file_path',
|
|
@@ -83,6 +92,11 @@ module ScoutApm
|
|
|
83
92
|
'remote_agent_port',
|
|
84
93
|
'report_format',
|
|
85
94
|
'revision_sha',
|
|
95
|
+
'sample_rate',
|
|
96
|
+
'sample_endpoints',
|
|
97
|
+
'sample_jobs',
|
|
98
|
+
'endpoint_sample_rate',
|
|
99
|
+
'job_sample_rate',
|
|
86
100
|
'scm_subdirectory',
|
|
87
101
|
'start_resque_server_instrument',
|
|
88
102
|
'ssl_cert_file',
|
|
@@ -170,6 +184,13 @@ module ScoutApm
|
|
|
170
184
|
end
|
|
171
185
|
end
|
|
172
186
|
|
|
187
|
+
class NullableIntegerCoercion
|
|
188
|
+
def coerce(val)
|
|
189
|
+
return val if val.nil?
|
|
190
|
+
val.to_i
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
173
194
|
# Simply returns the passed in value, without change
|
|
174
195
|
class NullCoercion
|
|
175
196
|
def coerce(val)
|
|
@@ -184,6 +205,8 @@ module ScoutApm
|
|
|
184
205
|
'dev_trace' => BooleanCoercion.new,
|
|
185
206
|
'enable_background_jobs' => BooleanCoercion.new,
|
|
186
207
|
'ignore' => JsonCoercion.new,
|
|
208
|
+
'ignore_endpoints' => JsonCoercion.new,
|
|
209
|
+
'ignore_jobs' => JsonCoercion.new,
|
|
187
210
|
'max_traces' => IntegerCoercion.new,
|
|
188
211
|
'monitor' => BooleanCoercion.new,
|
|
189
212
|
'collect_remote_ip' => BooleanCoercion.new,
|
|
@@ -194,6 +217,11 @@ module ScoutApm
|
|
|
194
217
|
'external_service_metric_report_limit' => IntegerCoercion.new,
|
|
195
218
|
'instrument_http_url_length' => IntegerCoercion.new,
|
|
196
219
|
'record_queue_time' => BooleanCoercion.new,
|
|
220
|
+
'sample_rate' => IntegerCoercion.new,
|
|
221
|
+
'sample_endpoints' => JsonCoercion.new,
|
|
222
|
+
'sample_jobs' => JsonCoercion.new,
|
|
223
|
+
'endpoint_sample_rate' => NullableIntegerCoercion.new,
|
|
224
|
+
'job_sample_rate' => NullableIntegerCoercion.new,
|
|
197
225
|
'start_resque_server_instrument' => BooleanCoercion.new,
|
|
198
226
|
'timeline_traces' => BooleanCoercion.new,
|
|
199
227
|
'auto_instruments' => BooleanCoercion.new,
|
|
@@ -290,41 +318,48 @@ module ScoutApm
|
|
|
290
318
|
|
|
291
319
|
class ConfigDefaults
|
|
292
320
|
DEFAULTS = {
|
|
293
|
-
'compress_payload'
|
|
294
|
-
'detailed_middleware'
|
|
295
|
-
'dev_trace'
|
|
296
|
-
'direct_host'
|
|
297
|
-
'disabled_instruments'
|
|
298
|
-
'enable_background_jobs'
|
|
299
|
-
'host'
|
|
300
|
-
'ignore'
|
|
301
|
-
'
|
|
302
|
-
'
|
|
303
|
-
'
|
|
304
|
-
'
|
|
305
|
-
'
|
|
306
|
-
'
|
|
307
|
-
'
|
|
308
|
-
'
|
|
309
|
-
'
|
|
310
|
-
'
|
|
311
|
-
'
|
|
321
|
+
'compress_payload' => true,
|
|
322
|
+
'detailed_middleware' => false,
|
|
323
|
+
'dev_trace' => false,
|
|
324
|
+
'direct_host' => 'https://apm.scoutapp.com',
|
|
325
|
+
'disabled_instruments' => [],
|
|
326
|
+
'enable_background_jobs' => true,
|
|
327
|
+
'host' => 'https://checkin.scoutapp.com',
|
|
328
|
+
'ignore' => [],
|
|
329
|
+
'ignore_endpoints' => [],
|
|
330
|
+
'ignore_jobs' => [],
|
|
331
|
+
'log_level' => 'info',
|
|
332
|
+
'max_traces' => 10,
|
|
333
|
+
'profile' => true, # for scoutprof
|
|
334
|
+
'report_format' => 'json',
|
|
335
|
+
'scm_subdirectory' => '',
|
|
336
|
+
'uri_reporting' => 'full_path',
|
|
337
|
+
'remote_agent_host' => '127.0.0.1',
|
|
338
|
+
'remote_agent_port' => 7721, # picked at random
|
|
339
|
+
'database_metric_limit' => 5000, # The hard limit on db metrics
|
|
340
|
+
'database_metric_report_limit' => 1000,
|
|
341
|
+
'external_service_metric_limit' => 5000, # The hard limit on external service metrics
|
|
312
342
|
'external_service_metric_report_limit' => 1000,
|
|
313
|
-
'instrument_http_url_length'
|
|
314
|
-
'
|
|
315
|
-
'
|
|
316
|
-
'
|
|
317
|
-
'
|
|
318
|
-
'
|
|
319
|
-
'
|
|
320
|
-
'
|
|
321
|
-
'
|
|
322
|
-
'
|
|
323
|
-
'
|
|
324
|
-
'
|
|
325
|
-
'
|
|
326
|
-
'
|
|
327
|
-
'
|
|
343
|
+
'instrument_http_url_length' => 300,
|
|
344
|
+
'sample_rate' => 100,
|
|
345
|
+
'sample_endpoints' => [],
|
|
346
|
+
'sample_jobs' => [],
|
|
347
|
+
'endpoint_sample_rate' => nil,
|
|
348
|
+
'job_sample_rate' => nil,
|
|
349
|
+
'start_resque_server_instrument' => true, # still only starts if Resque is detected
|
|
350
|
+
'collect_remote_ip' => true,
|
|
351
|
+
'record_queue_time' => true,
|
|
352
|
+
'timeline_traces' => true,
|
|
353
|
+
'auto_instruments' => false,
|
|
354
|
+
'auto_instruments_ignore' => [],
|
|
355
|
+
'use_prepend' => false,
|
|
356
|
+
'alias_method_instruments' => [],
|
|
357
|
+
'prepend_instruments' => [],
|
|
358
|
+
'ssl_cert_file' => File.join( File.dirname(__FILE__), *%w[.. .. data cacert.pem] ),
|
|
359
|
+
'errors_enabled' => false,
|
|
360
|
+
'errors_ignored_exceptions' => %w(ActiveRecord::RecordNotFound ActionController::RoutingError),
|
|
361
|
+
'errors_filtered_params' => %w(password s3-key),
|
|
362
|
+
'errors_host' => 'https://errors.scoutapm.com',
|
|
328
363
|
}.freeze
|
|
329
364
|
|
|
330
365
|
def value(key)
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
module ScoutApm
|
|
2
|
+
class Sampling
|
|
3
|
+
attr_reader :global_sample_rate, :sample_endpoints, :sample_uri_regex, :sample_jobs, :ignore_uri_regex, :ignore_jobs
|
|
4
|
+
|
|
5
|
+
def initialize(config)
|
|
6
|
+
@global_sample_rate = config.value('sample_rate')
|
|
7
|
+
# web endpoints matched prefix by regex
|
|
8
|
+
# jobs matched explicitly by name
|
|
9
|
+
|
|
10
|
+
# for now still support old config key ('ignore') for backwards compatibility
|
|
11
|
+
@ignore_endpoints = config.value('ignore').present? ? config.value('ignore') : config.value('ignore_endpoints')
|
|
12
|
+
@sample_endpoints = individual_sample_to_hash(config.value('sample_endpoints'))
|
|
13
|
+
@endpoint_sample_rate = config.value('endpoint_sample_rate')
|
|
14
|
+
|
|
15
|
+
@ignore_jobs = config.value('ignore_jobs')
|
|
16
|
+
@sample_jobs = individual_sample_to_hash(config.value('sample_jobs'))
|
|
17
|
+
@job_sample_rate = config.value('job_sample_rate')
|
|
18
|
+
|
|
19
|
+
log_string = "Sampling initialized with config: "
|
|
20
|
+
log_string += "global_sample_rate: #{@global_sample_rate.inspect}, "
|
|
21
|
+
log_string += "endpoint_sample_rate: #{@endpoint_sample_rate.inspect}, "
|
|
22
|
+
log_string += "sample_endpoints: #{@sample_endpoints.inspect}, "
|
|
23
|
+
log_string += "ignore_endpoints: #{@ignore_endpoints.inspect}, "
|
|
24
|
+
log_string += "job_sample_rate: #{@job_sample_rate.inspect}, "
|
|
25
|
+
log_string += "sample_jobs: #{@sample_jobs.inspect}, "
|
|
26
|
+
log_string += "ignore_jobs: #{@ignore_jobs.inspect}"
|
|
27
|
+
logger.info(log_string)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def drop_request?(transaction)
|
|
31
|
+
# Individual endpoint/job sampling takes precedence over ignoring.
|
|
32
|
+
# Individual endpoint/job sample rate always takes precedence over general endpoint/job rate.
|
|
33
|
+
# General endpoint/job rate always takes precedence over global sample rate
|
|
34
|
+
if transaction.job?
|
|
35
|
+
job_name = transaction.layer_finder.job.name
|
|
36
|
+
rate = job_sample_rate(job_name)
|
|
37
|
+
return sample?(rate) unless rate.nil?
|
|
38
|
+
return true if ignore_job?(job_name)
|
|
39
|
+
return sample?(@job_sample_rate) unless @job_sample_rate.nil?
|
|
40
|
+
elsif transaction.web?
|
|
41
|
+
uri = transaction.annotations[:uri]
|
|
42
|
+
rate = web_sample_rate(uri)
|
|
43
|
+
return sample?(rate) unless rate.nil?
|
|
44
|
+
return true if ignore_uri?(uri)
|
|
45
|
+
return sample?(@endpoint_sample_rate) unless @endpoint_sample_rate.nil?
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# global sample check
|
|
49
|
+
if @global_sample_rate
|
|
50
|
+
return sample?(@global_sample_rate)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
false # don't drop the request
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def individual_sample_to_hash(sampling_config)
|
|
57
|
+
return nil if sampling_config.blank?
|
|
58
|
+
# config looks like ['/foo:50','/bar:100']. parse it into hash of string: integer
|
|
59
|
+
sample_hash = {}
|
|
60
|
+
sampling_config.each do |sample|
|
|
61
|
+
path, rate = sample.split(':')
|
|
62
|
+
sample_hash[path] = rate.to_i
|
|
63
|
+
end
|
|
64
|
+
sample_hash
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def ignore_uri?(uri)
|
|
68
|
+
return false if @ignore_endpoints.blank?
|
|
69
|
+
@ignore_endpoints.each do |prefix|
|
|
70
|
+
return true if uri.start_with?(prefix)
|
|
71
|
+
end
|
|
72
|
+
false
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def web_sample_rate(uri)
|
|
76
|
+
return nil if @sample_endpoints.blank?
|
|
77
|
+
@sample_endpoints.each do |prefix, rate|
|
|
78
|
+
return rate if uri.start_with?(prefix)
|
|
79
|
+
end
|
|
80
|
+
nil
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def ignore_job?(job_name)
|
|
84
|
+
return false if @ignore_jobs.blank?
|
|
85
|
+
@ignore_jobs.include?(job_name)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def job_sample_rate(job_name)
|
|
89
|
+
return nil if @sample_jobs.blank?
|
|
90
|
+
@sample_jobs.fetch(job_name, nil)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def sample?(rate)
|
|
94
|
+
rand * 100 > rate
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
private
|
|
98
|
+
|
|
99
|
+
def logger
|
|
100
|
+
ScoutApm::Agent.instance.logger
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
end
|
|
104
|
+
end
|
|
@@ -303,7 +303,11 @@ module ScoutApm
|
|
|
303
303
|
restore_from_dump! if @agent_context.nil?
|
|
304
304
|
|
|
305
305
|
# Bail out early if the user asked us to ignore this uri
|
|
306
|
-
return if @agent_context.ignored_uris.ignore?(annotations[:uri])
|
|
306
|
+
# return if @agent_context.ignored_uris.ignore?(annotations[:uri])
|
|
307
|
+
if @agent_context.sampling.drop_request?(self)
|
|
308
|
+
logger.debug("Dropping request due to sampling")
|
|
309
|
+
return
|
|
310
|
+
end
|
|
307
311
|
|
|
308
312
|
apply_name_override
|
|
309
313
|
|
data/lib/scout_apm/version.rb
CHANGED
data/lib/scout_apm.rb
CHANGED
|
@@ -111,6 +111,7 @@ require 'scout_apm/instruments/samplers'
|
|
|
111
111
|
require 'scout_apm/app_server_load'
|
|
112
112
|
|
|
113
113
|
require 'scout_apm/ignored_uris.rb'
|
|
114
|
+
require 'scout_apm/sampling.rb'
|
|
114
115
|
require 'scout_apm/utils/active_record_metric_name'
|
|
115
116
|
require 'scout_apm/utils/backtrace_parser'
|
|
116
117
|
require 'scout_apm/utils/installed_gems'
|
data/test/test_helper.rb
CHANGED
|
@@ -38,6 +38,10 @@ class FakeConfigOverlay
|
|
|
38
38
|
@values[key]
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
+
def values
|
|
42
|
+
@values
|
|
43
|
+
end
|
|
44
|
+
|
|
41
45
|
def has_key?(key)
|
|
42
46
|
@values.has_key?(key)
|
|
43
47
|
end
|
|
@@ -169,3 +173,28 @@ end
|
|
|
169
173
|
class Minitest::Test
|
|
170
174
|
include CustomAsserts
|
|
171
175
|
end
|
|
176
|
+
|
|
177
|
+
class FakeTrackedRequest
|
|
178
|
+
def self.new_web_request(uri)
|
|
179
|
+
context = ScoutApm::Agent.instance.context
|
|
180
|
+
fake_store = ScoutApm::FakeStore.new
|
|
181
|
+
req = ScoutApm::TrackedRequest.new(context, fake_store)
|
|
182
|
+
|
|
183
|
+
first_layer = ScoutApm::Layer.new("Controller", "index")
|
|
184
|
+
req.start_layer(first_layer)
|
|
185
|
+
req.annotate_request(:uri => uri)
|
|
186
|
+
|
|
187
|
+
req
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def self.new_job_request(job_name)
|
|
191
|
+
context = ScoutApm::Agent.instance.context
|
|
192
|
+
fake_store = ScoutApm::FakeStore.new
|
|
193
|
+
req = ScoutApm::TrackedRequest.new(context, fake_store)
|
|
194
|
+
|
|
195
|
+
first_layer = ScoutApm::Layer.new("Job", job_name)
|
|
196
|
+
req.start_layer(first_layer)
|
|
197
|
+
|
|
198
|
+
req
|
|
199
|
+
end
|
|
200
|
+
end
|
data/test/unit/config_test.rb
CHANGED
|
@@ -72,6 +72,26 @@ class ConfigTest < Minitest::Test
|
|
|
72
72
|
assert_equal ["a"], coercion.coerce(["a"])
|
|
73
73
|
end
|
|
74
74
|
|
|
75
|
+
def test_integer_coercion
|
|
76
|
+
coercion = ScoutApm::Config::IntegerCoercion.new
|
|
77
|
+
assert_equal 1, coercion.coerce("1")
|
|
78
|
+
assert_equal 1, coercion.coerce(1)
|
|
79
|
+
assert_equal 0, coercion.coerce("0")
|
|
80
|
+
assert_equal 0, coercion.coerce(0)
|
|
81
|
+
assert_equal 0, coercion.coerce("")
|
|
82
|
+
assert_equal 0, coercion.coerce(nil)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def test_nullable_integer_coercion
|
|
86
|
+
coercion = ScoutApm::Config::NullableIntegerCoercion.new
|
|
87
|
+
assert_equal 1, coercion.coerce("1")
|
|
88
|
+
assert_equal 1, coercion.coerce(1)
|
|
89
|
+
assert_equal 0, coercion.coerce("0")
|
|
90
|
+
assert_equal 0, coercion.coerce(0)
|
|
91
|
+
assert_equal 0, coercion.coerce("")
|
|
92
|
+
assert_equal nil, coercion.coerce(nil)
|
|
93
|
+
end
|
|
94
|
+
|
|
75
95
|
def test_any_keys_found
|
|
76
96
|
ENV.stubs(:has_key?).returns(nil)
|
|
77
97
|
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
|
|
3
|
+
require 'scout_apm/sampling'
|
|
4
|
+
|
|
5
|
+
class SamplingTest < Minitest::Test
|
|
6
|
+
|
|
7
|
+
def setup
|
|
8
|
+
@global_sample_config = FakeConfigOverlay.new(
|
|
9
|
+
{
|
|
10
|
+
'sample_rate' => 80,
|
|
11
|
+
}
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
@individual_config = FakeConfigOverlay.new(
|
|
15
|
+
{
|
|
16
|
+
'sample_endpoints' => ['/foo/bar:100', '/foo:50', '/bar/zap:80'],
|
|
17
|
+
'ignore_endpoints' => ['/baz'],
|
|
18
|
+
'sample_jobs' => ['joba:50'],
|
|
19
|
+
'ignore_jobs' => 'jobb,jobc',
|
|
20
|
+
}
|
|
21
|
+
)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def test_individual_sample_to_hash
|
|
25
|
+
sampling = ScoutApm::Sampling.new(@individual_config)
|
|
26
|
+
assert_equal({'/foo/bar' => 100, '/foo' => 50, '/bar/zap' => 80}, sampling.individual_sample_to_hash(@individual_config.value('sample_endpoints')))
|
|
27
|
+
|
|
28
|
+
sampling = ScoutApm::Sampling.new(@global_sample_config)
|
|
29
|
+
assert_equal nil, sampling.individual_sample_to_hash(@global_sample_config.value('sample_endpoints'))
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def test_uri_ignore
|
|
33
|
+
sampling = ScoutApm::Sampling.new(@individual_config)
|
|
34
|
+
assert_equal true, sampling.ignore_uri?('/baz/bap')
|
|
35
|
+
assert_equal false, sampling.ignore_uri?('/foo/far')
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def test_uri_sample
|
|
39
|
+
sampling = ScoutApm::Sampling.new(@individual_config)
|
|
40
|
+
rate = sampling.web_sample_rate('/foo/far')
|
|
41
|
+
assert_equal 50, rate
|
|
42
|
+
|
|
43
|
+
rate = sampling.web_sample_rate('/bar')
|
|
44
|
+
assert_equal nil, rate
|
|
45
|
+
|
|
46
|
+
rate = sampling.web_sample_rate('/baz/bap')
|
|
47
|
+
assert_equal nil, rate
|
|
48
|
+
|
|
49
|
+
rate = sampling.web_sample_rate('/foo/bar/baz')
|
|
50
|
+
assert_equal 100, rate
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def test_job_ignore
|
|
54
|
+
sampling = ScoutApm::Sampling.new(@individual_config)
|
|
55
|
+
assert_equal true, sampling.ignore_job?('jobb')
|
|
56
|
+
assert_equal false, sampling.ignore_job?('joba')
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def test_job_sample
|
|
60
|
+
sampling = ScoutApm::Sampling.new(@individual_config)
|
|
61
|
+
assert_equal 50, sampling.job_sample_rate('joba')
|
|
62
|
+
assert_equal nil, sampling.job_sample_rate('jobb')
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def test_sample
|
|
66
|
+
sampling = ScoutApm::Sampling.new(@individual_config)
|
|
67
|
+
sampling.stub(:rand, 0.01) do
|
|
68
|
+
assert_equal(false, sampling.sample?(50))
|
|
69
|
+
end
|
|
70
|
+
sampling.stub(:rand, 0.99) do
|
|
71
|
+
assert_equal(true, sampling.sample?(50))
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def test_old_ignore
|
|
76
|
+
config = FakeConfigOverlay.new({'ignore' => ['/foo', '/bar']})
|
|
77
|
+
sampling = ScoutApm::Sampling.new(config)
|
|
78
|
+
assert_equal true, sampling.ignore_uri?('/foo')
|
|
79
|
+
assert_equal true, sampling.ignore_uri?('/bar/bap')
|
|
80
|
+
assert_equal false, sampling.ignore_uri?('/baz')
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def test_web_request_individual_sampling
|
|
84
|
+
sampling = ScoutApm::Sampling.new(@individual_config)
|
|
85
|
+
|
|
86
|
+
# should be ignored
|
|
87
|
+
transaction = FakeTrackedRequest.new_web_request('/baz/bap')
|
|
88
|
+
assert_equal true, sampling.drop_request?(transaction)
|
|
89
|
+
|
|
90
|
+
# should be kept
|
|
91
|
+
transaction = FakeTrackedRequest.new_web_request('/faz/bap')
|
|
92
|
+
assert_equal false, sampling.drop_request?(transaction)
|
|
93
|
+
|
|
94
|
+
transaction = FakeTrackedRequest.new_web_request('/foo/far')
|
|
95
|
+
sampling.stub(:rand, 0.01) do
|
|
96
|
+
assert_equal false, sampling.drop_request?(transaction)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# passes individual sample but caught by global rate
|
|
100
|
+
sampling.stub(:rand, 0.99) do
|
|
101
|
+
assert_equal true, sampling.drop_request?(transaction)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def test_web_reqeust_general_sampling
|
|
106
|
+
config = FakeConfigOverlay.new(@individual_config.values.merge({'endpoint_sample_rate' => 80}))
|
|
107
|
+
sampling = ScoutApm::Sampling.new(config)
|
|
108
|
+
|
|
109
|
+
transaction = FakeTrackedRequest.new_web_request('/foo/far')
|
|
110
|
+
transaction2 = FakeTrackedRequest.new_web_request('/ooo/oar')
|
|
111
|
+
# /foo/far sampled at 50 specifically, /ooo/oar caught by general endpoint rate of 80
|
|
112
|
+
sampling.stub(:rand, 0.01) do
|
|
113
|
+
assert_equal false, sampling.drop_request?(transaction)
|
|
114
|
+
assert_equal false, sampling.drop_request?(transaction2)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
sampling.stub(:rand, 0.70) do
|
|
118
|
+
assert_equal true, sampling.drop_request?(transaction)
|
|
119
|
+
assert_equal false, sampling.drop_request?(transaction2)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
sampling.stub(:rand, 0.99) do
|
|
123
|
+
assert_equal true, sampling.drop_request?(transaction)
|
|
124
|
+
assert_equal true, sampling.drop_request?(transaction2)
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def test_web_request_with_global_sampling
|
|
129
|
+
config = FakeConfigOverlay.new(@individual_config.values.merge({'sample_rate' => 20}))
|
|
130
|
+
sampling = ScoutApm::Sampling.new(config)
|
|
131
|
+
|
|
132
|
+
# caught by individual rate
|
|
133
|
+
transaction = FakeTrackedRequest.new_web_request('/foo/far')
|
|
134
|
+
sampling.stub(:rand, 0.01) do
|
|
135
|
+
assert_equal false, sampling.drop_request?(transaction)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# passes individual rate (50) but caught by global rate (20)
|
|
139
|
+
sampling.stub(:rand, 0.30) do
|
|
140
|
+
assert_equal false, sampling.drop_request?(transaction)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# passes individual rate
|
|
144
|
+
sampling.stub(:rand, 0.99) do
|
|
145
|
+
assert_equal true, sampling.drop_request?(transaction)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def test_job_request_individual_sampling
|
|
151
|
+
sampling = ScoutApm::Sampling.new(@individual_config)
|
|
152
|
+
|
|
153
|
+
# should be ignored
|
|
154
|
+
transaction = FakeTrackedRequest.new_job_request('jobb')
|
|
155
|
+
assert_equal true, sampling.drop_request?(transaction)
|
|
156
|
+
|
|
157
|
+
# should be kept
|
|
158
|
+
transaction = FakeTrackedRequest.new_job_request('jobz')
|
|
159
|
+
assert_equal false, sampling.drop_request?(transaction)
|
|
160
|
+
|
|
161
|
+
# should be sampled if rand > 50
|
|
162
|
+
transaction = FakeTrackedRequest.new_job_request('joba')
|
|
163
|
+
sampling.stub(:rand, 0.01) do
|
|
164
|
+
assert_equal false, sampling.drop_request?(transaction)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
sampling.stub(:rand, 0.99) do
|
|
168
|
+
assert_equal true, sampling.drop_request?(transaction)
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def test_job_general_sampling
|
|
173
|
+
config = FakeConfigOverlay.new(@individual_config.values.merge({'job_sample_rate' => 80}))
|
|
174
|
+
sampling = ScoutApm::Sampling.new(config)
|
|
175
|
+
|
|
176
|
+
transaction = FakeTrackedRequest.new_job_request('joba')
|
|
177
|
+
transaction2 = FakeTrackedRequest.new_job_request('jobz')
|
|
178
|
+
# joba sampled at 50 specifically, jobz caught by general job rate of 80
|
|
179
|
+
sampling.stub(:rand, 0.01) do
|
|
180
|
+
assert_equal false, sampling.drop_request?(transaction)
|
|
181
|
+
assert_equal false, sampling.drop_request?(transaction2)
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
sampling.stub(:rand, 0.70) do
|
|
185
|
+
assert_equal true, sampling.drop_request?(transaction)
|
|
186
|
+
assert_equal false, sampling.drop_request?(transaction2)
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
sampling.stub(:rand, 0.99) do
|
|
190
|
+
assert_equal true, sampling.drop_request?(transaction)
|
|
191
|
+
assert_equal true, sampling.drop_request?(transaction2)
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def test_job_request_global_sampling
|
|
196
|
+
config = FakeConfigOverlay.new(@individual_config.values.merge({'sample_rate' => 20}))
|
|
197
|
+
sampling = ScoutApm::Sampling.new(config)
|
|
198
|
+
|
|
199
|
+
# caught by individual rate
|
|
200
|
+
transaction = FakeTrackedRequest.new_job_request('joba')
|
|
201
|
+
sampling.stub(:rand, 0.01) do
|
|
202
|
+
assert_equal false, sampling.drop_request?(transaction)
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# passes individual rate (50) but caught by global rate (20)
|
|
206
|
+
sampling.stub(:rand, 0.30) do
|
|
207
|
+
assert_equal false, sampling.drop_request?(transaction)
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
# passes individual rate
|
|
211
|
+
sampling.stub(:rand, 0.99) do
|
|
212
|
+
assert_equal true, sampling.drop_request?(transaction)
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: scout_apm
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.
|
|
4
|
+
version: 5.6.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Derek Haynes
|
|
8
8
|
- Andre Lewis
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-
|
|
11
|
+
date: 2025-02-21 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: minitest
|
|
@@ -365,6 +365,7 @@ files:
|
|
|
365
365
|
- lib/scout_apm/reporting.rb
|
|
366
366
|
- lib/scout_apm/request_histograms.rb
|
|
367
367
|
- lib/scout_apm/request_manager.rb
|
|
368
|
+
- lib/scout_apm/sampling.rb
|
|
368
369
|
- lib/scout_apm/scored_item_set.rb
|
|
369
370
|
- lib/scout_apm/serializers/app_server_load_serializer.rb
|
|
370
371
|
- lib/scout_apm/serializers/db_query_serializer_to_json.rb
|
|
@@ -471,6 +472,7 @@ files:
|
|
|
471
472
|
- test/unit/remote/route_test.rb
|
|
472
473
|
- test/unit/remote/server_test.rb
|
|
473
474
|
- test/unit/request_histograms_test.rb
|
|
475
|
+
- test/unit/sampling_test.rb
|
|
474
476
|
- test/unit/scored_item_set_test.rb
|
|
475
477
|
- test/unit/serializers/payload_serializer_test.rb
|
|
476
478
|
- test/unit/slow_request_policy_test.rb
|