scout_apm 2.1.32 → 2.2.0.pre0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -1
- data/CHANGELOG.markdown +2 -161
- data/Rakefile +2 -2
- data/ext/allocations/allocations.c +0 -6
- data/ext/allocations/extconf.rb +0 -1
- data/ext/stacks/extconf.rb +33 -0
- data/ext/stacks/scout_atomics.h +86 -0
- data/ext/stacks/stacks.c +744 -0
- data/lib/scout_apm.rb +16 -24
- data/lib/scout_apm/agent.rb +38 -93
- data/lib/scout_apm/agent/logging.rb +1 -6
- data/lib/scout_apm/agent/reporting.rb +6 -8
- data/lib/scout_apm/app_server_load.rb +10 -21
- data/lib/scout_apm/attribute_arranger.rb +2 -0
- data/lib/scout_apm/background_job_integrations/delayed_job.rb +1 -71
- data/lib/scout_apm/background_job_integrations/sidekiq.rb +27 -66
- data/lib/scout_apm/background_worker.rb +15 -19
- data/lib/scout_apm/capacity.rb +57 -0
- data/lib/scout_apm/config.rb +29 -135
- data/lib/scout_apm/context.rb +5 -9
- data/lib/scout_apm/deploy_integrations/capistrano_2.cap +12 -0
- data/lib/scout_apm/deploy_integrations/capistrano_2.rb +83 -0
- data/lib/scout_apm/deploy_integrations/capistrano_3.cap +12 -0
- data/lib/scout_apm/deploy_integrations/capistrano_3.rb +88 -0
- data/lib/scout_apm/environment.rb +15 -22
- data/lib/scout_apm/histogram.rb +2 -11
- data/lib/scout_apm/instant/assets/xmlhttp_instrumentation.html +2 -2
- data/lib/scout_apm/instant/middleware.rb +57 -198
- data/lib/scout_apm/instruments/action_controller_rails_2.rb +2 -1
- data/lib/scout_apm/instruments/action_controller_rails_3_rails4.rb +59 -90
- data/lib/scout_apm/instruments/active_record.rb +5 -7
- data/lib/scout_apm/instruments/delayed_job.rb +57 -0
- data/lib/scout_apm/instruments/grape.rb +3 -4
- data/lib/scout_apm/instruments/middleware_detailed.rb +6 -4
- data/lib/scout_apm/instruments/middleware_summary.rb +1 -39
- data/lib/scout_apm/instruments/mongoid.rb +3 -24
- data/lib/scout_apm/instruments/net_http.rb +2 -7
- data/lib/scout_apm/instruments/percentile_sampler.rb +19 -36
- data/lib/scout_apm/instruments/process/process_cpu.rb +2 -3
- data/lib/scout_apm/instruments/process/process_memory.rb +3 -3
- data/lib/scout_apm/layaway.rb +33 -76
- data/lib/scout_apm/layer.rb +59 -16
- data/lib/scout_apm/layer_converters/converter_base.rb +0 -199
- data/lib/scout_apm/layer_converters/job_converter.rb +1 -1
- data/lib/scout_apm/layer_converters/metric_converter.rb +1 -1
- data/lib/scout_apm/layer_converters/slow_job_converter.rb +90 -15
- data/lib/scout_apm/layer_converters/slow_request_converter.rb +101 -13
- data/lib/scout_apm/metric_set.rb +1 -9
- data/lib/scout_apm/metric_stats.rb +8 -8
- data/lib/scout_apm/reporter.rb +15 -51
- data/lib/scout_apm/request_histograms.rb +0 -4
- data/lib/scout_apm/request_manager.rb +1 -2
- data/lib/scout_apm/scored_item_set.rb +0 -7
- data/lib/scout_apm/serializers/deploy_serializer.rb +16 -0
- data/lib/scout_apm/serializers/payload_serializer.rb +3 -9
- data/lib/scout_apm/serializers/payload_serializer_to_json.rb +5 -2
- data/lib/scout_apm/serializers/slow_jobs_serializer_to_json.rb +1 -2
- data/lib/scout_apm/server_integrations/puma.rb +2 -5
- data/lib/scout_apm/slow_item_set.rb +80 -0
- data/lib/scout_apm/slow_job_record.rb +1 -6
- data/lib/scout_apm/slow_transaction.rb +2 -20
- data/lib/scout_apm/store.rb +12 -50
- data/lib/scout_apm/trace_compactor.rb +311 -0
- data/lib/scout_apm/tracked_request.rb +37 -128
- data/lib/scout_apm/utils/backtrace_parser.rb +5 -7
- data/lib/scout_apm/utils/fake_stacks.rb +83 -0
- data/lib/scout_apm/version.rb +1 -1
- data/scout_apm.gemspec +4 -6
- data/test/test_helper.rb +0 -56
- data/test/unit/config_test.rb +9 -60
- data/test/unit/histogram_test.rb +0 -14
- data/test/unit/layaway_test.rb +16 -31
- data/test/unit/serializers/payload_serializer_test.rb +105 -3
- data/test/unit/slow_item_set_test.rb +94 -0
- data/test/unit/slow_job_policy_test.rb +49 -0
- data/test/unit/slow_request_policy_test.rb +5 -4
- data/test/unit/utils/backtrace_parser_test.rb +0 -19
- data/tester.rb +53 -0
- metadata +29 -124
- data/.rubocop.yml +0 -8
- data/Guardfile +0 -42
- data/ext/rusage/README.md +0 -26
- data/ext/rusage/extconf.rb +0 -5
- data/ext/rusage/rusage.c +0 -52
- data/lib/scout_apm/background_job_integrations/resque.rb +0 -85
- data/lib/scout_apm/background_recorder.rb +0 -43
- data/lib/scout_apm/debug.rb +0 -37
- data/lib/scout_apm/git_revision.rb +0 -51
- data/lib/scout_apm/instruments/action_view.rb +0 -49
- data/lib/scout_apm/instruments/resque.rb +0 -40
- data/lib/scout_apm/layer_children_set.rb +0 -77
- data/lib/scout_apm/limited_layer.rb +0 -122
- data/lib/scout_apm/rack.rb +0 -26
- data/lib/scout_apm/remote/message.rb +0 -23
- data/lib/scout_apm/remote/recorder.rb +0 -57
- data/lib/scout_apm/remote/router.rb +0 -49
- data/lib/scout_apm/remote/server.rb +0 -58
- data/lib/scout_apm/serializers/histograms_serializer_to_json.rb +0 -21
- data/lib/scout_apm/synchronous_recorder.rb +0 -26
- data/lib/scout_apm/utils/gzip_helper.rb +0 -24
- data/lib/scout_apm/utils/numbers.rb +0 -14
- data/lib/scout_apm/utils/scm.rb +0 -14
- data/test/unit/background_job_integrations/sidekiq_test.rb +0 -104
- data/test/unit/context_test.rb +0 -30
- data/test/unit/git_revision_test.rb +0 -15
- data/test/unit/instruments/net_http_test.rb +0 -21
- data/test/unit/instruments/percentile_sampler_test.rb +0 -137
- data/test/unit/layer_children_set_test.rb +0 -88
- data/test/unit/limited_layer_test.rb +0 -53
- data/test/unit/remote/test_message.rb +0 -13
- data/test/unit/remote/test_router.rb +0 -33
- data/test/unit/remote/test_server.rb +0 -15
- data/test/unit/store_test.rb +0 -89
- data/test/unit/test_tracked_request.rb +0 -87
- data/test/unit/utils/numbers_test.rb +0 -15
- data/test/unit/utils/scm.rb +0 -17
data/test/unit/config_test.rb
CHANGED
@@ -4,78 +4,27 @@ require 'scout_apm/config'
|
|
4
4
|
|
5
5
|
class ConfigTest < Minitest::Test
|
6
6
|
def test_initalize_without_a_config
|
7
|
-
conf = ScoutApm::Config.
|
7
|
+
conf = ScoutApm::Config.new(nil)
|
8
8
|
|
9
9
|
# nil for random keys
|
10
|
-
assert_nil conf.value(
|
10
|
+
assert_nil conf.value("log_file_path")
|
11
11
|
|
12
12
|
# but has values for defaulted keys
|
13
|
-
assert conf.value(
|
13
|
+
assert conf.value("host")
|
14
14
|
|
15
15
|
# and still reads from ENV
|
16
16
|
ENV['SCOUT_CONFIG_TEST_KEY'] = 'testval'
|
17
|
-
assert_equal 'testval', conf.value(
|
17
|
+
assert_equal 'testval', conf.value("config_test_key")
|
18
18
|
end
|
19
19
|
|
20
20
|
def test_loading_a_file
|
21
|
-
set_rack_env(
|
21
|
+
set_rack_env("production")
|
22
22
|
|
23
|
-
conf_file = File.expand_path('../../data/config_test_1.yml', __FILE__)
|
24
|
-
conf = ScoutApm::Config.with_file(conf_file)
|
25
|
-
|
26
|
-
assert_equal 'debug', conf.value('log_level')
|
27
|
-
assert_equal 'APM Test Conf (Production)', conf.value('name')
|
28
|
-
end
|
29
|
-
|
30
|
-
def test_loading_file_without_env_in_file
|
31
23
|
conf_file = File.expand_path("../../data/config_test_1.yml", __FILE__)
|
32
|
-
conf = ScoutApm::Config.
|
24
|
+
conf = ScoutApm::Config.new(conf_file)
|
33
25
|
|
34
|
-
assert_equal "
|
35
|
-
|
36
|
-
end
|
37
|
-
|
38
|
-
def test_boolean_coercion
|
39
|
-
coercion = ScoutApm::Config::BooleanCoercion.new
|
40
|
-
assert_equal true, coercion.coerce("true")
|
41
|
-
assert_equal true, coercion.coerce("t")
|
42
|
-
assert_equal false, coercion.coerce("false")
|
43
|
-
assert_equal false, coercion.coerce("f")
|
44
|
-
assert_equal false, coercion.coerce("")
|
45
|
-
|
46
|
-
assert_equal true, coercion.coerce(true)
|
47
|
-
assert_equal false, coercion.coerce(false)
|
48
|
-
assert_equal false, coercion.coerce(nil)
|
49
|
-
|
50
|
-
assert_equal true, coercion.coerce(1)
|
51
|
-
assert_equal true, coercion.coerce(20)
|
52
|
-
assert_equal true, coercion.coerce(-1)
|
53
|
-
assert_equal false, coercion.coerce(0)
|
54
|
-
|
55
|
-
# for any other unknown class, there is no clear answer, so be safe and say false.
|
56
|
-
assert_equal false, coercion.coerce([])
|
57
|
-
end
|
58
|
-
|
59
|
-
def test_json_coersion
|
60
|
-
coercion = ScoutApm::Config::JsonCoercion.new
|
61
|
-
assert_equal [1,2,3], coercion.coerce('[1,2,3]')
|
62
|
-
assert_equal ['foo/bar','baz/quux'], coercion.coerce('["foo/bar", "baz/quux"]')
|
63
|
-
|
64
|
-
assert_equal({"foo" => "bar"}, coercion.coerce('{"foo": "bar"}'))
|
65
|
-
|
66
|
-
assert_equal true, coercion.coerce(true)
|
67
|
-
assert_equal 10, coercion.coerce(10)
|
68
|
-
assert_equal ["a"], coercion.coerce(["a"])
|
69
|
-
end
|
70
|
-
|
71
|
-
def test_any_keys_found
|
72
|
-
ENV.stubs(:has_key?).returns(nil)
|
73
|
-
|
74
|
-
conf = ScoutApm::Config.with_file("a_file_that_doesnt_exist.yml")
|
75
|
-
assert ! conf.any_keys_found?
|
76
|
-
|
77
|
-
ENV.stubs(:has_key?).with("SCOUT_MONITOR").returns("true")
|
78
|
-
conf = ScoutApm::Config.with_file("a_file_that_doesnt_exist.yml")
|
79
|
-
assert conf.any_keys_found?
|
26
|
+
assert_equal "debug", conf.value('log_level')
|
27
|
+
assert_equal "APM Test Conf (Production)", conf.value('name')
|
80
28
|
end
|
81
29
|
end
|
30
|
+
|
data/test/unit/histogram_test.rb
CHANGED
@@ -79,20 +79,6 @@ class HistogramTest < Minitest::Test
|
|
79
79
|
assert combined.quantile(0) < combined.quantile(100)
|
80
80
|
end
|
81
81
|
|
82
|
-
def test_combine_dedups_identicals
|
83
|
-
hist1 = ScoutApm::NumericHistogram.new(5)
|
84
|
-
hist2 = ScoutApm::NumericHistogram.new(5)
|
85
|
-
hist1.add(1)
|
86
|
-
hist1.add(2)
|
87
|
-
hist2.add(2)
|
88
|
-
hist2.add(3)
|
89
|
-
|
90
|
-
combined = hist1.combine!(hist2)
|
91
|
-
assert_equal 4, combined.total
|
92
|
-
assert_equal [[1, 1], [2, 2], [1, 3]],
|
93
|
-
combined.bins.map{|bin| [bin.count, bin.value.to_i] }
|
94
|
-
end
|
95
|
-
|
96
82
|
def test_mean
|
97
83
|
hist = ScoutApm::NumericHistogram.new(5)
|
98
84
|
10.times {
|
data/test/unit/layaway_test.rb
CHANGED
@@ -5,40 +5,25 @@ require 'scout_apm/metric_stats'
|
|
5
5
|
require 'scout_apm/context'
|
6
6
|
require 'scout_apm/store'
|
7
7
|
|
8
|
-
require 'fileutils'
|
9
8
|
class LayawayTest < Minitest::Test
|
10
|
-
def
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
9
|
+
def test_add_reporting_period
|
10
|
+
File.open(DATA_FILE_PATH, 'w') { |file| file.write(Marshal.dump(NEW_FORMAT)) }
|
11
|
+
ScoutApm::Agent.instance.start
|
12
|
+
|
13
|
+
data = ScoutApm::Layaway.new
|
14
|
+
t = ScoutApm::StoreReportingPeriodTimestamp.new
|
15
|
+
data.add_reporting_period(t,ScoutApm::StoreReportingPeriod.new(t))
|
16
|
+
assert_equal [TIMESTAMP,t].sort_by(&:timestamp), Marshal.load(File.read(DATA_FILE_PATH)).keys.sort_by(&:timestamp)
|
15
17
|
end
|
16
18
|
|
17
|
-
def
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
assert_equal
|
19
|
+
def test_merge_reporting_period
|
20
|
+
File.open(DATA_FILE_PATH, 'w') { |file| file.write(Marshal.dump(NEW_FORMAT)) }
|
21
|
+
layaway = ScoutApm::Layaway.new
|
22
|
+
layaway.add_reporting_period(TIMESTAMP, ScoutApm::StoreReportingPeriod.new(TIMESTAMP))
|
23
|
+
unmarshalled = Marshal.load(File.read(DATA_FILE_PATH))
|
24
|
+
assert_equal [TIMESTAMP], unmarshalled.keys
|
23
25
|
end
|
24
26
|
|
25
|
-
|
26
|
-
|
27
|
-
config = make_fake_config("data_file" => "/tmp/scout_apm_test/layaway_limit")
|
28
|
-
layaway = ScoutApm::Layaway.new(config, ScoutApm::Agent.instance.environment)
|
29
|
-
layaway.delete_files_for(:all)
|
30
|
-
|
31
|
-
current_time = Time.now.utc
|
32
|
-
current_rp = ScoutApm::StoreReportingPeriod.new(current_time)
|
33
|
-
stale_rp = ScoutApm::StoreReportingPeriod.new(current_time - current_time.sec - 120)
|
34
|
-
|
35
|
-
# layaway.write_reporting_period returns nil on successful write
|
36
|
-
# It should probably be changed to return true or the number of bytes written
|
37
|
-
assert_nil layaway.write_reporting_period(stale_rp, 1)
|
38
|
-
|
39
|
-
# layaway.write_reporting_period returns an explicit false class on failure
|
40
|
-
assert layaway.write_reporting_period(current_rp, 1).is_a?(FalseClass)
|
41
|
-
|
42
|
-
layaway.delete_files_for(:all)
|
43
|
-
end
|
27
|
+
TIMESTAMP = ScoutApm::StoreReportingPeriodTimestamp.new(Time.parse("2015-01-01"))
|
28
|
+
NEW_FORMAT = {TIMESTAMP => ScoutApm::StoreReportingPeriod.new(TIMESTAMP)} # Format for 1.2+ agents
|
44
29
|
end
|
@@ -6,18 +6,33 @@ require 'scout_apm/serializers/payload_serializer_to_json'
|
|
6
6
|
require 'scout_apm/slow_transaction'
|
7
7
|
require 'scout_apm/metric_meta'
|
8
8
|
require 'scout_apm/metric_stats'
|
9
|
+
require 'scout_apm/utils/fake_stack_prof'
|
9
10
|
require 'scout_apm/context'
|
10
11
|
require 'ostruct'
|
11
12
|
require 'json' # to deserialize what has been manually serialized by the production code
|
12
13
|
|
14
|
+
# stub the report_format value
|
15
|
+
# class ScoutApm::Agent
|
16
|
+
# module Config
|
17
|
+
# def self.value(key)
|
18
|
+
# 'json'
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
|
22
|
+
# def self.instance
|
23
|
+
# OpenStruct.new(:config => Config)
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
|
13
27
|
class PayloadSerializerTest < Minitest::Test
|
28
|
+
|
14
29
|
def test_serializes_metadata_as_json
|
15
30
|
metadata = {
|
16
31
|
:app_root => "/srv/app/rootz",
|
17
32
|
:unique_id => "unique_idz",
|
18
33
|
:agent_version => 123
|
19
34
|
}
|
20
|
-
payload = ScoutApm::Serializers::PayloadSerializerToJson.serialize(metadata, {}, {}, [], []
|
35
|
+
payload = ScoutApm::Serializers::PayloadSerializerToJson.serialize(metadata, {}, {}, [], [])
|
21
36
|
|
22
37
|
# symbol keys turn to strings
|
23
38
|
formatted_metadata = {
|
@@ -58,7 +73,7 @@ class PayloadSerializerTest < Minitest::Test
|
|
58
73
|
stats.total_exclusive_time = 0.07813208899999999
|
59
74
|
}
|
60
75
|
}
|
61
|
-
payload = ScoutApm::Serializers::PayloadSerializerToJson.serialize({}, metrics, {}, [], []
|
76
|
+
payload = ScoutApm::Serializers::PayloadSerializerToJson.serialize({}, metrics, {}, [], [])
|
62
77
|
formatted_metrics = [
|
63
78
|
{
|
64
79
|
"key" => {
|
@@ -97,12 +112,99 @@ class PayloadSerializerTest < Minitest::Test
|
|
97
112
|
assert_equal formatted_metrics, JSON.parse(payload)["metrics"]
|
98
113
|
end
|
99
114
|
|
115
|
+
def test_serializes_slow_transactions_as_json
|
116
|
+
slow_transaction_metrics = {
|
117
|
+
ScoutApm::MetricMeta.new('ActiveRecord/all').tap { |meta|
|
118
|
+
meta.desc = "SELECT *\nfrom users where filter=?"
|
119
|
+
meta.extra = {:user => 'cooluser'}
|
120
|
+
meta.metric_id = nil
|
121
|
+
meta.scope = "Controller/apps/checkin"
|
122
|
+
} => ScoutApm::MetricStats.new.tap { |stats|
|
123
|
+
stats.call_count = 16
|
124
|
+
stats.max_call_time = 0.005338062
|
125
|
+
stats.min_call_time = 0.000613518
|
126
|
+
stats.sum_of_squares = 9.8040860751126e-05
|
127
|
+
stats.total_call_time = 0.033245704
|
128
|
+
stats.total_exclusive_time = 0.033245704
|
129
|
+
},
|
130
|
+
ScoutApm::MetricMeta.new("Controller/apps/checkin").tap { |meta|
|
131
|
+
meta.desc = nil
|
132
|
+
meta.extra = {}
|
133
|
+
meta.metric_id = nil
|
134
|
+
meta.scope = nil
|
135
|
+
} => ScoutApm::MetricStats.new.tap { |stats|
|
136
|
+
stats.call_count = 2
|
137
|
+
stats.max_call_time = 0.078521419
|
138
|
+
stats.min_call_time = 0.034881757
|
139
|
+
stats.sum_of_squares = 0.007382350213180609
|
140
|
+
stats.total_call_time = 0.113403176
|
141
|
+
stats.total_exclusive_time = 0.07813208899999999
|
142
|
+
}
|
143
|
+
}
|
144
|
+
context = ScoutApm::Context.new
|
145
|
+
context.add({"this" => "that"})
|
146
|
+
context.add_user({"hello" => "goodbye"})
|
147
|
+
slow_t = ScoutApm::SlowTransaction.new("http://example.com/blabla", "Buckethead/something/else", 1.23, slow_transaction_metrics, context, Time.at(1448198788), [], 10)
|
148
|
+
payload = ScoutApm::Serializers::PayloadSerializerToJson.serialize({}, {}, [slow_t], [], [])
|
149
|
+
formatted_slow_transactions = [
|
150
|
+
{
|
151
|
+
"key" => {
|
152
|
+
"bucket" => "Buckethead",
|
153
|
+
"name" => "something/else"
|
154
|
+
},
|
155
|
+
"time" => "2015-11-22 06:26:28 -0700",
|
156
|
+
"total_call_time" => 1.23,
|
157
|
+
"uri" => "http://example.com/blabla",
|
158
|
+
"context" => {"this"=>"that", "user"=>{"hello"=>"goodbye"}},
|
159
|
+
"prof" => [],
|
160
|
+
"score" => 10,
|
161
|
+
"metrics" => [
|
162
|
+
{
|
163
|
+
"key" => {
|
164
|
+
"bucket" => "ActiveRecord",
|
165
|
+
"name" => "all",
|
166
|
+
"desc" => "SELECT *\nfrom users where filter=?",
|
167
|
+
"extra" => {
|
168
|
+
"user" => "cooluser",
|
169
|
+
},
|
170
|
+
"scope" => {
|
171
|
+
"bucket" => "Controller",
|
172
|
+
"name" => "apps/checkin",
|
173
|
+
},
|
174
|
+
},
|
175
|
+
"call_count" => 16,
|
176
|
+
"max_call_time" => 0.005338062,
|
177
|
+
"min_call_time" => 0.000613518,
|
178
|
+
"total_call_time" => 0.033245704,
|
179
|
+
"total_exclusive_time" => 0.033245704,
|
180
|
+
},
|
181
|
+
{
|
182
|
+
"key" => {
|
183
|
+
"bucket" => "Controller",
|
184
|
+
"name" => "apps/checkin",
|
185
|
+
"desc" => nil,
|
186
|
+
"extra" => {},
|
187
|
+
"scope" => nil,
|
188
|
+
},
|
189
|
+
"call_count" => 2,
|
190
|
+
"max_call_time" => 0.078521419,
|
191
|
+
"min_call_time" => 0.034881757,
|
192
|
+
"total_call_time" => 0.113403176,
|
193
|
+
"total_exclusive_time" => 0.07813208899999999,
|
194
|
+
}
|
195
|
+
]
|
196
|
+
}
|
197
|
+
]
|
198
|
+
|
199
|
+
assert_equal formatted_slow_transactions, JSON.parse(payload)["slow_transactions"]
|
200
|
+
end
|
201
|
+
|
100
202
|
def test_escapes_json_quotes
|
101
203
|
metadata = {
|
102
204
|
:quotie => "here are some \"quotes\"",
|
103
205
|
:payload_version => 2,
|
104
206
|
}
|
105
|
-
payload = ScoutApm::Serializers::PayloadSerializerToJson.serialize(metadata, {}, {}, [], []
|
207
|
+
payload = ScoutApm::Serializers::PayloadSerializerToJson.serialize(metadata, {}, {}, [], [])
|
106
208
|
|
107
209
|
# symbol keys turn to strings
|
108
210
|
formatted_metadata = {
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
require 'scout_apm/slow_item_set'
|
4
|
+
require 'scout_apm/slow_transaction'
|
5
|
+
|
6
|
+
class SlowItemSetTest < Minitest::Test
|
7
|
+
def test_adding_to_empty_set
|
8
|
+
set = ScoutApm::SlowItemSet.new(3, 1)
|
9
|
+
set << make_slow("Controller/Foo")
|
10
|
+
assert_equal 1, set.count
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_adding_to_partially_full_set
|
14
|
+
set = ScoutApm::SlowItemSet.new(3, 1)
|
15
|
+
set << make_slow("Controller/Foo")
|
16
|
+
set << make_slow("Controller/Foo")
|
17
|
+
assert_equal 2, set.count
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_overflow_of_one_type
|
21
|
+
max_size = 3
|
22
|
+
set = ScoutApm::SlowItemSet.new(max_size, 1)
|
23
|
+
set << make_slow("Controller/Foo")
|
24
|
+
set << make_slow("Controller/Foo")
|
25
|
+
set << make_slow("Controller/Foo")
|
26
|
+
set << make_slow("Controller/Foo")
|
27
|
+
set << make_slow("Controller/Foo")
|
28
|
+
set << make_slow("Controller/Foo")
|
29
|
+
assert_equal max_size, set.count
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_eviction_of_overrepresented
|
33
|
+
max_size = 3
|
34
|
+
set = ScoutApm::SlowItemSet.new(max_size, 1)
|
35
|
+
set << make_slow("Controller/Foo")
|
36
|
+
set << make_slow("Controller/Foo")
|
37
|
+
set << make_slow("Controller/Foo")
|
38
|
+
set << make_slow("Controller/Foo")
|
39
|
+
set << make_slow("Controller/Foo")
|
40
|
+
set << make_slow("Controller/Bar")
|
41
|
+
|
42
|
+
# 3 total
|
43
|
+
assert_equal max_size, set.count
|
44
|
+
assert_equal 1, set.select{|sl| sl.metric_name == "Controller/Bar"}.length
|
45
|
+
assert_equal 2, set.select{|sl| sl.metric_name == "Controller/Foo"}.length
|
46
|
+
end
|
47
|
+
|
48
|
+
# Fill the set with /Foo records, then add a /Bar to evict. Check that the
|
49
|
+
# evicted one was the fastest of the Foos
|
50
|
+
def test_eviction_of_fastest
|
51
|
+
max_size = 3
|
52
|
+
set = ScoutApm::SlowItemSet.new(max_size, 1)
|
53
|
+
|
54
|
+
[1,2,3].shuffle.each do |seconds| # Shuffle to remove any assumptions on order
|
55
|
+
set << make_slow("Controller/Foo", seconds)
|
56
|
+
end
|
57
|
+
set << make_slow("Controller/Bar", 8)
|
58
|
+
|
59
|
+
# The foo taking 1 second should be evicted
|
60
|
+
assert_equal 2, set.select{|sl| sl.metric_name == "Controller/Foo"}.map{ |sl| sl.total_call_time}.min
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_eviction_when_no_overrepresented
|
64
|
+
max_size = 4
|
65
|
+
fair = 2
|
66
|
+
set = ScoutApm::SlowItemSet.new(max_size, fair)
|
67
|
+
|
68
|
+
# Full, but each is at fair level
|
69
|
+
set << make_slow("Controller/Bar")
|
70
|
+
set << make_slow("Controller/Bar")
|
71
|
+
set << make_slow("Controller/Foo")
|
72
|
+
set << make_slow("Controller/Foo")
|
73
|
+
|
74
|
+
set << make_slow("Controller/Quux")
|
75
|
+
assert_equal max_size, set.count
|
76
|
+
assert_equal 0, set.select{|sl| sl.metric_name == "Controller/Quux" }.length
|
77
|
+
end
|
78
|
+
|
79
|
+
##############
|
80
|
+
#### Helpers
|
81
|
+
##############
|
82
|
+
|
83
|
+
def make_slow(metric, time=5)
|
84
|
+
ScoutApm::SlowTransaction.new(
|
85
|
+
"http://foo.app/#{metric}",
|
86
|
+
metric,
|
87
|
+
time,
|
88
|
+
{}, # metrics
|
89
|
+
{}, # context
|
90
|
+
Time.now, # end time
|
91
|
+
[], # stackprof
|
92
|
+
0)
|
93
|
+
end
|
94
|
+
end
|
@@ -3,4 +3,53 @@ require 'test_helper'
|
|
3
3
|
require 'scout_apm/slow_job_policy'
|
4
4
|
|
5
5
|
class SlowJobPolicyTest < Minitest::Test
|
6
|
+
def test_first_call_is_not_slow
|
7
|
+
policy = ScoutApm::SlowJobPolicy.new
|
8
|
+
assert !policy.slow?("TestWorker", 10)
|
9
|
+
end
|
10
|
+
|
11
|
+
# All of these get faster and faster, so none are marked as slow.
|
12
|
+
def test_fast_calls_are_not_slow
|
13
|
+
policy = ScoutApm::SlowJobPolicy.new
|
14
|
+
assert !policy.slow?("TestWorker", 10)
|
15
|
+
assert !policy.slow?("TestWorker", 8)
|
16
|
+
assert !policy.slow?("TestWorker", 6)
|
17
|
+
assert !policy.slow?("TestWorker", 4)
|
18
|
+
assert !policy.slow?("TestWorker", 2)
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_slow_calls_are_marked_as_slow
|
22
|
+
policy = ScoutApm::SlowJobPolicy.new
|
23
|
+
policy.slow?("TestWorker", 10) # Prime it with a not-slow
|
24
|
+
|
25
|
+
assert policy.slow?("TestWorker", 12)
|
26
|
+
assert policy.slow?("TestWorker", 14)
|
27
|
+
assert policy.slow?("TestWorker", 16)
|
28
|
+
assert policy.slow?("TestWorker", 18)
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_mix_of_fast_and_slow
|
32
|
+
policy = ScoutApm::SlowJobPolicy.new
|
33
|
+
policy.slow?("TestWorker", 10) # Prime it with a not-slow
|
34
|
+
|
35
|
+
assert policy.slow?("TestWorker", 12)
|
36
|
+
assert !policy.slow?("TestWorker", 8)
|
37
|
+
assert policy.slow?("TestWorker", 13)
|
38
|
+
assert !policy.slow?("TestWorker", 6)
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_different_workers_dont_interfere
|
42
|
+
policy = ScoutApm::SlowJobPolicy.new
|
43
|
+
policy.slow?("TestWorker", 10) # Prime it with a not-slow
|
44
|
+
policy.slow?("OtherWorker", 1.0) # Prime it with a not-slow
|
45
|
+
|
46
|
+
assert !policy.slow?("TestWorker", 8)
|
47
|
+
assert policy.slow?("OtherWorker", 2)
|
48
|
+
assert !policy.slow?("TestWorker", 1)
|
49
|
+
assert policy.slow?("OtherWorker", 3)
|
50
|
+
assert policy.slow?("TestWorker", 12)
|
51
|
+
assert !policy.slow?("OtherWorker", 1)
|
52
|
+
assert policy.slow?("TestWorker", 12)
|
53
|
+
assert policy.slow?("OtherWorker", 4)
|
54
|
+
end
|
6
55
|
end
|