scout_apm 2.4.12 → 2.4.13

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 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: