scout_apm 2.2.0.pre3 → 2.3.0.pre
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 +147 -2
- data/Guardfile +43 -0
- data/Rakefile +2 -2
- data/ext/allocations/allocations.c +6 -0
- data/ext/allocations/extconf.rb +1 -0
- data/ext/rusage/README.md +26 -0
- data/ext/rusage/extconf.rb +5 -0
- data/ext/rusage/rusage.c +52 -0
- data/lib/scout_apm.rb +28 -15
- data/lib/scout_apm/agent.rb +89 -37
- data/lib/scout_apm/agent/logging.rb +6 -1
- data/lib/scout_apm/agent/reporting.rb +9 -6
- data/lib/scout_apm/app_server_load.rb +21 -10
- data/lib/scout_apm/attribute_arranger.rb +6 -3
- data/lib/scout_apm/background_job_integrations/delayed_job.rb +71 -1
- data/lib/scout_apm/background_job_integrations/resque.rb +85 -0
- data/lib/scout_apm/background_job_integrations/sidekiq.rb +22 -20
- data/lib/scout_apm/background_recorder.rb +43 -0
- data/lib/scout_apm/background_worker.rb +19 -15
- data/lib/scout_apm/config.rb +138 -28
- data/lib/scout_apm/db_query_metric_set.rb +80 -0
- data/lib/scout_apm/db_query_metric_stats.rb +102 -0
- data/lib/scout_apm/debug.rb +37 -0
- data/lib/scout_apm/environment.rb +22 -15
- data/lib/scout_apm/git_revision.rb +51 -0
- data/lib/scout_apm/histogram.rb +11 -2
- data/lib/scout_apm/instant/assets/xmlhttp_instrumentation.html +2 -2
- data/lib/scout_apm/instant/middleware.rb +196 -54
- data/lib/scout_apm/instruments/action_controller_rails_3_rails4.rb +89 -68
- data/lib/scout_apm/instruments/action_view.rb +49 -0
- data/lib/scout_apm/instruments/active_record.rb +127 -3
- data/lib/scout_apm/instruments/grape.rb +4 -3
- data/lib/scout_apm/instruments/middleware_detailed.rb +4 -6
- data/lib/scout_apm/instruments/mongoid.rb +24 -3
- data/lib/scout_apm/instruments/net_http.rb +7 -2
- data/lib/scout_apm/instruments/percentile_sampler.rb +36 -19
- data/lib/scout_apm/instruments/process/process_cpu.rb +3 -2
- data/lib/scout_apm/instruments/process/process_memory.rb +3 -3
- data/lib/scout_apm/instruments/resque.rb +40 -0
- data/lib/scout_apm/layaway.rb +67 -28
- data/lib/scout_apm/layer.rb +19 -59
- data/lib/scout_apm/layer_children_set.rb +77 -0
- data/lib/scout_apm/layer_converters/allocation_metric_converter.rb +5 -6
- data/lib/scout_apm/layer_converters/converter_base.rb +201 -14
- data/lib/scout_apm/layer_converters/database_converter.rb +55 -0
- data/lib/scout_apm/layer_converters/depth_first_walker.rb +22 -10
- data/lib/scout_apm/layer_converters/error_converter.rb +5 -7
- data/lib/scout_apm/layer_converters/find_layer_by_type.rb +34 -0
- data/lib/scout_apm/layer_converters/histograms.rb +14 -0
- data/lib/scout_apm/layer_converters/job_converter.rb +36 -50
- data/lib/scout_apm/layer_converters/metric_converter.rb +17 -19
- data/lib/scout_apm/layer_converters/request_queue_time_converter.rb +10 -12
- data/lib/scout_apm/layer_converters/slow_job_converter.rb +41 -115
- data/lib/scout_apm/layer_converters/slow_request_converter.rb +33 -117
- data/lib/scout_apm/limited_layer.rb +126 -0
- data/lib/scout_apm/metric_meta.rb +0 -5
- data/lib/scout_apm/metric_set.rb +9 -1
- data/lib/scout_apm/metric_stats.rb +7 -8
- data/lib/scout_apm/rack.rb +26 -0
- data/lib/scout_apm/remote/message.rb +23 -0
- data/lib/scout_apm/remote/recorder.rb +57 -0
- data/lib/scout_apm/remote/router.rb +49 -0
- data/lib/scout_apm/remote/server.rb +58 -0
- data/lib/scout_apm/reporter.rb +51 -15
- data/lib/scout_apm/request_histograms.rb +4 -0
- data/lib/scout_apm/request_manager.rb +2 -1
- data/lib/scout_apm/scored_item_set.rb +7 -0
- data/lib/scout_apm/serializers/db_query_serializer_to_json.rb +15 -0
- data/lib/scout_apm/serializers/histograms_serializer_to_json.rb +21 -0
- data/lib/scout_apm/serializers/payload_serializer.rb +10 -3
- data/lib/scout_apm/serializers/payload_serializer_to_json.rb +6 -6
- data/lib/scout_apm/serializers/slow_jobs_serializer_to_json.rb +2 -1
- data/lib/scout_apm/server_integrations/puma.rb +5 -2
- data/lib/scout_apm/slow_job_policy.rb +1 -10
- data/lib/scout_apm/slow_job_record.rb +6 -1
- data/lib/scout_apm/slow_request_policy.rb +1 -10
- data/lib/scout_apm/slow_transaction.rb +20 -2
- data/lib/scout_apm/store.rb +66 -12
- data/lib/scout_apm/synchronous_recorder.rb +26 -0
- data/lib/scout_apm/tracked_request.rb +136 -71
- data/lib/scout_apm/utils/active_record_metric_name.rb +8 -4
- data/lib/scout_apm/utils/backtrace_parser.rb +3 -3
- data/lib/scout_apm/utils/gzip_helper.rb +24 -0
- data/lib/scout_apm/utils/numbers.rb +14 -0
- data/lib/scout_apm/utils/scm.rb +14 -0
- data/lib/scout_apm/version.rb +1 -1
- data/scout_apm.gemspec +5 -4
- data/test/test_helper.rb +18 -0
- data/test/unit/config_test.rb +59 -8
- data/test/unit/db_query_metric_set_test.rb +56 -0
- data/test/unit/db_query_metric_stats_test.rb +113 -0
- data/test/unit/git_revision_test.rb +15 -0
- data/test/unit/histogram_test.rb +14 -0
- data/test/unit/instruments/net_http_test.rb +21 -0
- data/test/unit/instruments/percentile_sampler_test.rb +137 -0
- data/test/unit/layaway_test.rb +20 -0
- data/test/unit/layer_children_set_test.rb +88 -0
- data/test/unit/layer_converters/depth_first_walker_test.rb +66 -0
- data/test/unit/layer_converters/metric_converter_test.rb +22 -0
- data/test/unit/layer_converters/stubs.rb +33 -0
- data/test/unit/limited_layer_test.rb +53 -0
- data/test/unit/remote/test_message.rb +13 -0
- data/test/unit/remote/test_router.rb +33 -0
- data/test/unit/remote/test_server.rb +15 -0
- data/test/unit/serializers/payload_serializer_test.rb +3 -12
- data/test/unit/store_test.rb +66 -0
- data/test/unit/test_tracked_request.rb +87 -0
- data/test/unit/utils/active_record_metric_name_test.rb +8 -0
- data/test/unit/utils/backtrace_parser_test.rb +5 -0
- data/test/unit/utils/numbers_test.rb +15 -0
- data/test/unit/utils/scm.rb +17 -0
- metadata +125 -30
- data/ext/stacks/extconf.rb +0 -37
- data/ext/stacks/scout_atomics.h +0 -86
- data/ext/stacks/stacks.c +0 -811
- data/lib/scout_apm/capacity.rb +0 -57
- data/lib/scout_apm/deploy_integrations/capistrano_2.cap +0 -12
- data/lib/scout_apm/deploy_integrations/capistrano_2.rb +0 -83
- data/lib/scout_apm/deploy_integrations/capistrano_3.cap +0 -12
- data/lib/scout_apm/deploy_integrations/capistrano_3.rb +0 -88
- data/lib/scout_apm/instruments/delayed_job.rb +0 -57
- data/lib/scout_apm/serializers/deploy_serializer.rb +0 -16
- data/lib/scout_apm/trace_compactor.rb +0 -312
- data/lib/scout_apm/utils/fake_stacks.rb +0 -87
- data/tester.rb +0 -53
@@ -27,6 +27,14 @@ module ScoutApm
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
+
def model
|
31
|
+
parts.first
|
32
|
+
end
|
33
|
+
|
34
|
+
def normalized_operation
|
35
|
+
parse_operation
|
36
|
+
end
|
37
|
+
|
30
38
|
# For the layer lookup.
|
31
39
|
def hash
|
32
40
|
h = name.downcase.hash
|
@@ -44,10 +52,6 @@ module ScoutApm
|
|
44
52
|
|
45
53
|
private
|
46
54
|
|
47
|
-
def model
|
48
|
-
parts.first
|
49
|
-
end
|
50
|
-
|
51
55
|
def operation
|
52
56
|
if parts.length >= 2
|
53
57
|
parts[1].downcase
|
@@ -6,8 +6,8 @@ require 'scout_apm/environment'
|
|
6
6
|
module ScoutApm
|
7
7
|
module Utils
|
8
8
|
class BacktraceParser
|
9
|
-
|
10
|
-
APP_FRAMES =
|
9
|
+
# will return this many backtrace frames from the app stack.
|
10
|
+
APP_FRAMES = 8
|
11
11
|
|
12
12
|
attr_reader :call_stack
|
13
13
|
|
@@ -24,7 +24,7 @@ module ScoutApm
|
|
24
24
|
stack = []
|
25
25
|
call_stack.each do |c|
|
26
26
|
if m = c.match(@@app_dir_regex)
|
27
|
-
stack << m[1]
|
27
|
+
stack << ScoutApm::Utils::Scm.relative_scm_path(m[1])
|
28
28
|
break if stack.size == APP_FRAMES
|
29
29
|
end
|
30
30
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module ScoutApm
|
2
|
+
module Utils
|
3
|
+
# A simple wrapper around Ruby's built-in gzip support.
|
4
|
+
class GzipHelper
|
5
|
+
DEFAULT_GZIP_LEVEL = 5
|
6
|
+
|
7
|
+
attr_reader :level
|
8
|
+
|
9
|
+
def initialize(level = DEFAULT_GZIP_LEVEL)
|
10
|
+
@level = level
|
11
|
+
end
|
12
|
+
|
13
|
+
def deflate(str)
|
14
|
+
strio = StringIO.new
|
15
|
+
|
16
|
+
gz = Zlib::GzipWriter.new(strio, level)
|
17
|
+
gz.write str
|
18
|
+
gz.close
|
19
|
+
|
20
|
+
strio.string
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# Module for helping to deal with Source Code Management settings
|
2
|
+
module ScoutApm
|
3
|
+
module Utils
|
4
|
+
class Scm
|
5
|
+
# Takes an *already relative* path +path+
|
6
|
+
# Returns a relative path, prepending the configured +scm_subdirectory+ environment string
|
7
|
+
def self.relative_scm_path(path, scm_subdirectory = ScoutApm::Environment.instance.scm_subdirectory)
|
8
|
+
@@scm_subdirectory ||= scm_subdirectory.sub(/^\//, '')
|
9
|
+
@@scm_subdirectoy_blank ||= @@scm_subdirectory.empty?
|
10
|
+
@@scm_subdirectoy_blank ? path : File.join(@@scm_subdirectory, path)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/scout_apm/version.rb
CHANGED
data/scout_apm.gemspec
CHANGED
@@ -19,9 +19,7 @@ Gem::Specification.new do |s|
|
|
19
19
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
20
|
s.require_paths = ["lib","data"]
|
21
21
|
s.extensions << 'ext/allocations/extconf.rb'
|
22
|
-
s.extensions << 'ext/
|
23
|
-
|
24
|
-
s.add_runtime_dependency "rusage", '~> 0.2.0'
|
22
|
+
s.extensions << 'ext/rusage/extconf.rb'
|
25
23
|
|
26
24
|
s.add_development_dependency "minitest"
|
27
25
|
s.add_development_dependency 'mocha'
|
@@ -29,4 +27,7 @@ Gem::Specification.new do |s|
|
|
29
27
|
s.add_development_dependency "m"
|
30
28
|
s.add_development_dependency "simplecov"
|
31
29
|
s.add_development_dependency "rake-compiler"
|
32
|
-
|
30
|
+
s.add_development_dependency "addressable"
|
31
|
+
s.add_development_dependency "guard"
|
32
|
+
s.add_development_dependency "guard-minitest"
|
33
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -16,6 +16,14 @@ Kernel.module_eval do
|
|
16
16
|
def self.const_unset(const)
|
17
17
|
self.instance_eval { remove_const(const) }
|
18
18
|
end
|
19
|
+
|
20
|
+
def silence_warnings(&block)
|
21
|
+
warn_level = $VERBOSE
|
22
|
+
$VERBOSE = nil
|
23
|
+
result = block.call
|
24
|
+
$VERBOSE = warn_level
|
25
|
+
result
|
26
|
+
end
|
19
27
|
end
|
20
28
|
|
21
29
|
# A test helper class to create a temporary "configuration" we can control entirely purposes
|
@@ -83,3 +91,13 @@ class Minitest::Test
|
|
83
91
|
DATA_FILE_PATH = "#{DATA_FILE_DIR}/scout_apm.db"
|
84
92
|
end
|
85
93
|
|
94
|
+
|
95
|
+
module CustomAsserts
|
96
|
+
def assert_false(thing)
|
97
|
+
assert !thing
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
class Minitest::Test
|
102
|
+
include CustomAsserts
|
103
|
+
end
|
data/test/unit/config_test.rb
CHANGED
@@ -7,24 +7,75 @@ class ConfigTest < Minitest::Test
|
|
7
7
|
conf = ScoutApm::Config.without_file
|
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(
|
23
|
+
conf_file = File.expand_path('../../data/config_test_1.yml', __FILE__)
|
24
24
|
conf = ScoutApm::Config.with_file(conf_file)
|
25
25
|
|
26
|
-
assert_equal
|
27
|
-
assert_equal
|
26
|
+
assert_equal 'debug', conf.value('log_level')
|
27
|
+
assert_equal 'APM Test Conf (Production)', conf.value('name')
|
28
28
|
end
|
29
|
-
end
|
30
29
|
|
30
|
+
def test_loading_file_without_env_in_file
|
31
|
+
conf_file = File.expand_path("../../data/config_test_1.yml", __FILE__)
|
32
|
+
conf = ScoutApm::Config.with_file(conf_file, environment: "staging")
|
33
|
+
|
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?
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
require 'scout_apm/db_query_metric_set'
|
4
|
+
|
5
|
+
module ScoutApm
|
6
|
+
class DbQueryMetricSetTest < Minitest::Test
|
7
|
+
def test_hard_limit
|
8
|
+
config = make_fake_config(
|
9
|
+
'database_metric_limit' => 5, # The hard limit on db metrics
|
10
|
+
'database_metric_report_limit' => 2,)
|
11
|
+
set = DbQueryMetricSet.new(config)
|
12
|
+
set << fake_stat("a", 10)
|
13
|
+
set << fake_stat("b", 20)
|
14
|
+
set << fake_stat("c", 30)
|
15
|
+
set << fake_stat("d", 40)
|
16
|
+
set << fake_stat("e", 50)
|
17
|
+
set << fake_stat("f", 60)
|
18
|
+
|
19
|
+
assert_equal 5, set.metrics.size
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_report_limit
|
23
|
+
config = make_fake_config(
|
24
|
+
'database_metric_limit' => 50, # much larger max, uninterested in hitting it.
|
25
|
+
'database_metric_report_limit' => 2,)
|
26
|
+
set = DbQueryMetricSet.new(config)
|
27
|
+
set << fake_stat("a", 10)
|
28
|
+
set << fake_stat("b", 20)
|
29
|
+
set << fake_stat("c", 30)
|
30
|
+
set << fake_stat("d", 40)
|
31
|
+
set << fake_stat("e", 50)
|
32
|
+
set << fake_stat("f", 60)
|
33
|
+
|
34
|
+
assert_equal 2, set.metrics_to_report.size
|
35
|
+
assert_equal ["f","e"], set.metrics_to_report.map{|m| m.key}
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_combine
|
39
|
+
set1 = DbQueryMetricSet.new
|
40
|
+
set1 << fake_stat("a", 10)
|
41
|
+
set1 << fake_stat("b", 20)
|
42
|
+
set2 = DbQueryMetricSet.new
|
43
|
+
set2 << fake_stat("c", 10)
|
44
|
+
set2 << fake_stat("d", 20)
|
45
|
+
|
46
|
+
combined = set1.combine!(set2)
|
47
|
+
assert_equal ["a", "b", "c", "d"], combined.metrics.map{|_k, m| m.key}
|
48
|
+
end
|
49
|
+
|
50
|
+
def fake_stat(key, call_time)
|
51
|
+
OpenStruct.new(
|
52
|
+
key: key,
|
53
|
+
call_time: call_time)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
require 'scout_apm/db_query_metric_stats'
|
4
|
+
|
5
|
+
module ScoutApm
|
6
|
+
class DbQueryMetricStatsTest < Minitest::Test
|
7
|
+
def test_as_json_empty_stats
|
8
|
+
stat = build("table", "op", "Controller/public/index", 1, 10, 20)
|
9
|
+
|
10
|
+
assert_equal({
|
11
|
+
model_name: "table",
|
12
|
+
operation: "op",
|
13
|
+
call_count: 1,
|
14
|
+
transaction_count: 0,
|
15
|
+
scope: "Controller/public/index",
|
16
|
+
histogram: [[10.0, 1]],
|
17
|
+
|
18
|
+
max_call_time: 10.0,
|
19
|
+
min_call_time: 10.0,
|
20
|
+
call_time: 10.0,
|
21
|
+
|
22
|
+
max_rows_returned: 20,
|
23
|
+
min_rows_returned: 20,
|
24
|
+
rows_returned: 20,
|
25
|
+
}, stat.as_json)
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_increment_transaction_count
|
29
|
+
stat = build()
|
30
|
+
assert_equal 0, stat.transaction_count
|
31
|
+
|
32
|
+
stat.increment_transaction_count!
|
33
|
+
|
34
|
+
assert_equal 1, stat.transaction_count
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_key_name
|
38
|
+
stat = build("User", "find", "Controller/public/index")
|
39
|
+
assert_equal ["User", "find", "Controller/public/index"], stat.key
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_combine_min_call_time_picks_smallest
|
43
|
+
stat1, stat2 = build_pair
|
44
|
+
assert_equal 5.1, stat1.combine!(stat2).min_call_time
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_combine_max_call_time_picks_largest
|
48
|
+
stat1, stat2 = build_pair
|
49
|
+
assert_equal 8.2, stat1.combine!(stat2).max_call_time
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_combine_call_counts_adds
|
53
|
+
stat1, stat2 = build_pair
|
54
|
+
assert_equal 5, stat1.combine!(stat2).call_count
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_combine_transaction_count_adds
|
58
|
+
stat1, stat2 = build_pair
|
59
|
+
2.times { stat1.increment_transaction_count! }
|
60
|
+
3.times { stat2.increment_transaction_count! }
|
61
|
+
|
62
|
+
assert_equal 5, stat1.combine!(stat2).call_count
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_combine_doesnt_merge_with_self
|
66
|
+
stat = build
|
67
|
+
merged = stat.combine!(stat)
|
68
|
+
|
69
|
+
assert_equal DEFAULTS[:call_count], merged.call_count
|
70
|
+
assert_equal DEFAULTS[:call_time], merged.call_time
|
71
|
+
assert_equal DEFAULTS[:rows_returned], merged.rows_returned
|
72
|
+
end
|
73
|
+
|
74
|
+
# A.combine!(B) should be the the same as B.combine!(A)
|
75
|
+
# Have to be a bit careful, since combine! is destructive, so make two pairs
|
76
|
+
# with same data to do both sides, then check that they result in the same
|
77
|
+
# answer
|
78
|
+
[:transaction_count, :call_count, :rows_returned, :min_rows_returned, :max_rows_returned, :max_call_time, :min_call_time].each do |attr|
|
79
|
+
define_method :"test_combine_#{attr}_is_symmetric" do
|
80
|
+
stat1_a, stat2_a = build_pair
|
81
|
+
stat1_b, stat2_b = build_pair
|
82
|
+
merged_a = stat1_a.combine!(stat2_a)
|
83
|
+
merged_b = stat2_b.combine!(stat1_b)
|
84
|
+
|
85
|
+
assert_equal merged_a.send(attr), merged_b.send(attr)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
#############
|
90
|
+
# Helpers #
|
91
|
+
#############
|
92
|
+
DEFAULTS = {
|
93
|
+
call_count: 1,
|
94
|
+
call_time: 10.0,
|
95
|
+
rows_returned: 20,
|
96
|
+
}
|
97
|
+
|
98
|
+
def build(model_name="User",
|
99
|
+
operation="find",
|
100
|
+
scope="Controller/public/index",
|
101
|
+
call_count=DEFAULTS[:call_count],
|
102
|
+
call_time=DEFAULTS[:call_time],
|
103
|
+
rows_returned=DEFAULTS[:rows_returned])
|
104
|
+
DbQueryMetricStats.new(model_name, operation, scope, call_count, call_time, rows_returned)
|
105
|
+
end
|
106
|
+
|
107
|
+
def build_pair
|
108
|
+
stat1 = build("table", "op", "Controller/public/index", 2, 5.1, 10)
|
109
|
+
stat2 = build("table", "op", "Controller/public/index", 3, 8.2, 20)
|
110
|
+
[stat1, stat2]
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
require 'scout_apm/git_revision'
|
4
|
+
|
5
|
+
class GitRevisionTest < Minitest::Test
|
6
|
+
# TODO - other tests that would be nice:
|
7
|
+
# * ensure we only detect once, on initialize.
|
8
|
+
# * tests for reading cap files
|
9
|
+
|
10
|
+
def test_sha_from_heroku
|
11
|
+
ENV['HEROKU_SLUG_COMMIT'] = 'heroku_slug'
|
12
|
+
revision = ScoutApm::GitRevision.new
|
13
|
+
assert_equal 'heroku_slug', revision.sha
|
14
|
+
end
|
15
|
+
end
|
data/test/unit/histogram_test.rb
CHANGED
@@ -79,6 +79,20 @@ 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
|
+
|
82
96
|
def test_mean
|
83
97
|
hist = ScoutApm::NumericHistogram.new(5)
|
84
98
|
10.times {
|