scout_apm 3.0.0.pre20 → 3.0.0.pre21
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 +4 -4
- data/.rubocop.yml +8 -3
- data/.travis.yml +14 -0
- data/CHANGELOG.markdown +12 -0
- data/Gemfile +8 -0
- data/README.markdown +2 -0
- data/lib/scout_apm.rb +1 -0
- data/lib/scout_apm/agent/preconditions.rb +15 -3
- data/lib/scout_apm/instruments/middleware_detailed.rb +1 -1
- data/lib/scout_apm/tracer.rb +30 -26
- data/lib/scout_apm/tracked_request.rb +17 -0
- data/lib/scout_apm/transaction.rb +13 -0
- data/lib/scout_apm/version.rb +1 -1
- data/scout_apm.gemspec +8 -4
- data/test/test_helper.rb +21 -0
- data/test/unit/config_test.rb +1 -1
- data/test/unit/db_query_metric_set_test.rb +10 -6
- data/test/unit/db_query_metric_stats_test.rb +17 -17
- data/test/unit/histogram_test.rb +11 -4
- data/test/unit/ignored_uris_test.rb +1 -1
- data/test/unit/instruments/net_http_test.rb +7 -2
- data/test/unit/layer_converters/depth_first_walker_test.rb +4 -0
- data/test/unit/layer_converters/metric_converter_test.rb +1 -1
- data/test/unit/layer_converters/stubs.rb +2 -2
- data/test/unit/limited_layer_test.rb +1 -1
- data/test/unit/logger_test.rb +1 -1
- data/test/unit/serializers/payload_serializer_test.rb +4 -3
- data/test/unit/sql_sanitizer_test.rb +6 -0
- data/test/unit/tracer_test.rb +76 -0
- data/test/unit/{test_tracked_request.rb → tracked_request_test.rb} +33 -13
- data/test/unit/transaction_test.rb +14 -0
- data/test/unit/utils/backtrace_parser_test.rb +1 -1
- data/test/unit/utils/numbers_test.rb +1 -1
- data/test/unit/utils/scm.rb +2 -2
- metadata +29 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eb5a7880c0007cdc98449e7598022481be64b83f
|
4
|
+
data.tar.gz: b195f2ea2a704b97be089d38af6cb84145d96856
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3d181d12bf746066430840488485e2e96370a33ebfc6db4b7e6c25d9cb07763d380867bf6aabf3595044451ba1a657a6d03b1d739b567e430da431f2de854a59
|
7
|
+
data.tar.gz: f4149e4757f16f481ca9e9d4a3ababc1ec9ba3cb66718bffe2de207ae12b01f56fa81d0f14cf0d1b3348d7c8cf97d28809a6ec75ad6bdbb1a3af573a2de684bd
|
data/.rubocop.yml
CHANGED
@@ -1,8 +1,13 @@
|
|
1
|
+
# Disable all cops by default
|
2
|
+
AllCops:
|
3
|
+
DisabledByDefault: true
|
4
|
+
|
1
5
|
# 80 is stifling, especially with a few levels of nesting before we even start.
|
2
6
|
# So bump it to 100 to keep really long lines from creeping in.
|
3
7
|
Metrics/LineLength:
|
8
|
+
Enabled: false
|
4
9
|
Max: 100
|
5
10
|
|
6
|
-
Style/
|
7
|
-
|
8
|
-
|
11
|
+
Style/HashSyntax:
|
12
|
+
Enabled: true
|
13
|
+
EnforcedStyle: hash_rockets
|
data/.travis.yml
ADDED
data/CHANGELOG.markdown
CHANGED
@@ -2,6 +2,18 @@
|
|
2
2
|
|
3
3
|
* ScoutProf BETA
|
4
4
|
|
5
|
+
# 2.4.9
|
6
|
+
|
7
|
+
* ScoutApm::Transaction#rename and #ignore API
|
8
|
+
* Explicit custom instrumentation with ScoutApm::Tracer#instrument blocks,
|
9
|
+
without needing to include a module
|
10
|
+
* Quieter logging in normal startup cases
|
11
|
+
* Upgraded testing infrastructure
|
12
|
+
|
13
|
+
# 2.4.8
|
14
|
+
|
15
|
+
* Fix issue with detailed middleware instrumentation
|
16
|
+
|
5
17
|
# 2.4.7
|
6
18
|
|
7
19
|
* Fix issue recording backtraces
|
data/Gemfile
CHANGED
@@ -2,3 +2,11 @@ source "http://rubygems.org"
|
|
2
2
|
|
3
3
|
# Specify your gem's dependencies in scout_apm.gemspec
|
4
4
|
gemspec
|
5
|
+
|
6
|
+
# Pin development dependencies more conservatively for Ruby 1.8.7
|
7
|
+
if RUBY_VERSION <= "1.8.7"
|
8
|
+
gem "activesupport", "~> 3.2"
|
9
|
+
gem "i18n", "~> 0.6.11"
|
10
|
+
gem "pry", "~> 0.9.12"
|
11
|
+
gem "rake", "~> 10.5"
|
12
|
+
end
|
data/README.markdown
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# ScoutApm Ruby Agent
|
2
2
|
|
3
|
+
[](https://travis-ci.org/scoutapp/scout_apm_ruby)
|
4
|
+
|
3
5
|
A Ruby gem for detailed Rails application performance analysis. Metrics are
|
4
6
|
reported to [Scout](https://scoutapp.com), a hosted application monitoring
|
5
7
|
service.
|
data/lib/scout_apm.rb
CHANGED
@@ -129,6 +129,7 @@ require 'scout_apm/db_query_metric_set'
|
|
129
129
|
require 'scout_apm/store'
|
130
130
|
require 'scout_apm/fake_store'
|
131
131
|
require 'scout_apm/tracer'
|
132
|
+
require 'scout_apm/transaction'
|
132
133
|
require 'scout_apm/context'
|
133
134
|
require 'scout_apm/instant_reporting'
|
134
135
|
require 'scout_apm/trace_compactor'
|
@@ -4,20 +4,24 @@ module ScoutApm
|
|
4
4
|
# The preconditions here must be a 2 element hash, with :message and :check.
|
5
5
|
# message: Proc that takes the environment, and returns a string
|
6
6
|
# check: Proc that takes an AgentContext and returns true if precondition was met, if false, we shouldn't start.
|
7
|
+
# severity: Severity of the log message (one of: :debug, :info, :warn, :error or :fatal)
|
7
8
|
PRECONDITIONS = [
|
8
9
|
PRECONDITION_ENABLED = {
|
9
10
|
:message => proc {|environ| "Monitoring isn't enabled for the [#{environ.env}] environment." },
|
10
11
|
:check => proc { |context| context.config.value('monitor') },
|
12
|
+
:severity => :info,
|
11
13
|
},
|
12
14
|
|
13
15
|
PRECONDITION_APP_NAME = {
|
14
16
|
:message => proc {|environ| "An application name could not be determined. Specify the :name value in scout_apm.yml." },
|
15
17
|
:check => proc { |context| context.environment.application_name },
|
18
|
+
:severity => :warn,
|
16
19
|
},
|
17
20
|
|
18
21
|
PRECONDITION_INTERACTIVE = {
|
19
22
|
:message => proc {|environ| "Agent attempting to load in interactive mode." },
|
20
23
|
:check => proc { |context| ! context.environment.interactive? },
|
24
|
+
:severity => :info,
|
21
25
|
},
|
22
26
|
|
23
27
|
PRECONDITION_DETECTED_SERVER = {
|
@@ -28,16 +32,19 @@ module ScoutApm
|
|
28
32
|
|
29
33
|
!app_server_missing && !background_job_missing
|
30
34
|
},
|
35
|
+
:severity => :info,
|
31
36
|
},
|
32
37
|
|
33
38
|
PRECONDITION_ALREADY_STARTED = {
|
34
39
|
:message => proc {|environ| "Already started agent." },
|
35
40
|
:check => proc { |context| !context.started? },
|
41
|
+
:severity => :info,
|
36
42
|
},
|
37
43
|
|
38
44
|
PRECONDITION_OLD_SCOUT_RAILS = {
|
39
45
|
:message => proc {|environ| "ScoutAPM is incompatible with the old Scout Rails plugin. Please remove scout_rails from your Gemfile" },
|
40
46
|
:check => proc { !defined?(::ScoutRails) },
|
47
|
+
:severity => :warn,
|
41
48
|
},
|
42
49
|
]
|
43
50
|
|
@@ -45,13 +52,18 @@ module ScoutApm
|
|
45
52
|
@check_result ||=
|
46
53
|
begin
|
47
54
|
failed_preconditions = PRECONDITIONS.inject(Array.new) { |errors, condition|
|
48
|
-
|
49
|
-
|
55
|
+
unless condition[:check].call(context)
|
56
|
+
errors << {
|
57
|
+
:severity => condition[:severity],
|
58
|
+
:message => condition[:message].call(context.environment),
|
59
|
+
}
|
60
|
+
end
|
61
|
+
|
50
62
|
errors
|
51
63
|
}
|
52
64
|
|
53
65
|
if failed_preconditions.any?
|
54
|
-
failed_preconditions.each {|
|
66
|
+
failed_preconditions.each {|error| context.logger.send(error[:severity], error[:message]) }
|
55
67
|
force? # if forced, return true anyway
|
56
68
|
else
|
57
69
|
# No errors, we met preconditions
|
@@ -30,7 +30,7 @@ module ScoutApm
|
|
30
30
|
|
31
31
|
ActionDispatch::MiddlewareStack::Middleware.class_eval do
|
32
32
|
def build(app)
|
33
|
-
logger.info("
|
33
|
+
ScoutApm::Agent.instance.context.logger.info("Instrumenting Middleware #{klass.name}")
|
34
34
|
new_mw = klass.new(app, *args, &block)
|
35
35
|
MiddlewareWrapper.new(new_mw, klass.name)
|
36
36
|
end
|
data/lib/scout_apm/tracer.rb
CHANGED
@@ -12,31 +12,36 @@ module ScoutApm
|
|
12
12
|
klass.extend ClassMethods
|
13
13
|
end
|
14
14
|
|
15
|
+
# Type: the Layer type - "View" or similar
|
16
|
+
# Name: specific name - "users/_gravatar". The object must respond to "#to_s". This allows us to be more efficient - in most cases, the metric name isn't needed unless we are processing a slow transaction.
|
17
|
+
# A Block: The code to be instrumented
|
18
|
+
#
|
19
|
+
# Options:
|
20
|
+
# * :ignore_children - will not instrument any method calls beneath this call. Example use case: InfluxDB uses Net::HTTP, which is instrumented. However, we can provide more specific data if we know we're doing an influx call, so we'd rather just instrument the Influx call and ignore Net::HTTP.
|
21
|
+
# when rendering the transaction tree in the UI.
|
22
|
+
# * :desc - Additional capture, SQL, or HTTP url or similar
|
23
|
+
# * :scope - set to true if you want to make this layer a subscope
|
24
|
+
def self.instrument(type, name, options={}) # Takes a block
|
25
|
+
layer = ScoutApm::Layer.new(type, name)
|
26
|
+
layer.desc = options[:desc] if options[:desc]
|
27
|
+
layer.subscopable! if options[:scope]
|
28
|
+
|
29
|
+
req = ScoutApm::RequestManager.lookup
|
30
|
+
req.start_layer(layer)
|
31
|
+
req.ignore_children! if options[:ignore_children]
|
32
|
+
|
33
|
+
begin
|
34
|
+
yield
|
35
|
+
ensure
|
36
|
+
req.acknowledge_children! if options[:ignore_children]
|
37
|
+
req.stop_layer
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
15
41
|
module ClassMethods
|
16
|
-
#
|
17
|
-
|
18
|
-
|
19
|
-
#
|
20
|
-
# Options:
|
21
|
-
# * :ignore_children - will not instrument any method calls beneath this call. Example use case: InfluxDB uses Net::HTTP, which is instrumented. However, we can provide more specific data if we know we're doing an influx call, so we'd rather just instrument the Influx call and ignore Net::HTTP.
|
22
|
-
# when rendering the transaction tree in the UI.
|
23
|
-
# * :desc - Additional capture, SQL, or HTTP url or similar
|
24
|
-
# * :scope - set to true if you want to make this layer a subscope
|
25
|
-
def instrument(type, name, options={}) # Takes a block
|
26
|
-
layer = ScoutApm::Layer.new(type, name)
|
27
|
-
layer.desc = options[:desc] if options[:desc]
|
28
|
-
layer.subscopable! if options[:scope]
|
29
|
-
|
30
|
-
req = ScoutApm::RequestManager.lookup
|
31
|
-
req.start_layer(layer)
|
32
|
-
req.ignore_children! if options[:ignore_children]
|
33
|
-
|
34
|
-
begin
|
35
|
-
yield
|
36
|
-
ensure
|
37
|
-
req.acknowledge_children! if options[:ignore_children]
|
38
|
-
req.stop_layer
|
39
|
-
end
|
42
|
+
# See ScoutApm::Tracer.instrument
|
43
|
+
def instrument(type, name, options={}, &block)
|
44
|
+
ScoutApm::Tracer.instrument(type, name, options, &block)
|
40
45
|
end
|
41
46
|
|
42
47
|
# Wraps a method in a call to #instrument via aggressive monkey patching.
|
@@ -85,7 +90,6 @@ module ScoutApm
|
|
85
90
|
end
|
86
91
|
|
87
92
|
def _instrumented_method_string(instrumented_name, uninstrumented_name, type, name, options={})
|
88
|
-
klass = (self === Module) ? "self" : "self.class"
|
89
93
|
method_str = <<-EOF
|
90
94
|
def #{instrumented_name}(*args, &block)
|
91
95
|
name = begin
|
@@ -95,7 +99,7 @@ module ScoutApm
|
|
95
99
|
"Unknown"
|
96
100
|
end
|
97
101
|
|
98
|
-
|
102
|
+
::ScoutApm::Tracer.instrument( "#{type}",
|
99
103
|
name,
|
100
104
|
{:scope => #{options[:scope] || false}}
|
101
105
|
) do
|
@@ -38,6 +38,10 @@ module ScoutApm
|
|
38
38
|
# An object that responds to `record!(TrackedRequest)` to store this tracked request
|
39
39
|
attr_reader :recorder
|
40
40
|
|
41
|
+
# If specified, an override for the name of the request. If unspecified,
|
42
|
+
# the name is determined from the name of the Controller or Job layer.
|
43
|
+
attr_accessor :name_override
|
44
|
+
|
41
45
|
# When we see these layers, it means a real request is going through the
|
42
46
|
# system. We toggle a flag to turn on some slightly more expensive
|
43
47
|
# instrumentation (backtrace collection and the like) that would be too
|
@@ -294,6 +298,8 @@ module ScoutApm
|
|
294
298
|
# Bail out early if the user asked us to ignore this uri
|
295
299
|
return if @agent_context.ignored_uris.ignore?(annotations[:uri])
|
296
300
|
|
301
|
+
apply_name_override
|
302
|
+
|
297
303
|
converters = [
|
298
304
|
LayerConverters::Histograms,
|
299
305
|
LayerConverters::MetricConverter,
|
@@ -491,5 +497,16 @@ module ScoutApm
|
|
491
497
|
@recorder = @agent_context.recorder
|
492
498
|
@store = @agent_context.store
|
493
499
|
end
|
500
|
+
|
501
|
+
private
|
502
|
+
|
503
|
+
def apply_name_override
|
504
|
+
return unless name_override
|
505
|
+
|
506
|
+
scope_layer = layer_finder.scope
|
507
|
+
if scope_layer
|
508
|
+
scope_layer.name = name_override
|
509
|
+
end
|
510
|
+
end
|
494
511
|
end
|
495
512
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module ScoutApm
|
2
|
+
module Transaction
|
3
|
+
# Ignores the current request
|
4
|
+
def self.ignore!
|
5
|
+
::ScoutApm::RequestManager.lookup.ignore_request!
|
6
|
+
end
|
7
|
+
|
8
|
+
# Renames the last Controller or Job layer
|
9
|
+
def self.rename(name)
|
10
|
+
::ScoutApm::RequestManager.lookup.name_override = name
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/scout_apm/version.rb
CHANGED
data/scout_apm.gemspec
CHANGED
@@ -23,13 +23,17 @@ Gem::Specification.new do |s|
|
|
23
23
|
s.extensions << 'ext/rusage/extconf.rb'
|
24
24
|
|
25
25
|
s.add_development_dependency "minitest"
|
26
|
-
s.add_development_dependency
|
26
|
+
s.add_development_dependency "mocha"
|
27
27
|
s.add_development_dependency "pry"
|
28
|
-
s.add_development_dependency "m"
|
29
28
|
s.add_development_dependency "simplecov"
|
30
29
|
s.add_development_dependency "rake-compiler"
|
31
30
|
s.add_development_dependency "addressable"
|
32
|
-
s.add_development_dependency "guard"
|
33
|
-
s.add_development_dependency "guard-minitest"
|
34
31
|
s.add_development_dependency "activesupport"
|
32
|
+
|
33
|
+
if RUBY_VERSION >= "1.9.3"
|
34
|
+
s.add_development_dependency "rubocop"
|
35
|
+
s.add_development_dependency "guard"
|
36
|
+
s.add_development_dependency "guard-minitest"
|
37
|
+
s.add_development_dependency "m"
|
38
|
+
end
|
35
39
|
end
|
data/test/test_helper.rb
CHANGED
@@ -68,6 +68,7 @@ end
|
|
68
68
|
# Helpers available to all tests
|
69
69
|
class Minitest::Test
|
70
70
|
def setup
|
71
|
+
Thread.current[:scout_request] = nil
|
71
72
|
reopen_logger
|
72
73
|
FileUtils.mkdir_p(DATA_FILE_DIR)
|
73
74
|
ENV['SCOUT_DATA_FILE'] = DATA_FILE_PATH
|
@@ -106,6 +107,26 @@ class Minitest::Test
|
|
106
107
|
DATA_FILE_PATH = "#{DATA_FILE_DIR}/scout_apm.db"
|
107
108
|
end
|
108
109
|
|
110
|
+
class FakeRecorder
|
111
|
+
attr_reader :requests
|
112
|
+
|
113
|
+
def initialize
|
114
|
+
@requests = []
|
115
|
+
end
|
116
|
+
|
117
|
+
def start
|
118
|
+
# nothing to do
|
119
|
+
self
|
120
|
+
end
|
121
|
+
|
122
|
+
def stop
|
123
|
+
# nothing to do
|
124
|
+
end
|
125
|
+
|
126
|
+
def record!(request)
|
127
|
+
@requests << request
|
128
|
+
end
|
129
|
+
end
|
109
130
|
|
110
131
|
module CustomAsserts
|
111
132
|
def assert_false(thing)
|
data/test/unit/config_test.rb
CHANGED
@@ -33,7 +33,7 @@ class ConfigTest < Minitest::Test
|
|
33
33
|
|
34
34
|
def test_loading_file_without_env_in_file
|
35
35
|
conf_file = File.expand_path("../../data/config_test_1.yml", __FILE__)
|
36
|
-
conf = ScoutApm::Config.with_file(@context, conf_file, environment
|
36
|
+
conf = ScoutApm::Config.with_file(@context, conf_file, :environment => "staging")
|
37
37
|
|
38
38
|
assert_equal "info", conf.value('log_level') # the default value
|
39
39
|
assert_nil nil, conf.value('name') # the default value
|
@@ -7,7 +7,8 @@ class DbQueryMetricSetTest < Minitest::Test
|
|
7
7
|
def test_hard_limit
|
8
8
|
config = make_fake_config(
|
9
9
|
'database_metric_limit' => 5, # The hard limit on db metrics
|
10
|
-
'database_metric_report_limit' => 2
|
10
|
+
'database_metric_report_limit' => 2
|
11
|
+
)
|
11
12
|
context = ScoutApm::AgentContext.new().tap{|c| c.config = config }
|
12
13
|
set = DbQueryMetricSet.new(context)
|
13
14
|
|
@@ -24,7 +25,8 @@ class DbQueryMetricSetTest < Minitest::Test
|
|
24
25
|
def test_report_limit
|
25
26
|
config = make_fake_config(
|
26
27
|
'database_metric_limit' => 50, # much larger max, uninterested in hitting it.
|
27
|
-
'database_metric_report_limit' => 2
|
28
|
+
'database_metric_report_limit' => 2
|
29
|
+
)
|
28
30
|
context = ScoutApm::AgentContext.new().tap{|c| c.config = config }
|
29
31
|
set = DbQueryMetricSet.new(context)
|
30
32
|
set << fake_stat("a", 10)
|
@@ -41,7 +43,8 @@ class DbQueryMetricSetTest < Minitest::Test
|
|
41
43
|
def test_combine
|
42
44
|
config = make_fake_config(
|
43
45
|
'database_metric_limit' => 5, # The hard limit on db metrics
|
44
|
-
'database_metric_report_limit' => 2
|
46
|
+
'database_metric_report_limit' => 2
|
47
|
+
)
|
45
48
|
context = ScoutApm::AgentContext.new().tap{|c| c.config = config }
|
46
49
|
set1 = DbQueryMetricSet.new(context)
|
47
50
|
set1 << fake_stat("a", 10)
|
@@ -51,13 +54,14 @@ class DbQueryMetricSetTest < Minitest::Test
|
|
51
54
|
set2 << fake_stat("d", 20)
|
52
55
|
|
53
56
|
combined = set1.combine!(set2)
|
54
|
-
assert_equal ["a", "b", "c", "d"], combined.metrics.map{|_k, m| m.key}
|
57
|
+
assert_equal ["a", "b", "c", "d"], combined.metrics.map{|_k, m| m.key}.sort
|
55
58
|
end
|
56
59
|
|
57
60
|
def fake_stat(key, call_time)
|
58
61
|
OpenStruct.new(
|
59
|
-
key
|
60
|
-
call_time
|
62
|
+
:key => key,
|
63
|
+
:call_time => call_time
|
64
|
+
)
|
61
65
|
end
|
62
66
|
end
|
63
67
|
end
|
@@ -8,20 +8,20 @@ class DbQueryMetricStatsTest < Minitest::Test
|
|
8
8
|
stat = build("table", "op", "Controller/public/index", 1, 10, 20)
|
9
9
|
|
10
10
|
assert_equal({
|
11
|
-
model_name
|
12
|
-
operation
|
13
|
-
call_count
|
14
|
-
transaction_count
|
15
|
-
scope
|
16
|
-
histogram
|
17
|
-
|
18
|
-
max_call_time
|
19
|
-
min_call_time
|
20
|
-
call_time
|
21
|
-
|
22
|
-
max_rows_returned
|
23
|
-
min_rows_returned
|
24
|
-
rows_returned
|
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
25
|
}, stat.as_json)
|
26
26
|
end
|
27
27
|
|
@@ -90,9 +90,9 @@ class DbQueryMetricStatsTest < Minitest::Test
|
|
90
90
|
# Helpers #
|
91
91
|
#############
|
92
92
|
DEFAULTS = {
|
93
|
-
call_count
|
94
|
-
call_time
|
95
|
-
rows_returned
|
93
|
+
:call_count => 1,
|
94
|
+
:call_time => 10.0,
|
95
|
+
:rows_returned => 20,
|
96
96
|
}
|
97
97
|
|
98
98
|
def build(model_name="User",
|
data/test/unit/histogram_test.rb
CHANGED
@@ -35,8 +35,8 @@ class HistogramTest < Minitest::Test
|
|
35
35
|
end
|
36
36
|
}
|
37
37
|
|
38
|
-
assert_equal 1.5, hist.quantile(0)
|
39
|
-
assert_equal 9.5, hist.quantile(100)
|
38
|
+
assert_equal 1.5, round(hist.quantile(0), 1)
|
39
|
+
assert_equal 9.5, round(hist.quantile(100), 1)
|
40
40
|
end
|
41
41
|
|
42
42
|
def test_combine
|
@@ -55,8 +55,8 @@ class HistogramTest < Minitest::Test
|
|
55
55
|
}
|
56
56
|
|
57
57
|
combined = hist1.combine!(hist2)
|
58
|
-
assert_equal 1.5, combined.quantile(0)
|
59
|
-
assert_equal 9.5, combined.quantile(100)
|
58
|
+
assert_equal 1.5, round(combined.quantile(0), 1)
|
59
|
+
assert_equal 9.5, round(combined.quantile(100), 1)
|
60
60
|
assert_equal 200, combined.total
|
61
61
|
end
|
62
62
|
|
@@ -103,5 +103,12 @@ class HistogramTest < Minitest::Test
|
|
103
103
|
|
104
104
|
assert_equal 5.5, hist.mean
|
105
105
|
end
|
106
|
+
|
107
|
+
private
|
108
|
+
|
109
|
+
# Ruby 1.8 compatible round with precision
|
110
|
+
def round(number, precision)
|
111
|
+
((number * 10**precision).round.to_f) / (10**precision)
|
112
|
+
end
|
106
113
|
end
|
107
114
|
|
@@ -2,7 +2,7 @@ require 'test_helper'
|
|
2
2
|
|
3
3
|
require 'scout_apm/instruments/net_http'
|
4
4
|
|
5
|
-
require 'addressable'
|
5
|
+
require 'addressable/uri'
|
6
6
|
|
7
7
|
class NetHttpTest < Minitest::Test
|
8
8
|
def setup
|
@@ -11,7 +11,12 @@ class NetHttpTest < Minitest::Test
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def test_request_scout_description_for_uri
|
14
|
-
|
14
|
+
if RUBY_VERSION <= '1.9.3'
|
15
|
+
req = Net::HTTP::Get.new('/here')
|
16
|
+
else
|
17
|
+
req = Net::HTTP::Get.new(URI('http://example.org/here'))
|
18
|
+
end
|
19
|
+
|
15
20
|
assert_equal '/here', Net::HTTP.new('').request_scout_description(req)
|
16
21
|
end
|
17
22
|
|
@@ -25,6 +25,10 @@ class DepthFirstWalkerTest < Minitest::Test
|
|
25
25
|
# / \
|
26
26
|
# F G
|
27
27
|
def test_walk_interesting_tree
|
28
|
+
# The test could be rewritten to support 1.8.7, but it would likely be much
|
29
|
+
# harder to read.
|
30
|
+
skip "Lack of set ordering in Ruby 1.8.7 prevents this test from running correctly" if RUBY_VERSION.start_with?("1.8.")
|
31
|
+
|
28
32
|
calls = []
|
29
33
|
a = Layer.new("A", "x")
|
30
34
|
b = Layer.new("B", "x")
|
@@ -4,7 +4,7 @@
|
|
4
4
|
module ScoutApm
|
5
5
|
module LayerConverters
|
6
6
|
module Stubs
|
7
|
-
def faux_walker(subscope_stubs
|
7
|
+
def faux_walker(subscope_stubs = true)
|
8
8
|
@w ||= stub
|
9
9
|
|
10
10
|
if subscope_stubs && !@w_set_subscope_stubs
|
@@ -21,7 +21,7 @@ module ScoutApm
|
|
21
21
|
|
22
22
|
def faux_layer_finder
|
23
23
|
@layer_finder ||= stub
|
24
|
-
@layer_finder.stubs(scope
|
24
|
+
@layer_finder.stubs(:scope => stub)
|
25
25
|
@layer_finder
|
26
26
|
end
|
27
27
|
|
data/test/unit/logger_test.rb
CHANGED
@@ -5,7 +5,7 @@ require 'scout_apm/logger'
|
|
5
5
|
|
6
6
|
class LoggerTest < Minitest::Test
|
7
7
|
def setup
|
8
|
-
@env_root = Pathname.new(File.dirname(__FILE__)
|
8
|
+
@env_root = Pathname.new(File.expand_path(File.join(File.dirname(__FILE__), "..", "..")))
|
9
9
|
FileUtils.mkdir_p(@env_root + "log")
|
10
10
|
end
|
11
11
|
|
@@ -46,7 +46,7 @@ class PayloadSerializerTest < Minitest::Test
|
|
46
46
|
stats.min_call_time = 0.034881757
|
47
47
|
stats.sum_of_squares = 0.007382350213180609
|
48
48
|
stats.total_call_time = 0.113403176
|
49
|
-
stats.total_exclusive_time = 0.
|
49
|
+
stats.total_exclusive_time = 0.078132088
|
50
50
|
}
|
51
51
|
}
|
52
52
|
payload = ScoutApm::Serializers::PayloadSerializerToJson.serialize({}, metrics, {}, [], [], [], {})
|
@@ -83,11 +83,12 @@ class PayloadSerializerTest < Minitest::Test
|
|
83
83
|
"max_call_time" => 0.078521419,
|
84
84
|
"min_call_time" => 0.034881757,
|
85
85
|
"total_call_time" => 0.113403176,
|
86
|
-
"total_exclusive_time" => 0.
|
86
|
+
"total_exclusive_time" => 0.078132088,
|
87
87
|
"traces" => []
|
88
88
|
}
|
89
89
|
]
|
90
|
-
assert_equal formatted_metrics,
|
90
|
+
assert_equal formatted_metrics,
|
91
|
+
JSON.parse(payload)["metrics"].sort_by { |m| m["key"]["bucket"] }
|
91
92
|
end
|
92
93
|
|
93
94
|
def test_escapes_json_quotes
|
@@ -10,6 +10,8 @@ module ScoutApm
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def test_postgres_simple_select_of_first
|
13
|
+
skip "Broken on Ruby 1.8.7 because regular expressions do not support look-behinds" if RUBY_VERSION.start_with?("1.8.")
|
14
|
+
|
13
15
|
sql = %q|SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT 1|
|
14
16
|
ss = SqlSanitizer.new(sql).tap{ |it| it.database_engine = :postgres }
|
15
17
|
assert_equal %q|SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT 1|, ss.to_s
|
@@ -55,6 +57,8 @@ module ScoutApm
|
|
55
57
|
end
|
56
58
|
|
57
59
|
def test_mysql_limit
|
60
|
+
skip "Broken on Ruby 1.8.7 because regular expressions do not support look-behinds" if RUBY_VERSION.start_with?("1.8.")
|
61
|
+
|
58
62
|
sql = %q|SELECT `blogs`.* FROM `blogs` ORDER BY `blogs`.`id` ASC LIMIT 1|
|
59
63
|
ss = SqlSanitizer.new(sql).tap{ |it| it.database_engine = :mysql }
|
60
64
|
assert_equal %q|SELECT `blogs`.* FROM `blogs` ORDER BY `blogs`.`id` ASC LIMIT 1|, ss.to_s
|
@@ -86,6 +90,8 @@ module ScoutApm
|
|
86
90
|
end
|
87
91
|
|
88
92
|
def test_scrubs_invalid_encoding
|
93
|
+
skip "Ruby 1.8.7 has no concept of encoding" if RUBY_VERSION.start_with?("1.8.")
|
94
|
+
|
89
95
|
sql = "SELECT `blogs`.* FROM `blogs` WHERE (title = 'a\255c')".force_encoding('UTF-8')
|
90
96
|
assert_equal false, sql.valid_encoding?
|
91
97
|
ss = SqlSanitizer.new(sql).tap{ |it| it.database_engine = :mysql }
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class TracerTest < Minitest::Test
|
4
|
+
def test_instrument
|
5
|
+
recorder = FakeRecorder.new
|
6
|
+
ScoutApm::Agent.instance.context.recorder = recorder
|
7
|
+
|
8
|
+
invoked = false
|
9
|
+
ScoutApm::Tracer.instrument("Test", "name") do
|
10
|
+
invoked = true
|
11
|
+
end
|
12
|
+
|
13
|
+
assert invoked, "instrumented code was not invoked"
|
14
|
+
assert_recorded(recorder, "Test", "name")
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_instrument_included
|
18
|
+
recorder = FakeRecorder.new
|
19
|
+
ScoutApm::Agent.instance.context.recorder = recorder
|
20
|
+
|
21
|
+
klass = Class.new { include ScoutApm::Tracer }
|
22
|
+
|
23
|
+
invoked = false
|
24
|
+
klass.instrument("Test", "name") do
|
25
|
+
invoked = true
|
26
|
+
end
|
27
|
+
|
28
|
+
assert invoked, "instrumented code was not invoked"
|
29
|
+
assert_recorded(recorder, "Test", "name")
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_instrument_inside_method
|
33
|
+
recorder = FakeRecorder.new
|
34
|
+
ScoutApm::Agent.instance.context.recorder = recorder
|
35
|
+
|
36
|
+
klass = Class.new { include ScoutApm::Tracer }
|
37
|
+
klass.class_eval %q{
|
38
|
+
attr_reader :invoked
|
39
|
+
def work
|
40
|
+
ScoutApm::Tracer.instrument("Test", "name") do
|
41
|
+
@invoked = true
|
42
|
+
end
|
43
|
+
end
|
44
|
+
}
|
45
|
+
klass_instance = klass.new
|
46
|
+
klass_instance.work
|
47
|
+
|
48
|
+
assert klass_instance.invoked, "instrumented code was not invoked"
|
49
|
+
assert_recorded(recorder, "Test", "name")
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_instrument_method
|
53
|
+
recorder = FakeRecorder.new
|
54
|
+
ScoutApm::Agent.instance.context.recorder = recorder
|
55
|
+
|
56
|
+
klass = Class.new { include ScoutApm::Tracer }
|
57
|
+
|
58
|
+
invoked = false
|
59
|
+
klass.send(:define_method, :work) { invoked = true }
|
60
|
+
klass.instrument_method(:work, :type => "Test", :name => "name")
|
61
|
+
|
62
|
+
klass.new.work
|
63
|
+
|
64
|
+
assert invoked, "instrumented code was not invoked"
|
65
|
+
assert_recorded(recorder, "Test", "name")
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def assert_recorded(recorder, type, name)
|
71
|
+
req = recorder.requests.first
|
72
|
+
assert req, "recorder recorded no layers"
|
73
|
+
assert_equal type, req.root_layer.type
|
74
|
+
assert_equal name, req.root_layer.name
|
75
|
+
end
|
76
|
+
end
|
@@ -10,19 +10,6 @@ class TrackedRequestDumpAndLoadTest < Minitest::Test
|
|
10
10
|
loaded = Marshal.load(dumped)
|
11
11
|
assert_false loaded.nil?
|
12
12
|
end
|
13
|
-
|
14
|
-
def test_restore_store
|
15
|
-
faux_store = ScoutApm::FakeStore.new
|
16
|
-
context = ScoutApm::AgentContext.new
|
17
|
-
tr = ScoutApm::TrackedRequest.new(context, faux_store)
|
18
|
-
assert_equal faux_store, tr.instance_variable_get("@store")
|
19
|
-
|
20
|
-
tr.prepare_to_dump!
|
21
|
-
assert_nil tr.instance_variable_get("@store")
|
22
|
-
|
23
|
-
tr.restore_store
|
24
|
-
assert_equal context.store, tr.instance_variable_get("@store")
|
25
|
-
end
|
26
13
|
end
|
27
14
|
|
28
15
|
class TrackedRequestLayerManipulationTest < Minitest::Test
|
@@ -48,4 +35,37 @@ class TrackedRequestLayerManipulationTest < Minitest::Test
|
|
48
35
|
|
49
36
|
assert_equal "Controller", tr.current_layer.type
|
50
37
|
end
|
38
|
+
|
39
|
+
def test_name_override_controller
|
40
|
+
# layers are Middleware -> Controller
|
41
|
+
middleware_layer = ScoutApm::Layer.new("Middleware", "foo")
|
42
|
+
controller_layer = ScoutApm::Layer.new("Controller", "users/index")
|
43
|
+
|
44
|
+
tr = ScoutApm::TrackedRequest.new(ScoutApm::AgentContext.new, ScoutApm::FakeStore.new)
|
45
|
+
tr.start_layer(middleware_layer)
|
46
|
+
tr.name_override = "override"
|
47
|
+
tr.start_layer(controller_layer)
|
48
|
+
tr.stop_layer
|
49
|
+
tr.stop_layer
|
50
|
+
|
51
|
+
assert_equal "override", controller_layer.name
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_name_override_job
|
55
|
+
# layers are Middleware -> Queue -> Job
|
56
|
+
middleware_layer = ScoutApm::Layer.new("Middleware", "foo")
|
57
|
+
queue_layer = ScoutApm::Layer.new("Queue", "bar")
|
58
|
+
job_layer = ScoutApm::Layer.new("Job", "FooJob")
|
59
|
+
|
60
|
+
tr = ScoutApm::TrackedRequest.new(ScoutApm::AgentContext.new, ScoutApm::FakeStore.new)
|
61
|
+
tr.start_layer(middleware_layer)
|
62
|
+
tr.name_override = "override"
|
63
|
+
tr.start_layer(queue_layer)
|
64
|
+
tr.start_layer(job_layer)
|
65
|
+
tr.stop_layer
|
66
|
+
tr.stop_layer
|
67
|
+
tr.stop_layer
|
68
|
+
|
69
|
+
assert_equal "override", job_layer.name
|
70
|
+
end
|
51
71
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class TransactionTest < Minitest::Test
|
4
|
+
def test_ignore
|
5
|
+
recorder = FakeRecorder.new
|
6
|
+
ScoutApm::Agent.instance.context.recorder = recorder
|
7
|
+
|
8
|
+
ScoutApm::Tracer.instrument("Controller", "foo/bar") do
|
9
|
+
ScoutApm::Transaction.ignore!
|
10
|
+
end
|
11
|
+
|
12
|
+
assert_equal 0, recorder.requests.length
|
13
|
+
end
|
14
|
+
end
|
data/test/unit/utils/scm.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
require 'test_helper'
|
2
2
|
require 'scout_apm/utils/scm'
|
3
3
|
|
4
4
|
class ScmTest < Minitest::Test
|
@@ -14,4 +14,4 @@ class ScmTest < Minitest::Test
|
|
14
14
|
def test_relative_scm_path_not_blank_with_slashes
|
15
15
|
assert_equal 'src/app/models/person.rb', ScoutApm::Utils::Scm.relative_scm_path('app/models/person.rb', '/src/')
|
16
16
|
end
|
17
|
-
end
|
17
|
+
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: 3.0.0.
|
4
|
+
version: 3.0.0.pre21
|
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-
|
12
|
+
date: 2018-03-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: minitest
|
@@ -54,7 +54,7 @@ dependencies:
|
|
54
54
|
- !ruby/object:Gem::Version
|
55
55
|
version: '0'
|
56
56
|
- !ruby/object:Gem::Dependency
|
57
|
-
name:
|
57
|
+
name: simplecov
|
58
58
|
requirement: !ruby/object:Gem::Requirement
|
59
59
|
requirements:
|
60
60
|
- - ">="
|
@@ -68,7 +68,7 @@ dependencies:
|
|
68
68
|
- !ruby/object:Gem::Version
|
69
69
|
version: '0'
|
70
70
|
- !ruby/object:Gem::Dependency
|
71
|
-
name:
|
71
|
+
name: rake-compiler
|
72
72
|
requirement: !ruby/object:Gem::Requirement
|
73
73
|
requirements:
|
74
74
|
- - ">="
|
@@ -82,7 +82,7 @@ dependencies:
|
|
82
82
|
- !ruby/object:Gem::Version
|
83
83
|
version: '0'
|
84
84
|
- !ruby/object:Gem::Dependency
|
85
|
-
name:
|
85
|
+
name: addressable
|
86
86
|
requirement: !ruby/object:Gem::Requirement
|
87
87
|
requirements:
|
88
88
|
- - ">="
|
@@ -96,7 +96,21 @@ dependencies:
|
|
96
96
|
- !ruby/object:Gem::Version
|
97
97
|
version: '0'
|
98
98
|
- !ruby/object:Gem::Dependency
|
99
|
-
name:
|
99
|
+
name: activesupport
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
type: :development
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
- !ruby/object:Gem::Dependency
|
113
|
+
name: rubocop
|
100
114
|
requirement: !ruby/object:Gem::Requirement
|
101
115
|
requirements:
|
102
116
|
- - ">="
|
@@ -138,7 +152,7 @@ dependencies:
|
|
138
152
|
- !ruby/object:Gem::Version
|
139
153
|
version: '0'
|
140
154
|
- !ruby/object:Gem::Dependency
|
141
|
-
name:
|
155
|
+
name: m
|
142
156
|
requirement: !ruby/object:Gem::Requirement
|
143
157
|
requirements:
|
144
158
|
- - ">="
|
@@ -163,6 +177,7 @@ extra_rdoc_files: []
|
|
163
177
|
files:
|
164
178
|
- ".gitignore"
|
165
179
|
- ".rubocop.yml"
|
180
|
+
- ".travis.yml"
|
166
181
|
- CHANGELOG.markdown
|
167
182
|
- Gemfile
|
168
183
|
- Guardfile
|
@@ -297,6 +312,7 @@ files:
|
|
297
312
|
- lib/scout_apm/trace_compactor.rb
|
298
313
|
- lib/scout_apm/tracer.rb
|
299
314
|
- lib/scout_apm/tracked_request.rb
|
315
|
+
- lib/scout_apm/transaction.rb
|
300
316
|
- lib/scout_apm/utils/active_record_metric_name.rb
|
301
317
|
- lib/scout_apm/utils/backtrace_parser.rb
|
302
318
|
- lib/scout_apm/utils/fake_stacks.rb
|
@@ -346,7 +362,9 @@ files:
|
|
346
362
|
- test/unit/slow_request_policy_test.rb
|
347
363
|
- test/unit/sql_sanitizer_test.rb
|
348
364
|
- test/unit/store_test.rb
|
349
|
-
- test/unit/
|
365
|
+
- test/unit/tracer_test.rb
|
366
|
+
- test/unit/tracked_request_test.rb
|
367
|
+
- test/unit/transaction_test.rb
|
350
368
|
- test/unit/utils/active_record_metric_name_test.rb
|
351
369
|
- test/unit/utils/backtrace_parser_test.rb
|
352
370
|
- test/unit/utils/numbers_test.rb
|
@@ -411,7 +429,9 @@ test_files:
|
|
411
429
|
- test/unit/slow_request_policy_test.rb
|
412
430
|
- test/unit/sql_sanitizer_test.rb
|
413
431
|
- test/unit/store_test.rb
|
414
|
-
- test/unit/
|
432
|
+
- test/unit/tracer_test.rb
|
433
|
+
- test/unit/tracked_request_test.rb
|
434
|
+
- test/unit/transaction_test.rb
|
415
435
|
- test/unit/utils/active_record_metric_name_test.rb
|
416
436
|
- test/unit/utils/backtrace_parser_test.rb
|
417
437
|
- test/unit/utils/numbers_test.rb
|