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.
Files changed (117) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -1
  3. data/CHANGELOG.markdown +2 -161
  4. data/Rakefile +2 -2
  5. data/ext/allocations/allocations.c +0 -6
  6. data/ext/allocations/extconf.rb +0 -1
  7. data/ext/stacks/extconf.rb +33 -0
  8. data/ext/stacks/scout_atomics.h +86 -0
  9. data/ext/stacks/stacks.c +744 -0
  10. data/lib/scout_apm.rb +16 -24
  11. data/lib/scout_apm/agent.rb +38 -93
  12. data/lib/scout_apm/agent/logging.rb +1 -6
  13. data/lib/scout_apm/agent/reporting.rb +6 -8
  14. data/lib/scout_apm/app_server_load.rb +10 -21
  15. data/lib/scout_apm/attribute_arranger.rb +2 -0
  16. data/lib/scout_apm/background_job_integrations/delayed_job.rb +1 -71
  17. data/lib/scout_apm/background_job_integrations/sidekiq.rb +27 -66
  18. data/lib/scout_apm/background_worker.rb +15 -19
  19. data/lib/scout_apm/capacity.rb +57 -0
  20. data/lib/scout_apm/config.rb +29 -135
  21. data/lib/scout_apm/context.rb +5 -9
  22. data/lib/scout_apm/deploy_integrations/capistrano_2.cap +12 -0
  23. data/lib/scout_apm/deploy_integrations/capistrano_2.rb +83 -0
  24. data/lib/scout_apm/deploy_integrations/capistrano_3.cap +12 -0
  25. data/lib/scout_apm/deploy_integrations/capistrano_3.rb +88 -0
  26. data/lib/scout_apm/environment.rb +15 -22
  27. data/lib/scout_apm/histogram.rb +2 -11
  28. data/lib/scout_apm/instant/assets/xmlhttp_instrumentation.html +2 -2
  29. data/lib/scout_apm/instant/middleware.rb +57 -198
  30. data/lib/scout_apm/instruments/action_controller_rails_2.rb +2 -1
  31. data/lib/scout_apm/instruments/action_controller_rails_3_rails4.rb +59 -90
  32. data/lib/scout_apm/instruments/active_record.rb +5 -7
  33. data/lib/scout_apm/instruments/delayed_job.rb +57 -0
  34. data/lib/scout_apm/instruments/grape.rb +3 -4
  35. data/lib/scout_apm/instruments/middleware_detailed.rb +6 -4
  36. data/lib/scout_apm/instruments/middleware_summary.rb +1 -39
  37. data/lib/scout_apm/instruments/mongoid.rb +3 -24
  38. data/lib/scout_apm/instruments/net_http.rb +2 -7
  39. data/lib/scout_apm/instruments/percentile_sampler.rb +19 -36
  40. data/lib/scout_apm/instruments/process/process_cpu.rb +2 -3
  41. data/lib/scout_apm/instruments/process/process_memory.rb +3 -3
  42. data/lib/scout_apm/layaway.rb +33 -76
  43. data/lib/scout_apm/layer.rb +59 -16
  44. data/lib/scout_apm/layer_converters/converter_base.rb +0 -199
  45. data/lib/scout_apm/layer_converters/job_converter.rb +1 -1
  46. data/lib/scout_apm/layer_converters/metric_converter.rb +1 -1
  47. data/lib/scout_apm/layer_converters/slow_job_converter.rb +90 -15
  48. data/lib/scout_apm/layer_converters/slow_request_converter.rb +101 -13
  49. data/lib/scout_apm/metric_set.rb +1 -9
  50. data/lib/scout_apm/metric_stats.rb +8 -8
  51. data/lib/scout_apm/reporter.rb +15 -51
  52. data/lib/scout_apm/request_histograms.rb +0 -4
  53. data/lib/scout_apm/request_manager.rb +1 -2
  54. data/lib/scout_apm/scored_item_set.rb +0 -7
  55. data/lib/scout_apm/serializers/deploy_serializer.rb +16 -0
  56. data/lib/scout_apm/serializers/payload_serializer.rb +3 -9
  57. data/lib/scout_apm/serializers/payload_serializer_to_json.rb +5 -2
  58. data/lib/scout_apm/serializers/slow_jobs_serializer_to_json.rb +1 -2
  59. data/lib/scout_apm/server_integrations/puma.rb +2 -5
  60. data/lib/scout_apm/slow_item_set.rb +80 -0
  61. data/lib/scout_apm/slow_job_record.rb +1 -6
  62. data/lib/scout_apm/slow_transaction.rb +2 -20
  63. data/lib/scout_apm/store.rb +12 -50
  64. data/lib/scout_apm/trace_compactor.rb +311 -0
  65. data/lib/scout_apm/tracked_request.rb +37 -128
  66. data/lib/scout_apm/utils/backtrace_parser.rb +5 -7
  67. data/lib/scout_apm/utils/fake_stacks.rb +83 -0
  68. data/lib/scout_apm/version.rb +1 -1
  69. data/scout_apm.gemspec +4 -6
  70. data/test/test_helper.rb +0 -56
  71. data/test/unit/config_test.rb +9 -60
  72. data/test/unit/histogram_test.rb +0 -14
  73. data/test/unit/layaway_test.rb +16 -31
  74. data/test/unit/serializers/payload_serializer_test.rb +105 -3
  75. data/test/unit/slow_item_set_test.rb +94 -0
  76. data/test/unit/slow_job_policy_test.rb +49 -0
  77. data/test/unit/slow_request_policy_test.rb +5 -4
  78. data/test/unit/utils/backtrace_parser_test.rb +0 -19
  79. data/tester.rb +53 -0
  80. metadata +29 -124
  81. data/.rubocop.yml +0 -8
  82. data/Guardfile +0 -42
  83. data/ext/rusage/README.md +0 -26
  84. data/ext/rusage/extconf.rb +0 -5
  85. data/ext/rusage/rusage.c +0 -52
  86. data/lib/scout_apm/background_job_integrations/resque.rb +0 -85
  87. data/lib/scout_apm/background_recorder.rb +0 -43
  88. data/lib/scout_apm/debug.rb +0 -37
  89. data/lib/scout_apm/git_revision.rb +0 -51
  90. data/lib/scout_apm/instruments/action_view.rb +0 -49
  91. data/lib/scout_apm/instruments/resque.rb +0 -40
  92. data/lib/scout_apm/layer_children_set.rb +0 -77
  93. data/lib/scout_apm/limited_layer.rb +0 -122
  94. data/lib/scout_apm/rack.rb +0 -26
  95. data/lib/scout_apm/remote/message.rb +0 -23
  96. data/lib/scout_apm/remote/recorder.rb +0 -57
  97. data/lib/scout_apm/remote/router.rb +0 -49
  98. data/lib/scout_apm/remote/server.rb +0 -58
  99. data/lib/scout_apm/serializers/histograms_serializer_to_json.rb +0 -21
  100. data/lib/scout_apm/synchronous_recorder.rb +0 -26
  101. data/lib/scout_apm/utils/gzip_helper.rb +0 -24
  102. data/lib/scout_apm/utils/numbers.rb +0 -14
  103. data/lib/scout_apm/utils/scm.rb +0 -14
  104. data/test/unit/background_job_integrations/sidekiq_test.rb +0 -104
  105. data/test/unit/context_test.rb +0 -30
  106. data/test/unit/git_revision_test.rb +0 -15
  107. data/test/unit/instruments/net_http_test.rb +0 -21
  108. data/test/unit/instruments/percentile_sampler_test.rb +0 -137
  109. data/test/unit/layer_children_set_test.rb +0 -88
  110. data/test/unit/limited_layer_test.rb +0 -53
  111. data/test/unit/remote/test_message.rb +0 -13
  112. data/test/unit/remote/test_router.rb +0 -33
  113. data/test/unit/remote/test_server.rb +0 -15
  114. data/test/unit/store_test.rb +0 -89
  115. data/test/unit/test_tracked_request.rb +0 -87
  116. data/test/unit/utils/numbers_test.rb +0 -15
  117. data/test/unit/utils/scm.rb +0 -17
@@ -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.without_file
7
+ conf = ScoutApm::Config.new(nil)
8
8
 
9
9
  # nil for random keys
10
- assert_nil conf.value('log_file_path')
10
+ assert_nil conf.value("log_file_path")
11
11
 
12
12
  # but has values for defaulted keys
13
- assert conf.value('host')
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('config_test_key')
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('production')
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.with_file(conf_file, environment: "staging")
24
+ conf = ScoutApm::Config.new(conf_file)
33
25
 
34
- assert_equal "info", conf.value('log_level') # the default value
35
- assert_nil nil, conf.value('name') # the default value
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
+
@@ -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 {
@@ -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 test_directory_uses_DATA_FILE_option
11
- FileUtils.mkdir_p '/tmp/scout_apm_test/data_file_option'
12
- config = make_fake_config("data_file" => "/tmp/scout_apm_test/data_file_option")
13
-
14
- assert_equal Pathname.new("/tmp/scout_apm_test/data_file_option"), ScoutApm::Layaway.new(config, ScoutApm::Agent.instance.environment).directory
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 test_directory_looks_for_root_slash_tmp
18
- FileUtils.mkdir_p '/tmp/scout_apm_test/tmp'
19
- config = make_fake_config({})
20
- env = make_fake_environment(:root => "/tmp/scout_apm_test")
21
-
22
- assert_equal Pathname.new("/tmp/scout_apm_test/tmp"), ScoutApm::Layaway.new(config, env).directory
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
- def test_layaway_file_limit_prevents_new_writes
26
- FileUtils.mkdir_p '/tmp/scout_apm_test/layaway_limit'
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