scout_apm 5.5.0 → 5.6.0
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 +10 -0
- data/lib/scout_apm/agent_context.rb +4 -0
- data/lib/scout_apm/config.rb +62 -34
- data/lib/scout_apm/sampling.rb +96 -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/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: 46df05a2d67c23f243d1eedfddd2eabdd8a6151ef8974e185ea7c8efbe01d076
|
4
|
+
data.tar.gz: 072bcd67b72f477c924dd647f2e3f87e586f3a97ff8dbbd727d5f5991c060f54
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 31ab64b2f5a212322989d118edba3f92cb4c4a223618bebd7f4fae318ebb243459dcd730388a080d7e7d6e0ce1147af857bb656f67bdeda902878e167f195f90
|
7
|
+
data.tar.gz: 9191e3bf53423a7db1e9c0265a6b8cf03eb7bce0374ed392c137ab1c592dffee312c8efe8e6301e3a0fad17e033429af4c0b98b7608438be44251682236874d6
|
data/CHANGELOG.markdown
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
# Unreleased
|
2
2
|
|
3
|
+
# 5.6.0
|
4
|
+
- New options for sampling and ignore configurationn (#521)
|
5
|
+
- `sample_rate` - Set the rate at which requests are sampled globally (1-100, a percentage of requests to keep).
|
6
|
+
- `ignore_endpoints` - Ignore endpoints by regex matching prefix (Same as and replaces `ignore`)
|
7
|
+
- `sample_endpoints` - Sample endpoints by regex matching prefix (i.e. ['/foo:70']).
|
8
|
+
- `endpoint_sample_rate` - Set the rate at which all non-matching web requests are sampled.
|
9
|
+
- `ignore_jobs` - Ignore Jobs by explicit name match.
|
10
|
+
- `sample_jobs` - Sample Jobs by explicit name match (i.e. ['MyJob:70']).
|
11
|
+
- `job_sample_rate` - Set the rate at which all non-matching background jobs are sampled.
|
12
|
+
|
3
13
|
# 5.5.0
|
4
14
|
- Fix undeclared logger in grape instruments (#510)
|
5
15
|
- 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',
|
@@ -184,6 +198,8 @@ module ScoutApm
|
|
184
198
|
'dev_trace' => BooleanCoercion.new,
|
185
199
|
'enable_background_jobs' => BooleanCoercion.new,
|
186
200
|
'ignore' => JsonCoercion.new,
|
201
|
+
'ignore_endpoints' => JsonCoercion.new,
|
202
|
+
'ignore_jobs' => JsonCoercion.new,
|
187
203
|
'max_traces' => IntegerCoercion.new,
|
188
204
|
'monitor' => BooleanCoercion.new,
|
189
205
|
'collect_remote_ip' => BooleanCoercion.new,
|
@@ -194,6 +210,11 @@ module ScoutApm
|
|
194
210
|
'external_service_metric_report_limit' => IntegerCoercion.new,
|
195
211
|
'instrument_http_url_length' => IntegerCoercion.new,
|
196
212
|
'record_queue_time' => BooleanCoercion.new,
|
213
|
+
'sample_rate' => IntegerCoercion.new,
|
214
|
+
'sample_endpoints' => JsonCoercion.new,
|
215
|
+
'sample_jobs' => JsonCoercion.new,
|
216
|
+
'endpoint_sample_rate' => IntegerCoercion.new,
|
217
|
+
'job_sample_rate' => IntegerCoercion.new,
|
197
218
|
'start_resque_server_instrument' => BooleanCoercion.new,
|
198
219
|
'timeline_traces' => BooleanCoercion.new,
|
199
220
|
'auto_instruments' => BooleanCoercion.new,
|
@@ -290,41 +311,48 @@ module ScoutApm
|
|
290
311
|
|
291
312
|
class ConfigDefaults
|
292
313
|
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
|
-
'
|
314
|
+
'compress_payload' => true,
|
315
|
+
'detailed_middleware' => false,
|
316
|
+
'dev_trace' => false,
|
317
|
+
'direct_host' => 'https://apm.scoutapp.com',
|
318
|
+
'disabled_instruments' => [],
|
319
|
+
'enable_background_jobs' => true,
|
320
|
+
'host' => 'https://checkin.scoutapp.com',
|
321
|
+
'ignore' => [],
|
322
|
+
'ignore_endpoints' => [],
|
323
|
+
'ignore_jobs' => [],
|
324
|
+
'log_level' => 'info',
|
325
|
+
'max_traces' => 10,
|
326
|
+
'profile' => true, # for scoutprof
|
327
|
+
'report_format' => 'json',
|
328
|
+
'scm_subdirectory' => '',
|
329
|
+
'uri_reporting' => 'full_path',
|
330
|
+
'remote_agent_host' => '127.0.0.1',
|
331
|
+
'remote_agent_port' => 7721, # picked at random
|
332
|
+
'database_metric_limit' => 5000, # The hard limit on db metrics
|
333
|
+
'database_metric_report_limit' => 1000,
|
334
|
+
'external_service_metric_limit' => 5000, # The hard limit on external service metrics
|
312
335
|
'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
|
-
'
|
336
|
+
'instrument_http_url_length' => 300,
|
337
|
+
'sample_rate' => 100,
|
338
|
+
'sample_endpoints' => [],
|
339
|
+
'sample_jobs' => [],
|
340
|
+
'endpoint_sample_rate' => 100,
|
341
|
+
'job_sample_rate' => 100,
|
342
|
+
'start_resque_server_instrument' => true, # still only starts if Resque is detected
|
343
|
+
'collect_remote_ip' => true,
|
344
|
+
'record_queue_time' => true,
|
345
|
+
'timeline_traces' => true,
|
346
|
+
'auto_instruments' => false,
|
347
|
+
'auto_instruments_ignore' => [],
|
348
|
+
'use_prepend' => false,
|
349
|
+
'alias_method_instruments' => [],
|
350
|
+
'prepend_instruments' => [],
|
351
|
+
'ssl_cert_file' => File.join( File.dirname(__FILE__), *%w[.. .. data cacert.pem] ),
|
352
|
+
'errors_enabled' => false,
|
353
|
+
'errors_ignored_exceptions' => %w(ActiveRecord::RecordNotFound ActionController::RoutingError),
|
354
|
+
'errors_filtered_params' => %w(password s3-key),
|
355
|
+
'errors_host' => 'https://errors.scoutapm.com',
|
328
356
|
}.freeze
|
329
357
|
|
330
358
|
def value(key)
|
@@ -0,0 +1,96 @@
|
|
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
|
+
logger.info("Sampling initialized with config: global_sample_rate: #{@global_sample_rate}, endpoint_sample_rate: #{@endpoint_sample_rate}, sample_endpoints: #{@sample_endpoints}, ignore_endpoints: #{@ignore_endpoints}, job_sample_rate: #@job_sample_rate}, sample_jobs: #{@sample_jobs}, ignore_jobs: #{@ignore_jobs}")
|
20
|
+
end
|
21
|
+
|
22
|
+
def drop_request?(transaction)
|
23
|
+
# Individual endpoint/job sampling takes precedence over ignoring.
|
24
|
+
# Individual endpoint/job sample rate always takes precedence over general endpoint/job rate.
|
25
|
+
# General endpoint/job rate always takes precedence over global sample rate
|
26
|
+
if transaction.job?
|
27
|
+
job_name = transaction.layer_finder.job.name
|
28
|
+
rate = job_sample_rate(job_name)
|
29
|
+
return sample?(rate) unless rate.nil?
|
30
|
+
return true if ignore_job?(job_name)
|
31
|
+
return sample?(@job_sample_rate) unless @job_sample_rate.nil?
|
32
|
+
elsif transaction.web?
|
33
|
+
uri = transaction.annotations[:uri]
|
34
|
+
rate = web_sample_rate(uri)
|
35
|
+
return sample?(rate) unless rate.nil?
|
36
|
+
return true if ignore_uri?(uri)
|
37
|
+
return sample?(@endpoint_sample_rate) unless @endpoint_sample_rate.nil?
|
38
|
+
end
|
39
|
+
|
40
|
+
# global sample check
|
41
|
+
if @global_sample_rate
|
42
|
+
return sample?(@global_sample_rate)
|
43
|
+
end
|
44
|
+
|
45
|
+
false # don't drop the request
|
46
|
+
end
|
47
|
+
|
48
|
+
def individual_sample_to_hash(sampling_config)
|
49
|
+
return nil if sampling_config.blank?
|
50
|
+
# config looks like ['/foo:50','/bar:100']. parse it into hash of string: integer
|
51
|
+
sample_hash = {}
|
52
|
+
sampling_config.each do |sample|
|
53
|
+
path, rate = sample.split(':')
|
54
|
+
sample_hash[path] = rate.to_i
|
55
|
+
end
|
56
|
+
sample_hash
|
57
|
+
end
|
58
|
+
|
59
|
+
def ignore_uri?(uri)
|
60
|
+
return false if @ignore_endpoints.blank?
|
61
|
+
@ignore_endpoints.each do |prefix|
|
62
|
+
return true if uri.start_with?(prefix)
|
63
|
+
end
|
64
|
+
false
|
65
|
+
end
|
66
|
+
|
67
|
+
def web_sample_rate(uri)
|
68
|
+
return nil if @sample_endpoints.blank?
|
69
|
+
@sample_endpoints.each do |prefix, rate|
|
70
|
+
return rate if uri.start_with?(prefix)
|
71
|
+
end
|
72
|
+
nil
|
73
|
+
end
|
74
|
+
|
75
|
+
def ignore_job?(job_name)
|
76
|
+
return false if @ignore_jobs.blank?
|
77
|
+
@ignore_jobs.include?(job_name)
|
78
|
+
end
|
79
|
+
|
80
|
+
def job_sample_rate(job_name)
|
81
|
+
return nil if @sample_jobs.blank?
|
82
|
+
@sample_jobs.fetch(job_name, nil)
|
83
|
+
end
|
84
|
+
|
85
|
+
def sample?(rate)
|
86
|
+
rand * 100 > rate
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def logger
|
92
|
+
ScoutApm::Agent.instance.logger
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
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
|
@@ -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.0
|
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-01-
|
11
|
+
date: 2025-01-15 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
|