scout_apm 2.4.12 → 2.4.13

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a7e5d2b9fe9d2fd469d56bda28c282bd2b100d35
4
- data.tar.gz: 3da3eba76be22b53891292dca9675c3dd03b198a
3
+ metadata.gz: 2ec07b46e556c0beae2648d2c25a610199814179
4
+ data.tar.gz: ed6284b5c6a58a7ab08a464eb6e60cb65334d12f
5
5
  SHA512:
6
- metadata.gz: fd1c158b0acae2f310e15312af1eb7a258cbbf1fa4566e609c40eca4157406d54d2a50e9c13cde6d7c82af52ccc3d0e76c4f8d6cfb8b05a151da2da29f1b1550
7
- data.tar.gz: 561089fdc52667d956594f473b60086d5c3d5a536936a84963c5e28a30e2c4ef5b4ef211b6ddd833b58044ad4b18acd5e4941e945b337032b4f7f281f550db6d
6
+ metadata.gz: 15c5a89d33a1af9e605a03390b9344cfad0ceefbb18a3afe6800c4afb3797bca60af57d15ef0323165e344d55454877d15e8455f12e3ba5fd15bf3c3eaf01867
7
+ data.tar.gz: 1caf6345c5900c54a493aa87bd95168fa5733ae91a7b73211094045b0437c707e6e755286481d89514f43dca1a8a2e31f3a8eeb5dec8cbbabdfebbfb8aed52ac
data/CHANGELOG.markdown CHANGED
@@ -1,3 +1,7 @@
1
+ # 2.4.13
2
+
3
+ * Incorporating total time consumed into transaction trace policy
4
+
1
5
  # 2.4.12
2
6
 
3
7
  * Calculates DelayedJob queue latency correctly when jobs are scheduled to run in the future
@@ -114,6 +114,10 @@ module ScoutApm
114
114
  @request_histograms_by_time ||= Hash.new { |h, k| h[k] = ScoutApm::RequestHistograms.new }
115
115
  end
116
116
 
117
+ def transaction_time_consumed
118
+ @transaction_time_consumed ||= ScoutApm::TransactionTimeConsumed.new
119
+ end
120
+
117
121
  def store
118
122
  return @store if @store
119
123
  self.store = ScoutApm::Store.new(self)
@@ -20,6 +20,7 @@ require 'scout_apm/environment'
20
20
  # key - the account key with Scout APM. Found in Settings in the Web UI
21
21
  # log_file_path - either a directory or "STDOUT".
22
22
  # log_level - DEBUG / INFO / WARN as usual
23
+ # max_traces - Internal: An experiment in trace quality, this requires a server-side setting as well. Setting this to a higher value will make your app server work harder for no benefit.
23
24
  # monitor - true or false. False prevents any instrumentation from starting
24
25
  # name - override the name reported to APM. This is the name that shows in the Web UI
25
26
  # profile - turn on/off scoutprof (only applicable in Gem versions including scoutprof)
@@ -57,6 +58,7 @@ module ScoutApm
57
58
  'log_level',
58
59
  'log_stderr',
59
60
  'log_stdout',
61
+ 'max_traces',
60
62
  'monitor',
61
63
  'name',
62
64
  'profile',
@@ -151,6 +153,7 @@ module ScoutApm
151
153
  "dev_trace" => BooleanCoercion.new,
152
154
  "enable_background_jobs" => BooleanCoercion.new,
153
155
  "ignore" => JsonCoercion.new,
156
+ "max_traces" => IntegerCoercion.new,
154
157
  "monitor" => BooleanCoercion.new,
155
158
  'database_metric_limit' => IntegerCoercion.new,
156
159
  'database_metric_report_limit' => IntegerCoercion.new,
@@ -250,6 +253,7 @@ module ScoutApm
250
253
  'host' => 'https://checkin.scoutapp.com',
251
254
  'ignore' => [],
252
255
  'log_level' => 'info',
256
+ 'max_traces' => 10,
253
257
  'profile' => true, # for scoutprof
254
258
  'report_format' => 'json',
255
259
  'scm_subdirectory' => '',
@@ -17,6 +17,10 @@ module ScoutApm
17
17
  # Outliers are worth up to "1000ms" of weight
18
18
  POINT_MULTIPLIER_PERCENTILE = 1.0
19
19
 
20
+ # Points for an endpoint's who's throughput * response time is a large % of
21
+ # overall time spent processing requests
22
+ POINT_MULTIPLIER_PERCENT_TIME = 2.5
23
+
20
24
  # A hash of Job Names to the last time we stored a slow trace for it.
21
25
  #
22
26
  # Defaults to a start time that is pretty close to application boot time.
@@ -60,7 +64,9 @@ module ScoutApm
60
64
  # What approximate percentile was this request?
61
65
  percentile = context.request_histograms.approximate_quantile_of_value(unique_name, total_time)
62
66
 
63
- return speed_points(total_time) + percentile_points(percentile) + age_points(age)
67
+ percent_of_total_time = context.transaction_time_consumed.percent_of_total(unique_name)
68
+
69
+ return speed_points(total_time) + percentile_points(percentile) + age_points(age) + percent_time_points(percent_of_total_time)
64
70
  end
65
71
 
66
72
  private
@@ -90,5 +96,16 @@ module ScoutApm
90
96
  def age_points(age)
91
97
  age / 60.0 * POINT_MULTIPLIER_AGE
92
98
  end
99
+
100
+ # Of the total time spent handling endpoints in this app, if this endpoint
101
+ # is a higher percent, it should get more points.
102
+ #
103
+ # A: 20 calls @ 100ms each => 2 seconds of total time
104
+ # B: 10 calls @ 100ms each => 1 second of total time
105
+ #
106
+ # Then A is 66% of the total call time
107
+ def percent_time_points(percent) # Scale 0.0 - 1.0
108
+ percent * POINT_MULTIPLIER_PERCENT_TIME
109
+ end
93
110
  end
94
111
  end
@@ -17,6 +17,10 @@ module ScoutApm
17
17
  # Outliers are worth up to "1000ms" of weight
18
18
  POINT_MULTIPLIER_PERCENTILE = 1.0
19
19
 
20
+ # Points for an endpoint's who's throughput * response time is a large % of
21
+ # overall time spent processing requests
22
+ POINT_MULTIPLIER_PERCENT_TIME = 2.5
23
+
20
24
  # A hash of Endpoint Name to the last time we stored a slow transaction for it.
21
25
  #
22
26
  # Defaults to a start time that is pretty close to application boot time.
@@ -60,7 +64,9 @@ module ScoutApm
60
64
  # What approximate percentile was this request?
61
65
  percentile = context.request_histograms.approximate_quantile_of_value(unique_name, total_time)
62
66
 
63
- return speed_points(total_time) + percentile_points(percentile) + age_points(age)
67
+ percent_of_total_time = context.transaction_time_consumed.percent_of_total(unique_name)
68
+
69
+ return speed_points(total_time) + percentile_points(percentile) + age_points(age) + percent_time_points(percent_of_total_time)
64
70
  end
65
71
 
66
72
  private
@@ -90,5 +96,16 @@ module ScoutApm
90
96
  def age_points(age)
91
97
  age / 60.0 * POINT_MULTIPLIER_AGE
92
98
  end
99
+
100
+ # Of the total time spent handling endpoints in this app, if this endpoint
101
+ # is a higher percent, it should get more points.
102
+ #
103
+ # A: 20 calls @ 100ms each => 2 seconds of total time
104
+ # B: 10 calls @ 100ms each => 1 second of total time
105
+ #
106
+ # Then A is 66% of the total call time
107
+ def percent_time_points(percent) # Scale 0.0 - 1.0
108
+ percent * POINT_MULTIPLIER_PERCENT_TIME
109
+ end
93
110
  end
94
111
  end
@@ -205,8 +205,8 @@ module ScoutApm
205
205
  def initialize(timestamp, context)
206
206
  @timestamp = timestamp
207
207
 
208
- @request_traces = ScoredItemSet.new
209
- @job_traces = ScoredItemSet.new
208
+ @request_traces = ScoredItemSet.new(context.config.value('max_traces'))
209
+ @job_traces = ScoredItemSet.new(context.config.value('max_traces'))
210
210
 
211
211
  @histograms = []
212
212
 
@@ -273,6 +273,8 @@ module ScoutApm
273
273
 
274
274
  apply_name_override
275
275
 
276
+ @agent_context.transaction_time_consumed.add(unique_name, root_layer.total_call_time)
277
+
276
278
  # Make a constant, then call converters.dup.each so it isn't inline?
277
279
  converters = {
278
280
  :histograms => LayerConverters::Histograms,
@@ -0,0 +1,51 @@
1
+ module ScoutApm
2
+ class TransactionTimeConsumed
3
+ # Private Accessor:
4
+ # A hash of Endpoint Name to an time consumed record
5
+ attr_reader :endpoints
6
+ private :endpoints
7
+
8
+ # Private Accessor:
9
+ # The total time spent across all endpoints
10
+ attr_reader :total_duration
11
+ private :total_duration
12
+
13
+ def initialize
14
+ @total_duration = 0.0
15
+ @endpoints = Hash.new { |h, k| h[k] = TotalTimeRecord.new }
16
+ end
17
+
18
+ def add(item, duration)
19
+ @total_duration += duration.to_f
20
+ @endpoints[item].add(duration.to_f)
21
+ end
22
+
23
+ def percent_of_total(item)
24
+ if total_duration == 0.0
25
+ 0
26
+ else
27
+ @endpoints[item].total_duration / total_duration
28
+ end
29
+ end
30
+
31
+ def total_time_for(item)
32
+ @endpoints[item].total_duration
33
+ end
34
+
35
+ def call_count_for(item)
36
+ @endpoints[item].count
37
+ end
38
+
39
+ # Time is in seconds
40
+ TotalTimeRecord = Struct.new(:total_duration, :count) do
41
+ def initialize
42
+ super(0, 0)
43
+ end
44
+
45
+ def add(duration)
46
+ self.total_duration += duration.to_f
47
+ self.count += 1
48
+ end
49
+ end
50
+ end
51
+ end
@@ -1,4 +1,4 @@
1
1
  module ScoutApm
2
- VERSION = "2.4.12"
2
+ VERSION = "2.4.13"
3
3
  end
4
4
 
data/lib/scout_apm.rb CHANGED
@@ -138,6 +138,7 @@ require 'scout_apm/slow_request_policy'
138
138
  require 'scout_apm/slow_job_policy'
139
139
  require 'scout_apm/job_record'
140
140
  require 'scout_apm/request_histograms'
141
+ require 'scout_apm/transaction_time_consumed'
141
142
 
142
143
  require 'scout_apm/attribute_arranger'
143
144
  require 'scout_apm/git_revision'
@@ -38,7 +38,7 @@ class PeriodicCallbacksTest < Minitest::Test
38
38
  private
39
39
 
40
40
  def reporting_period
41
- rp = ScoutApm::StoreReportingPeriod.new(ScoutApm::AgentContext.new, Time.at(metadata[:agent_time].to_i))
41
+ rp = ScoutApm::StoreReportingPeriod.new(Time.at(metadata[:agent_time].to_i), ScoutApm::AgentContext.new)
42
42
  rp.absorb_metrics!(metrics)
43
43
  end
44
44
 
@@ -55,4 +55,4 @@ class PeriodicCallbacksTest < Minitest::Test
55
55
  {:app_root=>"/srv/rails_app", :unique_id=>"ID", :agent_version=>"2.4.10", :agent_time=>"1523287920", :agent_pid=>21581, :platform=>"ruby"}
56
56
  end
57
57
 
58
- end
58
+ end
@@ -37,9 +37,14 @@ class SlowRequestPolicyTest < Minitest::Test
37
37
  request.set_duration(10) # 10 seconds
38
38
  policy.last_seen[request.unique_name] = Time.now - 120 # 2 minutes since last seen
39
39
  @context.request_histograms.add(request.unique_name, 1)
40
+ @context.transaction_time_consumed.add(request.unique_name, 1)
40
41
 
41
- # Actual value I have in console is 1.499
42
- assert policy.score(request) > 1.45
43
- assert policy.score(request) < 1.55
42
+ # Actual value I have in console is 4.01
43
+ # Score uses Time.now to compare w/ last_seen, and will tick up slowly as
44
+ # time passes, hence the range below.
45
+ score = policy.score(request)
46
+
47
+ assert score > 3.95
48
+ assert score < 4.05
44
49
  end
45
50
  end
@@ -0,0 +1,46 @@
1
+ require 'test_helper'
2
+
3
+ require 'scout_apm/transaction_time_consumed'
4
+
5
+ module ScoutApm
6
+ class TransactionTimeConsumedTest < Minitest::Test
7
+ def setup
8
+ @ttc = ScoutApm::TransactionTimeConsumed.new
9
+ end
10
+
11
+ def test_insert_new_times
12
+ @ttc.add("Controller/Foo", 1.5)
13
+ @ttc.add("Controller/Foo", 2.75)
14
+ assert_equal 4.25, @ttc.total_time_for("Controller/Foo")
15
+ end
16
+
17
+ def test_insert_tracks_endpoints_separately
18
+ @ttc.add("Controller/Foo", 1.5)
19
+ @ttc.add("Controller/Foo", 2.75)
20
+ @ttc.add("Controller/Bar", 5)
21
+ @ttc.add("Controller/Bar", 5)
22
+ assert_equal 4.25, @ttc.total_time_for("Controller/Foo")
23
+ assert_equal 10.0, @ttc.total_time_for("Controller/Bar")
24
+ end
25
+
26
+ def test_calculates_percent_of_total
27
+ @ttc.add("Controller/Foo", 1)
28
+ @ttc.add("Controller/Bar", 4)
29
+ assert_equal 0.2, @ttc.percent_of_total("Controller/Foo")
30
+ assert_equal 0.8, @ttc.percent_of_total("Controller/Bar")
31
+ end
32
+
33
+ def test_counts_total_call_count
34
+ @ttc.add("Controller/Foo", 1)
35
+ @ttc.add("Controller/Foo", 1)
36
+ @ttc.add("Controller/Foo", 1)
37
+ @ttc.add("Controller/Bar", 4)
38
+ assert_equal 3, @ttc.call_count_for("Controller/Foo")
39
+ assert_equal 1, @ttc.call_count_for("Controller/Bar")
40
+ end
41
+
42
+ def test_percent_of_total_is_0_with_no_data
43
+ assert_equal 0.0, @ttc.percent_of_total("Controller/Foo")
44
+ end
45
+ end
46
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scout_apm
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.12
4
+ version: 2.4.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - Derek Haynes
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2018-06-01 00:00:00.000000000 Z
12
+ date: 2018-06-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: minitest
@@ -310,6 +310,7 @@ files:
310
310
  - lib/scout_apm/tracer.rb
311
311
  - lib/scout_apm/tracked_request.rb
312
312
  - lib/scout_apm/transaction.rb
313
+ - lib/scout_apm/transaction_time_consumed.rb
313
314
  - lib/scout_apm/utils/active_record_metric_name.rb
314
315
  - lib/scout_apm/utils/backtrace_parser.rb
315
316
  - lib/scout_apm/utils/gzip_helper.rb
@@ -363,6 +364,7 @@ files:
363
364
  - test/unit/tracer_test.rb
364
365
  - test/unit/tracked_request_test.rb
365
366
  - test/unit/transaction_test.rb
367
+ - test/unit/transaction_time_consumed_test.rb
366
368
  - test/unit/utils/active_record_metric_name_test.rb
367
369
  - test/unit/utils/backtrace_parser_test.rb
368
370
  - test/unit/utils/numbers_test.rb
@@ -388,7 +390,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
388
390
  version: '0'
389
391
  requirements: []
390
392
  rubyforge_project: scout_apm
391
- rubygems_version: 2.4.5.2
393
+ rubygems_version: 2.4.6
392
394
  signing_key:
393
395
  specification_version: 4
394
396
  summary: Ruby application performance monitoring
@@ -431,7 +433,9 @@ test_files:
431
433
  - test/unit/tracer_test.rb
432
434
  - test/unit/tracked_request_test.rb
433
435
  - test/unit/transaction_test.rb
436
+ - test/unit/transaction_time_consumed_test.rb
434
437
  - test/unit/utils/active_record_metric_name_test.rb
435
438
  - test/unit/utils/backtrace_parser_test.rb
436
439
  - test/unit/utils/numbers_test.rb
437
440
  - test/unit/utils/scm.rb
441
+ has_rdoc: