scout_apm 2.2.0.pre2 → 2.2.0.pre3
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 -0
- data/CHANGELOG.markdown +20 -0
- data/lib/scout_apm/background_job_integrations/sidekiq.rb +51 -18
- data/lib/scout_apm/context.rb +9 -5
- data/lib/scout_apm/instruments/action_controller_rails_2.rb +1 -2
- data/lib/scout_apm/instruments/action_controller_rails_3_rails4.rb +13 -3
- data/lib/scout_apm/instruments/middleware_summary.rb +39 -1
- data/lib/scout_apm/tracked_request.rb +20 -6
- data/lib/scout_apm/utils/backtrace_parser.rb +4 -2
- data/lib/scout_apm/version.rb +1 -1
- data/scout_apm.gemspec +1 -0
- data/test/test_helper.rb +1 -1
- data/test/unit/background_job_integrations/sidekiq_test.rb +104 -0
- data/test/unit/context_test.rb +30 -0
- data/test/unit/utils/backtrace_parser_test.rb +14 -0
- metadata +19 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b4fa1f78b691cca73f89e5f79902cdc097633773
|
4
|
+
data.tar.gz: da4c781988cd5996d6d565b42d5ce25e90e4608a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dc8f935276423d6cb568af1dded73c38af744747b07fb8ed390a0f3f968c6ff7188e912da1acd1c3599d683a1ee8160196ff7756c2b55c384b4584342e677ca9
|
7
|
+
data.tar.gz: e5709ffa058e1ffed9d16bc37733f38c0d777f1d33d597447f2d38c7a168635ecbca9d13540be7baa3a8e84a8f082b68ce23b2a62b3d92b7cb0c103010443bc5
|
data/.rubocop.yml
ADDED
data/CHANGELOG.markdown
CHANGED
@@ -2,6 +2,26 @@
|
|
2
2
|
|
3
3
|
* ScoutProf BETA
|
4
4
|
|
5
|
+
# 2.1.4
|
6
|
+
|
7
|
+
* Enhance regular expression that determines if a backtrace line is "inside"
|
8
|
+
the application
|
9
|
+
* Avoids labeling vendor/ as part of the monitored app
|
10
|
+
|
11
|
+
# 2.1.3
|
12
|
+
|
13
|
+
* Less noisy output on errors with Context
|
14
|
+
* Not logging errors w/nil keys or values
|
15
|
+
* Bumping log level down from WARN => INFO on errors
|
16
|
+
* Fix error with complicated AR queries
|
17
|
+
* Caused high log noise
|
18
|
+
* Sidekiq instrumentation changes to handle a variety of edge cases
|
19
|
+
|
20
|
+
# 2.1.2
|
21
|
+
|
22
|
+
* Applies `Rails.application.config.filter_parameters` settings to reported transaction trace uris
|
23
|
+
* Fix incompatibility with ResqueWeb and middleware instrumentation
|
24
|
+
|
5
25
|
# 2.1.1
|
6
26
|
|
7
27
|
* Fix an issue with AR instrumentation and complex queries
|
@@ -8,7 +8,7 @@ module ScoutApm
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def present?
|
11
|
-
defined?(::Sidekiq) &&
|
11
|
+
defined?(::Sidekiq) && File.basename($PROGRAM_NAME).start_with?('sidekiq')
|
12
12
|
end
|
13
13
|
|
14
14
|
def forking?
|
@@ -16,22 +16,33 @@ module ScoutApm
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def install
|
19
|
+
install_tracer
|
20
|
+
add_middleware
|
21
|
+
install_processor
|
22
|
+
end
|
23
|
+
|
24
|
+
def install_tracer
|
19
25
|
# ScoutApm::Tracer is not available when this class is defined
|
20
26
|
SidekiqMiddleware.class_eval do
|
21
27
|
include ScoutApm::Tracer
|
22
28
|
end
|
29
|
+
end
|
23
30
|
|
31
|
+
def add_middleware
|
24
32
|
::Sidekiq.configure_server do |config|
|
25
33
|
config.server_middleware do |chain|
|
26
34
|
chain.add SidekiqMiddleware
|
27
35
|
end
|
28
36
|
end
|
37
|
+
end
|
29
38
|
|
39
|
+
def install_processor
|
30
40
|
require 'sidekiq/processor' # sidekiq v4 has not loaded this file by this point
|
31
41
|
|
32
42
|
::Sidekiq::Processor.class_eval do
|
33
43
|
def initialize_with_scout(boss)
|
34
|
-
|
44
|
+
agent = ::ScoutApm::Agent.instance
|
45
|
+
agent.start_background_worker
|
35
46
|
initialize_without_scout(boss)
|
36
47
|
end
|
37
48
|
|
@@ -41,21 +52,18 @@ module ScoutApm
|
|
41
52
|
end
|
42
53
|
end
|
43
54
|
|
55
|
+
# We insert this middleware into the Sidekiq stack, to capture each job,
|
56
|
+
# and time them.
|
44
57
|
class SidekiqMiddleware
|
45
|
-
|
46
|
-
job_class = msg["class"] # TODO: Validate this across different versions of Sidekiq
|
47
|
-
if job_class == "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper" && msg.has_key?("wrapped")
|
48
|
-
job_class = msg["wrapped"]
|
49
|
-
end
|
50
|
-
|
51
|
-
latency = (Time.now.to_f - (msg['enqueued_at'] || msg['created_at']))
|
58
|
+
ACTIVE_JOB_KLASS = 'ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper'.freeze
|
52
59
|
|
60
|
+
def call(_worker, msg, queue)
|
53
61
|
req = ScoutApm::RequestManager.lookup
|
54
62
|
req.job!
|
55
|
-
req.annotate_request(:queue_latency => latency)
|
63
|
+
req.annotate_request(:queue_latency => latency(msg))
|
56
64
|
|
57
|
-
queue_layer = ScoutApm::Layer.new(
|
58
|
-
job_layer = ScoutApm::Layer.new(
|
65
|
+
queue_layer = ScoutApm::Layer.new('Queue', queue)
|
66
|
+
job_layer = ScoutApm::Layer.new('Job', job_class(msg))
|
59
67
|
|
60
68
|
if ScoutApm::Agent.instance.config.value('profile') && SidekiqMiddleware.version_supports_profiling?
|
61
69
|
# Capture ScoutProf if we can
|
@@ -64,18 +72,43 @@ module ScoutApm
|
|
64
72
|
#job_layer.traced!
|
65
73
|
end
|
66
74
|
|
67
|
-
req.start_layer(queue_layer)
|
68
|
-
req.start_layer(job_layer)
|
69
|
-
|
70
75
|
begin
|
76
|
+
req.start_layer(queue_layer)
|
77
|
+
started_queue = true
|
78
|
+
req.start_layer(job_layer)
|
79
|
+
started_job = true
|
80
|
+
|
71
81
|
yield
|
72
82
|
rescue
|
73
83
|
req.error!
|
74
84
|
raise
|
85
|
+
ensure
|
86
|
+
req.stop_layer if started_job
|
87
|
+
req.stop_layer if started_queue
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
UNKNOWN_CLASS_PLACEHOLDER = 'UnknownJob'.freeze
|
92
|
+
|
93
|
+
def job_class(msg)
|
94
|
+
job_class = msg.fetch('class', UNKNOWN_CLASS_PLACEHOLDER)
|
95
|
+
if job_class == ACTIVE_JOB_KLASS && msg.key?('wrapped')
|
96
|
+
job_class = msg['wrapped']
|
97
|
+
end
|
98
|
+
job_class
|
99
|
+
rescue
|
100
|
+
UNKNOWN_CLASS_PLACEHOLDER
|
101
|
+
end
|
102
|
+
|
103
|
+
def latency(msg, time = Time.now.to_f)
|
104
|
+
created_at = msg['enqueued_at'] || msg['created_at']
|
105
|
+
if created_at
|
106
|
+
(time - created_at)
|
107
|
+
else
|
108
|
+
0
|
75
109
|
end
|
76
|
-
|
77
|
-
|
78
|
-
req.stop_layer # Queue
|
110
|
+
rescue
|
111
|
+
0
|
79
112
|
end
|
80
113
|
|
81
114
|
def self.version_supports_profiling?
|
data/lib/scout_apm/context.rb
CHANGED
@@ -75,8 +75,10 @@ module ScoutApm
|
|
75
75
|
def value_valid?(key_value)
|
76
76
|
# ensure one of our accepted types.
|
77
77
|
value = key_value.values.last
|
78
|
-
if
|
79
|
-
|
78
|
+
if value.nil?
|
79
|
+
false # don't log this ... easy to happen
|
80
|
+
elsif !valid_type?([String, Symbol, Numeric, Time, Date, TrueClass, FalseClass],value)
|
81
|
+
ScoutApm::Agent.instance.logger.info "The value for [#{key_value.keys.first}] is not a valid type [#{value.class}]."
|
80
82
|
false
|
81
83
|
else
|
82
84
|
true
|
@@ -86,14 +88,16 @@ module ScoutApm
|
|
86
88
|
# for consistently with #value_valid?, takes a hash eventhough the value isn't yet used.
|
87
89
|
def key_valid?(key_value)
|
88
90
|
key = key_value.keys.first
|
91
|
+
if key.nil?
|
92
|
+
false # don't log this ... easy to happen
|
89
93
|
# ensure a string or a symbol
|
90
|
-
|
91
|
-
ScoutApm::Agent.instance.logger.
|
94
|
+
elsif !valid_type?([String, Symbol],key)
|
95
|
+
ScoutApm::Agent.instance.logger.info "The key [#{key}] is not a valid type [#{key.class}]."
|
92
96
|
return false
|
93
97
|
end
|
94
98
|
# only alphanumeric, dash, and underscore allowed.
|
95
99
|
if key.to_s.match(/[^\w-]/)
|
96
|
-
ScoutApm::Agent.instance.logger.
|
100
|
+
ScoutApm::Agent.instance.logger.info "They key name [#{key}] is not valid."
|
97
101
|
return false
|
98
102
|
end
|
99
103
|
true
|
@@ -48,8 +48,7 @@ module ScoutApm
|
|
48
48
|
# specific controller actions.
|
49
49
|
def perform_action_with_scout_instruments(*args, &block)
|
50
50
|
req = ScoutApm::RequestManager.lookup
|
51
|
-
|
52
|
-
req.annotate_request(:uri => path)
|
51
|
+
req.annotate_request(:uri => request.path) # for security by-default, we don't use request.fullpath which could reveal filtered params.
|
53
52
|
req.context.add_user(:ip => request.remote_ip)
|
54
53
|
req.set_headers(request.headers)
|
55
54
|
req.start_layer( ScoutApm::Layer.new("Controller", "#{controller_path}/#{action_name}") )
|
@@ -60,8 +60,7 @@ module ScoutApm
|
|
60
60
|
module ActionControllerRails3Rails4Instruments
|
61
61
|
def process_action(*args)
|
62
62
|
req = ScoutApm::RequestManager.lookup
|
63
|
-
|
64
|
-
req.annotate_request(:uri => path)
|
63
|
+
req.annotate_request(:uri => scout_transaction_uri(request))
|
65
64
|
|
66
65
|
# IP Spoofing Protection can throw an exception, just move on w/o remote ip
|
67
66
|
req.context.add_user(:ip => request.remote_ip) rescue nil
|
@@ -95,8 +94,19 @@ module ScoutApm
|
|
95
94
|
ensure
|
96
95
|
req.stop_layer
|
97
96
|
end
|
97
|
+
end # process_action
|
98
|
+
|
99
|
+
# Given an +ActionDispatch::Request+, formats the uri based on config settings.
|
100
|
+
def scout_transaction_uri(request)
|
101
|
+
case ScoutApm::Agent.instance.config.value("uri_reporting")
|
102
|
+
when 'path'
|
103
|
+
request.path # strips off the query string for more security
|
104
|
+
else # default handles filtered params
|
105
|
+
request.filtered_path
|
106
|
+
end
|
98
107
|
end
|
99
|
-
|
108
|
+
|
109
|
+
end # ActionControllerRails3Rails4Instruments
|
100
110
|
end
|
101
111
|
end
|
102
112
|
|
@@ -23,7 +23,15 @@ module ScoutApm
|
|
23
23
|
ActionDispatch::MiddlewareStack.class_eval do
|
24
24
|
def build_with_scout_instruments(app = nil, &block)
|
25
25
|
mw_stack = build_without_scout_instruments(app) { block.call if block }
|
26
|
-
|
26
|
+
if app == mw_stack
|
27
|
+
# Return the raw middleware stack if it equaled app. No
|
28
|
+
# middlewares were created, so nothing to wrap & test.
|
29
|
+
#
|
30
|
+
# Avoids instrumentation of something that doesn't exist
|
31
|
+
mw_stack
|
32
|
+
else
|
33
|
+
MiddlewareSummaryWrapper.new(mw_stack)
|
34
|
+
end
|
27
35
|
end
|
28
36
|
|
29
37
|
alias_method :build_without_scout_instruments, :build
|
@@ -45,6 +53,36 @@ module ScoutApm
|
|
45
53
|
ensure
|
46
54
|
req.stop_layer
|
47
55
|
end
|
56
|
+
|
57
|
+
# Some code (found in resque_web initially) attempts to call methods
|
58
|
+
# directly on `MyApplication.app`, which is the middleware stack.
|
59
|
+
# If it hits our middleware instead of the object at the root of the
|
60
|
+
# app that it expected, then a method it expects will not be there, and an
|
61
|
+
# error thrown.
|
62
|
+
#
|
63
|
+
# Specifically, resque_web assumes `ResqueWeb::Engine.app.url_helpers`
|
64
|
+
# is a method call on rails router for its own Engine, when in fact,
|
65
|
+
# we've added a middleware before it.
|
66
|
+
#
|
67
|
+
# So method_missing just proxies anything to the nested @app object
|
68
|
+
#
|
69
|
+
# While method_missing is not very performant, this is only here to
|
70
|
+
# handle edge-cases in other code, and should not be regularly called
|
71
|
+
def method_missing(sym, *arguments, &block)
|
72
|
+
if @app.respond_to?(sym)
|
73
|
+
@app.send(sym, *arguments, &block)
|
74
|
+
else
|
75
|
+
super
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def respond_to?(sym, include_private = false)
|
80
|
+
if @app.respond_to?(sym, include_private)
|
81
|
+
true
|
82
|
+
else
|
83
|
+
super
|
84
|
+
end
|
85
|
+
end
|
48
86
|
end
|
49
87
|
end
|
50
88
|
end
|
@@ -47,7 +47,7 @@ module ScoutApm
|
|
47
47
|
@layers = []
|
48
48
|
@call_set = Hash.new { |h, k| h[k] = CallSet.new }
|
49
49
|
@annotations = {}
|
50
|
-
@ignoring_children =
|
50
|
+
@ignoring_children = 0
|
51
51
|
@context = Context.new
|
52
52
|
@root_layer = nil
|
53
53
|
@error = false
|
@@ -323,27 +323,41 @@ module ScoutApm
|
|
323
323
|
# specific, and useful than the fact that InfluxDB happens to use Net::HTTP
|
324
324
|
# internally
|
325
325
|
#
|
326
|
-
# When enabled, new layers won't be added to the current Request
|
326
|
+
# When enabled, new layers won't be added to the current Request, and calls
|
327
|
+
# to stop_layer will be ignored.
|
327
328
|
#
|
328
329
|
# Do not forget to turn if off when leaving a layer, it is the
|
329
330
|
# instrumentation's task to do that.
|
331
|
+
#
|
332
|
+
# When you use this in code, be sure to use it in this order:
|
333
|
+
#
|
334
|
+
# start_layer
|
335
|
+
# ignore_children
|
336
|
+
# -> call
|
337
|
+
# acknowledge_children
|
338
|
+
# stop_layer
|
339
|
+
#
|
340
|
+
# If you don't call it in this order, it's possible to get out of sync, and
|
341
|
+
# have an ignored start and an actually-executed stop, causing layers to
|
342
|
+
# get out of sync
|
330
343
|
|
331
344
|
def ignore_children!
|
332
|
-
@ignoring_children
|
345
|
+
@ignoring_children += 1
|
333
346
|
end
|
334
347
|
|
335
348
|
def acknowledge_children!
|
336
|
-
@ignoring_children
|
349
|
+
if @ignoring_children > 0
|
350
|
+
@ignoring_children -= 1
|
351
|
+
end
|
337
352
|
end
|
338
353
|
|
339
354
|
def ignoring_children?
|
340
|
-
@ignoring_children
|
355
|
+
@ignoring_children > 0
|
341
356
|
end
|
342
357
|
|
343
358
|
# Grab backtraces more aggressively when running in dev trace mode
|
344
359
|
def backtrace_threshold
|
345
360
|
dev_trace ? 0.05 : 0.5 # the minimum threshold in seconds to record the backtrace for a metric.
|
346
361
|
end
|
347
|
-
|
348
362
|
end
|
349
363
|
end
|
@@ -14,7 +14,10 @@ module ScoutApm
|
|
14
14
|
def initialize(call_stack, root=ScoutApm::Environment.instance.root)
|
15
15
|
@call_stack = call_stack
|
16
16
|
# We can't use a constant as it'd be too early to fetch environment info
|
17
|
-
|
17
|
+
#
|
18
|
+
# This regex looks for files under the app root, inside lib/, app/, and
|
19
|
+
# config/ dirs, and captures the path under root.
|
20
|
+
@@app_dir_regex = %r[#{root}/((?:lib/|app/|config/).*)]
|
18
21
|
end
|
19
22
|
|
20
23
|
def call
|
@@ -27,7 +30,6 @@ module ScoutApm
|
|
27
30
|
end
|
28
31
|
stack
|
29
32
|
end
|
30
|
-
|
31
33
|
end
|
32
34
|
end
|
33
35
|
end
|
data/lib/scout_apm/version.rb
CHANGED
data/scout_apm.gemspec
CHANGED
@@ -24,6 +24,7 @@ Gem::Specification.new do |s|
|
|
24
24
|
s.add_runtime_dependency "rusage", '~> 0.2.0'
|
25
25
|
|
26
26
|
s.add_development_dependency "minitest"
|
27
|
+
s.add_development_dependency 'mocha'
|
27
28
|
s.add_development_dependency "pry"
|
28
29
|
s.add_development_dependency "m"
|
29
30
|
s.add_development_dependency "simplecov"
|
data/test/test_helper.rb
CHANGED
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'scout_apm/request_manager'
|
3
|
+
require 'scout_apm/background_job_integrations/sidekiq'
|
4
|
+
|
5
|
+
class SidekiqTest < Minitest::Test
|
6
|
+
SidekiqMiddleware = ScoutApm::BackgroundJobIntegrations::SidekiqMiddleware
|
7
|
+
|
8
|
+
########################################
|
9
|
+
# Middleware
|
10
|
+
########################################
|
11
|
+
def test_middleware_call_happy_path
|
12
|
+
fake_request = mock
|
13
|
+
fake_request.expects(:annotate_request)
|
14
|
+
fake_request.expects(:job!)
|
15
|
+
fake_request.expects(:start_layer).twice
|
16
|
+
fake_request.expects(:stop_layer).twice
|
17
|
+
fake_request.expects(:error!).never
|
18
|
+
|
19
|
+
ScoutApm::RequestManager.stubs(:lookup).returns(fake_request)
|
20
|
+
|
21
|
+
block_called = false
|
22
|
+
msg = { 'class' => 'MyJobClass',
|
23
|
+
'created_at' => Time.now }
|
24
|
+
|
25
|
+
SidekiqMiddleware.new.call(nil, msg, "defaultqueue") { block_called = true }
|
26
|
+
assert_equal true, block_called
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_middleware_call_job_exception
|
30
|
+
fake_request = mock
|
31
|
+
fake_request.expects(:annotate_request)
|
32
|
+
fake_request.expects(:job!)
|
33
|
+
fake_request.expects(:start_layer).twice
|
34
|
+
fake_request.expects(:stop_layer).twice
|
35
|
+
fake_request.expects(:error!)
|
36
|
+
|
37
|
+
ScoutApm::RequestManager.stubs(:lookup).returns(fake_request)
|
38
|
+
|
39
|
+
msg = { 'class' => 'MyJobClass',
|
40
|
+
'created_at' => Time.now }
|
41
|
+
|
42
|
+
assert_raises RuntimeError do
|
43
|
+
SidekiqMiddleware.new.call(nil, msg, "defaultqueue") { raise "TheJobFailed" }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_middleware_call_edge_cases
|
48
|
+
fake_request = mock
|
49
|
+
fake_request.expects(:annotate_request)
|
50
|
+
fake_request.expects(:job!)
|
51
|
+
fake_request.expects(:start_layer).twice
|
52
|
+
fake_request.expects(:stop_layer).twice
|
53
|
+
fake_request.expects(:error!)
|
54
|
+
|
55
|
+
ScoutApm::RequestManager.stubs(:lookup).returns(fake_request)
|
56
|
+
|
57
|
+
# msg doesn't have anything
|
58
|
+
msg = { }
|
59
|
+
|
60
|
+
assert_raises RuntimeError do
|
61
|
+
SidekiqMiddleware.new.call(nil, msg, "defaultqueue") { raise "TheJobFailed" }
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
########################################
|
66
|
+
# Job Class Determination
|
67
|
+
########################################
|
68
|
+
def test_job_class_name_normally
|
69
|
+
msg = { 'class' => 'AGreatJob' }
|
70
|
+
assert_equal 'AGreatJob', SidekiqMiddleware.new.job_class(msg)
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_job_class_name_activejob
|
74
|
+
msg = { 'class' => 'ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper',
|
75
|
+
'wrapped' => 'RealJobClass' }
|
76
|
+
assert_equal 'RealJobClass', SidekiqMiddleware.new.job_class(msg)
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_job_class_name_error_default
|
80
|
+
msg = {}
|
81
|
+
assert_equal 'UnknownJob', SidekiqMiddleware.new.job_class(msg)
|
82
|
+
end
|
83
|
+
|
84
|
+
########################################
|
85
|
+
# Latency Calculation
|
86
|
+
########################################
|
87
|
+
def test_latency_from_created_at
|
88
|
+
# Created at time 80, but now it is 200. Latency was 120
|
89
|
+
msg = { 'created_at' => 80 }
|
90
|
+
assert_equal 120, SidekiqMiddleware.new.latency(msg, 200)
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_latency_from_enqueued_at
|
94
|
+
# Created at time 80, but now it is 200. Latency was 120
|
95
|
+
msg = { 'enqueued_at' => 80 }
|
96
|
+
assert_equal 120, SidekiqMiddleware.new.latency(msg, 200)
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_latency_fallback
|
100
|
+
# No created at time, so fall back to 0
|
101
|
+
msg = {}
|
102
|
+
assert_equal 0, SidekiqMiddleware.new.latency(msg, 200)
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
require 'scout_apm/context'
|
4
|
+
|
5
|
+
class ContextText < Minitest::Test
|
6
|
+
def test_ignore_nil_value
|
7
|
+
context = ScoutApm::Context.new
|
8
|
+
assert hash = context.add(:nil_key => nil, :org => 'org')
|
9
|
+
assert_equal ({:org => 'org'}), hash
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_ignore_nil_key
|
13
|
+
context = ScoutApm::Context.new
|
14
|
+
assert hash = context.add(nil => nil, :org => 'org')
|
15
|
+
assert_equal ({:org => 'org'}), hash
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_ignore_unsupported_value_type
|
19
|
+
context = ScoutApm::Context.new
|
20
|
+
assert hash = context.add(:array => [1,2,3,4], :org => 'org')
|
21
|
+
assert_equal ({:org => 'org'}), hash
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_ignore_unsupported_key_type
|
25
|
+
context = ScoutApm::Context.new
|
26
|
+
assert hash = context.add([1,2,3,4] => 'hey', :org => 'org')
|
27
|
+
assert_equal ({:org => 'org'}), hash
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
@@ -49,4 +49,18 @@ class BacktraceParserTest < Minitest::Test
|
|
49
49
|
result = ScoutApm::Utils::BacktraceParser.new(raw_backtrace, "/Users/scout/different-secrets").call
|
50
50
|
assert_equal 0, result.length
|
51
51
|
end
|
52
|
+
|
53
|
+
def test_excludes_vendor_paths
|
54
|
+
raw_backtrace = [
|
55
|
+
"#{root}/vendor/ruby/thing.rb",
|
56
|
+
"#{root}/app/controllers/users_controller.rb",
|
57
|
+
"#{root}/vendor/ruby/thing.rb",
|
58
|
+
"#{root}/config/initializers/inject_something.rb",
|
59
|
+
]
|
60
|
+
result = ScoutApm::Utils::BacktraceParser.new(raw_backtrace, root).call
|
61
|
+
|
62
|
+
assert_equal 2, result.length
|
63
|
+
assert_equal false, (result[0] =~ %r|app/controllers/users_controller.rb|).nil?
|
64
|
+
assert_equal false, (result[1] =~ %r|config/initializers/inject_something.rb|).nil?
|
65
|
+
end
|
52
66
|
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.2.0.
|
4
|
+
version: 2.2.0.pre3
|
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: 2016-08-
|
12
|
+
date: 2016-08-25 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rusage
|
@@ -39,6 +39,20 @@ dependencies:
|
|
39
39
|
- - ">="
|
40
40
|
- !ruby/object:Gem::Version
|
41
41
|
version: '0'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: mocha
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
42
56
|
- !ruby/object:Gem::Dependency
|
43
57
|
name: pry
|
44
58
|
requirement: !ruby/object:Gem::Requirement
|
@@ -105,6 +119,7 @@ extensions:
|
|
105
119
|
extra_rdoc_files: []
|
106
120
|
files:
|
107
121
|
- ".gitignore"
|
122
|
+
- ".rubocop.yml"
|
108
123
|
- CHANGELOG.markdown
|
109
124
|
- Gemfile
|
110
125
|
- LICENSE.md
|
@@ -229,7 +244,9 @@ files:
|
|
229
244
|
- test/data/config_test_1.yml
|
230
245
|
- test/test_helper.rb
|
231
246
|
- test/unit/agent_test.rb
|
247
|
+
- test/unit/background_job_integrations/sidekiq_test.rb
|
232
248
|
- test/unit/config_test.rb
|
249
|
+
- test/unit/context_test.rb
|
233
250
|
- test/unit/environment_test.rb
|
234
251
|
- test/unit/histogram_test.rb
|
235
252
|
- test/unit/ignored_uris_test.rb
|