scout_apm 5.1.0 → 5.3.0
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/.github/workflows/test.yml +15 -0
- data/CHANGELOG.markdown +16 -0
- data/gems/instruments.gemfile +6 -0
- data/gems/sidekiq.gemfile +4 -0
- data/lib/scout_apm/background_job_integrations/sidekiq.rb +2 -8
- data/lib/scout_apm/config.rb +16 -1
- data/lib/scout_apm/instrument_manager.rb +18 -1
- data/lib/scout_apm/instruments/action_controller_rails_2.rb +1 -1
- data/lib/scout_apm/instruments/action_controller_rails_3_rails4.rb +1 -1
- data/lib/scout_apm/instruments/action_view.rb +1 -1
- data/lib/scout_apm/instruments/active_record.rb +1 -1
- data/lib/scout_apm/instruments/elasticsearch.rb +91 -42
- data/lib/scout_apm/instruments/grape.rb +1 -1
- data/lib/scout_apm/instruments/http.rb +36 -16
- data/lib/scout_apm/instruments/http_client.rb +33 -14
- data/lib/scout_apm/instruments/influxdb.rb +2 -2
- data/lib/scout_apm/instruments/memcached.rb +26 -11
- data/lib/scout_apm/instruments/middleware_detailed.rb +1 -1
- data/lib/scout_apm/instruments/middleware_summary.rb +1 -1
- data/lib/scout_apm/instruments/mongoid.rb +1 -1
- data/lib/scout_apm/instruments/moped.rb +44 -19
- data/lib/scout_apm/instruments/net_http.rb +49 -21
- data/lib/scout_apm/instruments/rails_router.rb +1 -1
- data/lib/scout_apm/instruments/redis.rb +26 -11
- data/lib/scout_apm/instruments/sinatra.rb +1 -1
- data/lib/scout_apm/instruments/typhoeus.rb +1 -1
- data/lib/scout_apm/store.rb +6 -0
- data/lib/scout_apm/utils/sql_sanitizer.rb +4 -2
- data/lib/scout_apm/version.rb +1 -1
- data/test/unit/background_job_integrations/sidekiq_test.rb +17 -0
- data/test/unit/instruments/active_record_test.rb +1 -1
- data/test/unit/instruments/http_client_test.rb +24 -0
- data/test/unit/instruments/http_test.rb +24 -0
- data/test/unit/instruments/moped_test.rb +24 -0
- data/test/unit/instruments/net_http_test.rb +11 -1
- data/test/unit/instruments/redis_test.rb +24 -0
- data/test/unit/instruments/typhoeus_test.rb +1 -1
- data/test/unit/sql_sanitizer_test.rb +9 -9
- metadata +8 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4a454dcd926d9c3d9a9432c43ee101bfb9305b2ed181193d55a51fd8d525f3d8
|
|
4
|
+
data.tar.gz: 9bfdbfb6852b7b933f83f947cb225fe1096083c6a4fe44a0620ff888ee01e26d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 29012317cfdcb2958395ca541ec628d4f8d3d2ee5278428075930be30cb9fa445c23463cc11f32dab39649a5b34fd6caf6f981eee7c5c88ef1ade39c36e5806d
|
|
7
|
+
data.tar.gz: a45e503bcd08fa16cbc885133efcc2bbea64bf76eff6a9de7d5c35a7ddce4ea5a059904c902de6afacba0daba5128b62ce477565aecf2512391962cfea729623
|
data/.github/workflows/test.yml
CHANGED
|
@@ -35,11 +35,26 @@ jobs:
|
|
|
35
35
|
gemfile: gems/rails3.gemfile
|
|
36
36
|
bundler: 1.17.3
|
|
37
37
|
- ruby: 2.7
|
|
38
|
+
- ruby: 2.7
|
|
39
|
+
prepend: true
|
|
40
|
+
- ruby: 3.0
|
|
41
|
+
- ruby: 3.0
|
|
42
|
+
prepend: true
|
|
43
|
+
- ruby: 3.0
|
|
44
|
+
gemfile: gems/instruments.gemfile
|
|
45
|
+
test_features: "instruments"
|
|
46
|
+
- ruby: 3.0
|
|
47
|
+
gemfile: gems/instruments.gemfile
|
|
48
|
+
prepend: true
|
|
49
|
+
test_features: "instruments"
|
|
38
50
|
- ruby: 3.0
|
|
51
|
+
gemfile: gems/sidekiq.gemfile
|
|
52
|
+
test_features: "sidekiq_install"
|
|
39
53
|
|
|
40
54
|
env:
|
|
41
55
|
BUNDLE_GEMFILE: ${{ matrix.gemfile }}
|
|
42
56
|
SCOUT_TEST_FEATURES: ${{ matrix.test_features }}
|
|
57
|
+
SCOUT_USE_PREPEND: ${{ matrix.prepend }}
|
|
43
58
|
|
|
44
59
|
runs-on: ubuntu-latest
|
|
45
60
|
|
data/CHANGELOG.markdown
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Unreleased
|
|
2
2
|
|
|
3
|
+
# 5.3.0
|
|
4
|
+
|
|
5
|
+
* Add configuraiton option to use `Module#prepend` instead of `Module#alias_method` (default)
|
|
6
|
+
for instrumentation (#448). The default method for instrumentation has not changed, but
|
|
7
|
+
configuration options were added to allow switching to `Module#prepend` for most
|
|
8
|
+
instrumentation. Refer to the documentation for more information:
|
|
9
|
+
[Library Instrumentation Method](https://scoutapm.com/docs/ruby/configuration#library-instrumentation-method)
|
|
10
|
+
|
|
11
|
+
# 5.2.0
|
|
12
|
+
|
|
13
|
+
* Use Sidekiq lifecycle hooks to start Scout agent on Sidekiq start. (#449)
|
|
14
|
+
|
|
15
|
+
# 5.1.1
|
|
16
|
+
|
|
17
|
+
* Improvements to SqlServer scrubbing in SqlSanitizer (#422)
|
|
18
|
+
|
|
3
19
|
# 5.1.0
|
|
4
20
|
|
|
5
21
|
* Specify correct (MIT) license in Gemspec (#430)
|
|
@@ -37,17 +37,11 @@ module ScoutApm
|
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
def install_processor
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
::Sidekiq::Processor.class_eval do
|
|
43
|
-
def initialize_with_scout(*args)
|
|
40
|
+
::Sidekiq.configure_server do |config|
|
|
41
|
+
config.on(:startup) do
|
|
44
42
|
agent = ::ScoutApm::Agent.instance
|
|
45
43
|
agent.start
|
|
46
|
-
initialize_without_scout(*args)
|
|
47
44
|
end
|
|
48
|
-
|
|
49
|
-
alias_method :initialize_without_scout, :initialize
|
|
50
|
-
alias_method :initialize, :initialize_with_scout
|
|
51
45
|
end
|
|
52
46
|
end
|
|
53
47
|
end
|
data/lib/scout_apm/config.rb
CHANGED
|
@@ -35,7 +35,13 @@ require 'scout_apm/environment'
|
|
|
35
35
|
# start_resque_server_instrument - Used in special situations with certain Resque installs
|
|
36
36
|
# timeline_traces - true/false to enable sending of of the timeline trace format.
|
|
37
37
|
# auto_instruments - true/false whether to install autoinstruments. Only installed if on a supported Ruby version.
|
|
38
|
-
# auto_instruments_ignore
|
|
38
|
+
# auto_instruments_ignore - An array of file names to exclude from autoinstruments (Ex: ['application_controller']).
|
|
39
|
+
# use_prepend - Whether to apply instrumentation using Module#Prepend instead
|
|
40
|
+
# of Module#alias_method (Default: false)
|
|
41
|
+
# alias_method_instruments - If `use_prepend` is true, continue to use Module#alias_method for
|
|
42
|
+
# any instruments listed in this array. Default: []
|
|
43
|
+
# prepend_instruments - If `use_prepend` is false, force using Module#prepend for any
|
|
44
|
+
# instruments listed in this array. Default: []
|
|
39
45
|
#
|
|
40
46
|
# Any of these config settings can be set with an environment variable prefixed
|
|
41
47
|
# by SCOUT_ and uppercasing the key: SCOUT_LOG_LEVEL for instance.
|
|
@@ -85,6 +91,9 @@ module ScoutApm
|
|
|
85
91
|
'timeline_traces',
|
|
86
92
|
'auto_instruments',
|
|
87
93
|
'auto_instruments_ignore',
|
|
94
|
+
'use_prepend',
|
|
95
|
+
'alias_method_instruments',
|
|
96
|
+
'prepend_instruments',
|
|
88
97
|
|
|
89
98
|
# Error Service Related Configuration
|
|
90
99
|
'errors_enabled',
|
|
@@ -189,6 +198,9 @@ module ScoutApm
|
|
|
189
198
|
'timeline_traces' => BooleanCoercion.new,
|
|
190
199
|
'auto_instruments' => BooleanCoercion.new,
|
|
191
200
|
'auto_instruments_ignore' => JsonCoercion.new,
|
|
201
|
+
'use_prepend' => BooleanCoercion.new,
|
|
202
|
+
'alias_method_instruments' => JsonCoercion.new,
|
|
203
|
+
'prepend_instruments' => JsonCoercion.new,
|
|
192
204
|
'errors_enabled' => BooleanCoercion.new,
|
|
193
205
|
'errors_ignored_exceptions' => JsonCoercion.new,
|
|
194
206
|
'errors_filtered_params' => JsonCoercion.new,
|
|
@@ -305,6 +317,9 @@ module ScoutApm
|
|
|
305
317
|
'timeline_traces' => true,
|
|
306
318
|
'auto_instruments' => false,
|
|
307
319
|
'auto_instruments_ignore' => [],
|
|
320
|
+
'use_prepend' => false,
|
|
321
|
+
'alias_method_instruments' => [],
|
|
322
|
+
'prepend_instruments' => [],
|
|
308
323
|
'ssl_cert_file' => File.join( File.dirname(__FILE__), *%w[.. .. data cacert.pem] ),
|
|
309
324
|
'errors_enabled' => false,
|
|
310
325
|
'errors_ignored_exceptions' => %w(ActiveRecord::RecordNotFound ActionController::RoutingError),
|
|
@@ -50,6 +50,23 @@ module ScoutApm
|
|
|
50
50
|
(config.value("disabled_instruments") || []).include?(instrument_short_name)
|
|
51
51
|
end
|
|
52
52
|
|
|
53
|
+
def prepend_for_instrument?(instrument_klass)
|
|
54
|
+
instrument_short_name = instrument_klass.name.split("::").last
|
|
55
|
+
|
|
56
|
+
# `use_prepend` defaults to false, which means we use `alias_method` by default.
|
|
57
|
+
# If `use_prepend` is `true`, then we should default to using `prepend` unless
|
|
58
|
+
# the instrument is explicitly listed in the `alias_method_instruments` config array.
|
|
59
|
+
if config.value("use_prepend")
|
|
60
|
+
return false if (config.value("alias_method_instruments") || []).include?(instrument_short_name)
|
|
61
|
+
return true
|
|
62
|
+
else
|
|
63
|
+
# `use_prepend` is false, but we should use `prepend` if the instrument is
|
|
64
|
+
# explicitly listed in the `prepend_instruments` array.
|
|
65
|
+
return true if (config.value("prepend_instruments") || []).include?(instrument_short_name)
|
|
66
|
+
return false
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
53
70
|
private
|
|
54
71
|
|
|
55
72
|
def install_instrument(instrument_klass)
|
|
@@ -62,7 +79,7 @@ module ScoutApm
|
|
|
62
79
|
|
|
63
80
|
instance = instrument_klass.new(context)
|
|
64
81
|
@installed_instruments << instance
|
|
65
|
-
instance.install
|
|
82
|
+
instance.install(prepend: prepend_for_instrument?(instrument_klass))
|
|
66
83
|
end
|
|
67
84
|
|
|
68
85
|
def already_installed?(instrument_klass)
|
|
@@ -18,66 +18,115 @@ module ScoutApm
|
|
|
18
18
|
@installed
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
def install
|
|
21
|
+
def install(prepend:)
|
|
22
22
|
if defined?(::Elasticsearch) &&
|
|
23
23
|
defined?(::Elasticsearch::Transport) &&
|
|
24
24
|
defined?(::Elasticsearch::Transport::Client)
|
|
25
25
|
|
|
26
26
|
@installed = true
|
|
27
27
|
|
|
28
|
-
logger.info "Instrumenting Elasticsearch"
|
|
28
|
+
logger.info "Instrumenting Elasticsearch. Prepend: #{prepend}"
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
include ScoutApm::Tracer
|
|
30
|
+
if prepend
|
|
31
|
+
::Elasticsearch::Transport::Client.send(:include, ScoutApm::Tracer)
|
|
32
|
+
::Elasticsearch::Transport::Client.send(:prepend, ElasticsearchTransportClientInstrumentationPrepend)
|
|
33
|
+
else
|
|
34
|
+
::Elasticsearch::Transport::Client.class_eval do
|
|
35
|
+
include ScoutApm::Tracer
|
|
32
36
|
|
|
33
|
-
|
|
34
|
-
|
|
37
|
+
def perform_request_with_scout_instruments(*args, &block)
|
|
38
|
+
name = _sanitize_name(args[1])
|
|
35
39
|
|
|
36
|
-
|
|
37
|
-
|
|
40
|
+
self.class.instrument("Elasticsearch", name, :ignore_children => true) do
|
|
41
|
+
perform_request_without_scout_instruments(*args, &block)
|
|
42
|
+
end
|
|
38
43
|
end
|
|
39
|
-
end
|
|
40
44
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
45
|
+
alias_method :perform_request_without_scout_instruments, :perform_request
|
|
46
|
+
alias_method :perform_request, :perform_request_with_scout_instruments
|
|
47
|
+
|
|
48
|
+
def _sanitize_name(name)
|
|
49
|
+
name = name.split("/").last.gsub(/^_/, '')
|
|
50
|
+
allowed_names = ["bench",
|
|
51
|
+
"bulk",
|
|
52
|
+
"count",
|
|
53
|
+
"exists",
|
|
54
|
+
"explain",
|
|
55
|
+
"field_stats",
|
|
56
|
+
"health",
|
|
57
|
+
"mget",
|
|
58
|
+
"mlt",
|
|
59
|
+
"mpercolate",
|
|
60
|
+
"msearch",
|
|
61
|
+
"mtermvectors",
|
|
62
|
+
"percolate",
|
|
63
|
+
"query",
|
|
64
|
+
"scroll",
|
|
65
|
+
"search_shards",
|
|
66
|
+
"source",
|
|
67
|
+
"suggest",
|
|
68
|
+
"template",
|
|
69
|
+
"termvectors",
|
|
70
|
+
"update",
|
|
71
|
+
"search", ]
|
|
72
|
+
|
|
73
|
+
if allowed_names.include?(name)
|
|
74
|
+
name
|
|
75
|
+
else
|
|
76
|
+
"Unknown"
|
|
77
|
+
end
|
|
78
|
+
rescue
|
|
72
79
|
"Unknown"
|
|
73
80
|
end
|
|
74
|
-
rescue
|
|
75
|
-
"Unknown"
|
|
76
81
|
end
|
|
77
82
|
end
|
|
78
83
|
end
|
|
79
84
|
end
|
|
80
85
|
end
|
|
86
|
+
|
|
87
|
+
module ElasticsearchTransportClientInstrumentationPrepend
|
|
88
|
+
def perform_request(*args, &block)
|
|
89
|
+
name = _sanitize_name(args[1])
|
|
90
|
+
|
|
91
|
+
self.class.instrument("Elasticsearch", name, :ignore_children => true) do
|
|
92
|
+
super(*args, &block)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def _sanitize_name(name)
|
|
97
|
+
name = name.split("/").last.gsub(/^_/, '')
|
|
98
|
+
allowed_names = ["bench",
|
|
99
|
+
"bulk",
|
|
100
|
+
"count",
|
|
101
|
+
"exists",
|
|
102
|
+
"explain",
|
|
103
|
+
"field_stats",
|
|
104
|
+
"health",
|
|
105
|
+
"mget",
|
|
106
|
+
"mlt",
|
|
107
|
+
"mpercolate",
|
|
108
|
+
"msearch",
|
|
109
|
+
"mtermvectors",
|
|
110
|
+
"percolate",
|
|
111
|
+
"query",
|
|
112
|
+
"scroll",
|
|
113
|
+
"search_shards",
|
|
114
|
+
"source",
|
|
115
|
+
"suggest",
|
|
116
|
+
"template",
|
|
117
|
+
"termvectors",
|
|
118
|
+
"update",
|
|
119
|
+
"search", ]
|
|
120
|
+
|
|
121
|
+
if allowed_names.include?(name)
|
|
122
|
+
name
|
|
123
|
+
else
|
|
124
|
+
"Unknown"
|
|
125
|
+
end
|
|
126
|
+
rescue
|
|
127
|
+
"Unknown"
|
|
128
|
+
end
|
|
129
|
+
end
|
|
81
130
|
end
|
|
82
131
|
end
|
|
83
132
|
|
|
@@ -16,33 +16,53 @@ module ScoutApm
|
|
|
16
16
|
@installed
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
def install
|
|
19
|
+
def install(prepend:)
|
|
20
20
|
if defined?(::HTTP) && defined?(::HTTP::Client)
|
|
21
21
|
@installed = true
|
|
22
22
|
|
|
23
|
-
logger.info "Instrumenting HTTP::Client"
|
|
23
|
+
logger.info "Instrumenting HTTP::Client. Prepend: #{prepend}"
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
include ScoutApm::Tracer
|
|
25
|
+
if prepend
|
|
26
|
+
::HTTP::Client.send(:include, ScoutApm::Tracer)
|
|
27
|
+
::HTTP::Client.send(:prepend, HTTPInstrumentationPrepend)
|
|
28
|
+
else
|
|
29
|
+
::HTTP::Client.class_eval do
|
|
30
|
+
include ScoutApm::Tracer
|
|
27
31
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
32
|
+
def request_with_scout_instruments(verb, uri, opts = {})
|
|
33
|
+
self.class.instrument("HTTP", verb, :ignore_children => true, :desc => request_scout_description(verb, uri)) do
|
|
34
|
+
request_without_scout_instruments(verb, uri, opts)
|
|
35
|
+
end
|
|
31
36
|
end
|
|
32
|
-
end
|
|
33
37
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
def request_scout_description(verb, uri)
|
|
39
|
+
max_length = ScoutApm::Agent.instance.context.config.value('instrument_http_url_length')
|
|
40
|
+
(String(uri).split('?').first)[0..(max_length - 1)]
|
|
41
|
+
rescue
|
|
42
|
+
""
|
|
43
|
+
end
|
|
40
44
|
|
|
41
|
-
|
|
42
|
-
|
|
45
|
+
alias request_without_scout_instruments request
|
|
46
|
+
alias request request_with_scout_instruments
|
|
47
|
+
end
|
|
43
48
|
end
|
|
44
49
|
end
|
|
45
50
|
end
|
|
46
51
|
end
|
|
52
|
+
|
|
53
|
+
module HTTPInstrumentationPrepend
|
|
54
|
+
def request(verb, uri, opts = {})
|
|
55
|
+
self.class.instrument("HTTP", verb, :ignore_children => true, :desc => request_scout_description(verb, uri)) do
|
|
56
|
+
super(verb, uri, opts)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def request_scout_description(verb, uri)
|
|
61
|
+
max_length = ScoutApm::Agent.instance.context.config.value('instrument_http_url_length')
|
|
62
|
+
(String(uri).split('?').first)[0..(max_length - 1)]
|
|
63
|
+
rescue
|
|
64
|
+
""
|
|
65
|
+
end
|
|
66
|
+
end
|
|
47
67
|
end
|
|
48
68
|
end
|
|
@@ -16,33 +16,52 @@ module ScoutApm
|
|
|
16
16
|
@installed
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
def install
|
|
19
|
+
def install(prepend:)
|
|
20
20
|
if defined?(::HTTPClient)
|
|
21
21
|
@installed = true
|
|
22
22
|
|
|
23
|
-
logger.info "Instrumenting HTTPClient"
|
|
23
|
+
logger.info "Instrumenting HTTPClient. Prepend: #{prepend}"
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
include ScoutApm::Tracer
|
|
25
|
+
if prepend
|
|
26
|
+
::HTTPClient.send(:include, ScoutApm::Tracer)
|
|
27
|
+
::HTTPClient.send(:prepend, HttpClientInstrumentationPrepend)
|
|
28
|
+
else
|
|
29
|
+
::HTTPClient.class_eval do
|
|
30
|
+
include ScoutApm::Tracer
|
|
27
31
|
|
|
28
|
-
|
|
32
|
+
def request_with_scout_instruments(*args, &block)
|
|
29
33
|
|
|
30
|
-
|
|
31
|
-
|
|
34
|
+
method = args[0].to_s
|
|
35
|
+
url = args[1]
|
|
32
36
|
|
|
33
|
-
|
|
34
|
-
|
|
37
|
+
max_length = ScoutApm::Agent.instance.context.config.value('instrument_http_url_length')
|
|
38
|
+
url = url && url.to_s[0..(max_length - 1)]
|
|
35
39
|
|
|
36
|
-
|
|
37
|
-
|
|
40
|
+
self.class.instrument("HTTP", method, :desc => url) do
|
|
41
|
+
request_without_scout_instruments(*args, &block)
|
|
42
|
+
end
|
|
38
43
|
end
|
|
39
|
-
end
|
|
40
44
|
|
|
41
|
-
|
|
42
|
-
|
|
45
|
+
alias request_without_scout_instruments request
|
|
46
|
+
alias request request_with_scout_instruments
|
|
47
|
+
end
|
|
43
48
|
end
|
|
44
49
|
end
|
|
45
50
|
end
|
|
46
51
|
end
|
|
52
|
+
|
|
53
|
+
module HttpClientInstrumentationPrepend
|
|
54
|
+
def request(*args, &block)
|
|
55
|
+
method = args[0].to_s
|
|
56
|
+
url = args[1]
|
|
57
|
+
|
|
58
|
+
max_length = ScoutApm::Agent.instance.context.config.value('instrument_http_url_length')
|
|
59
|
+
url = url && url.to_s[0..(max_length - 1)]
|
|
60
|
+
|
|
61
|
+
self.class.instrument("HTTP", method, :desc => url) do
|
|
62
|
+
super(request, *args, &block)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
47
66
|
end
|
|
48
67
|
end
|
|
@@ -16,11 +16,11 @@ module ScoutApm
|
|
|
16
16
|
@installed
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
def install
|
|
19
|
+
def install(prepend:)
|
|
20
20
|
if defined?(::InfluxDB)
|
|
21
21
|
@installed = true
|
|
22
22
|
|
|
23
|
-
logger.debug "Instrumenting InfluxDB"
|
|
23
|
+
logger.debug "Instrumenting InfluxDB."
|
|
24
24
|
|
|
25
25
|
::InfluxDB::Client.class_eval do
|
|
26
26
|
include ScoutApm::Tracer
|
|
@@ -16,28 +16,43 @@ module ScoutApm
|
|
|
16
16
|
@installed
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
def install
|
|
19
|
+
def install(prepend:)
|
|
20
20
|
if defined?(::Dalli) && defined?(::Dalli::Client)
|
|
21
21
|
@installed = true
|
|
22
22
|
|
|
23
|
-
logger.info "Instrumenting Memcached"
|
|
23
|
+
logger.info "Instrumenting Memcached. Prepend: #{prepend}"
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
include ScoutApm::Tracer
|
|
25
|
+
if prepend
|
|
26
|
+
::Dalli::Client.send(:include, ScoutApm::Tracer)
|
|
27
|
+
::Dalli::Client.send(:prepend, MemcachedInstrumentationPrepend)
|
|
28
|
+
else
|
|
29
|
+
::Dalli::Client.class_eval do
|
|
30
|
+
include ScoutApm::Tracer
|
|
27
31
|
|
|
28
|
-
|
|
29
|
-
|
|
32
|
+
def perform_with_scout_instruments(*args, &block)
|
|
33
|
+
command = args.first rescue "Unknown"
|
|
30
34
|
|
|
31
|
-
|
|
32
|
-
|
|
35
|
+
self.class.instrument("Memcached", command) do
|
|
36
|
+
perform_without_scout_instruments(*args, &block)
|
|
37
|
+
end
|
|
33
38
|
end
|
|
34
|
-
end
|
|
35
39
|
|
|
36
|
-
|
|
37
|
-
|
|
40
|
+
alias_method :perform_without_scout_instruments, :perform
|
|
41
|
+
alias_method :perform, :perform_with_scout_instruments
|
|
42
|
+
end
|
|
38
43
|
end
|
|
39
44
|
end
|
|
40
45
|
end
|
|
41
46
|
end
|
|
47
|
+
|
|
48
|
+
module MemcachedInstrumentationPrepend
|
|
49
|
+
def perform(*args, &block)
|
|
50
|
+
command = args.first rescue "Unknown"
|
|
51
|
+
|
|
52
|
+
self.class.instrument("Memcached", command) do
|
|
53
|
+
super(*args, &block)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
42
57
|
end
|
|
43
58
|
end
|
|
@@ -16,32 +16,37 @@ module ScoutApm
|
|
|
16
16
|
@installed
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
def install
|
|
19
|
+
def install(prepend:)
|
|
20
20
|
if defined?(::Moped)
|
|
21
21
|
@installed = true
|
|
22
22
|
|
|
23
|
-
logger.info "Instrumenting Moped"
|
|
23
|
+
logger.info "Instrumenting Moped. Prepend: #{prepend}"
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
include ScoutApm::Tracer
|
|
25
|
+
if prepend
|
|
26
|
+
::Moped::Node.send(:include, ScoutApm::Tracer)
|
|
27
|
+
::Moped::Node.send(:prepend, MopedInstrumentationPrepend)
|
|
28
|
+
else
|
|
29
|
+
::Moped::Node.class_eval do
|
|
30
|
+
include ScoutApm::Tracer
|
|
27
31
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
def process_with_scout_instruments(operation, &callback)
|
|
33
|
+
if operation.respond_to?(:collection)
|
|
34
|
+
collection = operation.collection
|
|
35
|
+
name = "Process/#{collection}/#{operation.class.to_s.split('::').last}"
|
|
36
|
+
self.class.instrument("MongoDB", name, :annotate_layer => { :query => scout_sanitize_log(operation.log_inspect) }) do
|
|
37
|
+
process_without_scout_instruments(operation, &callback)
|
|
38
|
+
end
|
|
34
39
|
end
|
|
35
40
|
end
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
alias_method :process_without_scout_instruments, :process
|
|
42
|
+
alias_method :process, :process_with_scout_instruments
|
|
43
|
+
|
|
44
|
+
# replaces values w/ ?
|
|
45
|
+
def scout_sanitize_log(log)
|
|
46
|
+
return nil if log.length > 1000 # safeguard - don't sanitize large SQL statements
|
|
47
|
+
log.gsub(/(=>")((?:[^"]|"")*)"/) do
|
|
48
|
+
$1 + '?' + '"'
|
|
49
|
+
end
|
|
45
50
|
end
|
|
46
51
|
end
|
|
47
52
|
end
|
|
@@ -49,6 +54,26 @@ module ScoutApm
|
|
|
49
54
|
end
|
|
50
55
|
|
|
51
56
|
end
|
|
57
|
+
|
|
58
|
+
module MopedInstrumentationPrepend
|
|
59
|
+
def process(operation, &callback)
|
|
60
|
+
if operation.respond_to?(:collection)
|
|
61
|
+
collection = operation.collection
|
|
62
|
+
name = "Process/#{collection}/#{operation.class.to_s.split('::').last}"
|
|
63
|
+
self.class.instrument("MongoDB", name, :annotate_layer => { :query => scout_sanitize_log(operation.log_inspect) }) do
|
|
64
|
+
super(operation, &callback)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# replaces values w/ ?
|
|
70
|
+
def scout_sanitize_log(log)
|
|
71
|
+
return nil if log.length > 1000 # safeguard - don't sanitize large SQL statements
|
|
72
|
+
log.gsub(/(=>")((?:[^"]|"")*)"/) do
|
|
73
|
+
$1 + '?' + '"'
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
52
77
|
end
|
|
53
78
|
end
|
|
54
79
|
|
|
@@ -16,41 +16,69 @@ module ScoutApm
|
|
|
16
16
|
@installed
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
def install
|
|
19
|
+
def install(prepend:)
|
|
20
20
|
if defined?(::Net) && defined?(::Net::HTTP)
|
|
21
21
|
@installed = true
|
|
22
22
|
|
|
23
|
-
logger.info "Instrumenting Net::HTTP"
|
|
23
|
+
logger.info "Instrumenting Net::HTTP. Prepend: #{prepend}"
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
include ScoutApm::Tracer
|
|
25
|
+
if prepend
|
|
26
|
+
::Net::HTTP.send(:include, ScoutApm::Tracer)
|
|
27
|
+
::Net::HTTP.send(:prepend, NetHttpInstrumentationPrepend)
|
|
28
|
+
else
|
|
29
|
+
::Net::HTTP.class_eval do
|
|
30
|
+
include ScoutApm::Tracer
|
|
27
31
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
32
|
+
def request_with_scout_instruments(*args, &block)
|
|
33
|
+
self.class.instrument("HTTP", "request", :ignore_children => true, :desc => request_scout_description(args.first)) do
|
|
34
|
+
request_without_scout_instruments(*args, &block)
|
|
35
|
+
end
|
|
31
36
|
end
|
|
32
|
-
end
|
|
33
37
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
38
|
+
def request_scout_description(req)
|
|
39
|
+
path = req.path
|
|
40
|
+
path = path.path if path.respond_to?(:path)
|
|
41
|
+
|
|
42
|
+
# Protect against a nil address value
|
|
43
|
+
if @address.nil?
|
|
44
|
+
return "No Address Found"
|
|
45
|
+
end
|
|
37
46
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
47
|
+
max_length = ScoutApm::Agent.instance.context.config.value('instrument_http_url_length')
|
|
48
|
+
(@address + path.split('?').first)[0..(max_length - 1)]
|
|
49
|
+
rescue
|
|
50
|
+
""
|
|
41
51
|
end
|
|
42
52
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
rescue
|
|
46
|
-
""
|
|
53
|
+
alias request_without_scout_instruments request
|
|
54
|
+
alias request request_with_scout_instruments
|
|
47
55
|
end
|
|
48
|
-
|
|
49
|
-
alias request_without_scout_instruments request
|
|
50
|
-
alias request request_with_scout_instruments
|
|
51
56
|
end
|
|
52
57
|
end
|
|
53
58
|
end
|
|
54
59
|
end
|
|
60
|
+
|
|
61
|
+
module NetHttpInstrumentationPrepend
|
|
62
|
+
def request(request, *args, &block)
|
|
63
|
+
self.class.instrument("HTTP", "request", :ignore_children => true, :desc => request_scout_description(args.first)) do
|
|
64
|
+
super(request, *args, &block)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def request_scout_description(req)
|
|
69
|
+
path = req.path
|
|
70
|
+
path = path.path if path.respond_to?(:path)
|
|
71
|
+
|
|
72
|
+
# Protect against a nil address value
|
|
73
|
+
if @address.nil?
|
|
74
|
+
return "No Address Found"
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
max_length = ScoutApm::Agent.instance.context.config.value('instrument_http_url_length')
|
|
78
|
+
(@address + path.split('?').first)[0..(max_length - 1)]
|
|
79
|
+
rescue
|
|
80
|
+
""
|
|
81
|
+
end
|
|
82
|
+
end
|
|
55
83
|
end
|
|
56
84
|
end
|
|
@@ -16,28 +16,43 @@ module ScoutApm
|
|
|
16
16
|
@installed
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
def install
|
|
19
|
+
def install(prepend:)
|
|
20
20
|
if defined?(::Redis) && defined?(::Redis::Client)
|
|
21
21
|
@installed = true
|
|
22
22
|
|
|
23
|
-
logger.info "Instrumenting Redis"
|
|
23
|
+
logger.info "Instrumenting Redis. Prepend: #{prepend}"
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
include ScoutApm::Tracer
|
|
25
|
+
if prepend
|
|
26
|
+
::Redis::Client.send(:include, ScoutApm::Tracer)
|
|
27
|
+
::Redis::Client.send(:prepend, RedisClientInstrumentationPrepend)
|
|
28
|
+
else
|
|
29
|
+
::Redis::Client.class_eval do
|
|
30
|
+
include ScoutApm::Tracer
|
|
27
31
|
|
|
28
|
-
|
|
29
|
-
|
|
32
|
+
def call_with_scout_instruments(*args, &block)
|
|
33
|
+
command = args.first.first rescue "Unknown"
|
|
30
34
|
|
|
31
|
-
|
|
32
|
-
|
|
35
|
+
self.class.instrument("Redis", command) do
|
|
36
|
+
call_without_scout_instruments(*args, &block)
|
|
37
|
+
end
|
|
33
38
|
end
|
|
34
|
-
end
|
|
35
39
|
|
|
36
|
-
|
|
37
|
-
|
|
40
|
+
alias_method :call_without_scout_instruments, :call
|
|
41
|
+
alias_method :call, :call_with_scout_instruments
|
|
42
|
+
end
|
|
38
43
|
end
|
|
39
44
|
end
|
|
40
45
|
end
|
|
41
46
|
end
|
|
47
|
+
|
|
48
|
+
module RedisClientInstrumentationPrepend
|
|
49
|
+
def call(*args, &block)
|
|
50
|
+
command = args.first.first rescue "Unknown"
|
|
51
|
+
|
|
52
|
+
self.class.instrument("Redis", command) do
|
|
53
|
+
super(*args, &block)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
42
57
|
end
|
|
43
58
|
end
|
data/lib/scout_apm/store.rb
CHANGED
|
@@ -217,6 +217,7 @@ module ScoutApm
|
|
|
217
217
|
|
|
218
218
|
def initialize(timestamp, context)
|
|
219
219
|
@timestamp = timestamp
|
|
220
|
+
@context = context
|
|
220
221
|
|
|
221
222
|
@request_traces = ScoredItemSet.new(context.config.value('max_traces'))
|
|
222
223
|
@job_traces = ScoredItemSet.new(context.config.value('max_traces'))
|
|
@@ -230,6 +231,11 @@ module ScoutApm
|
|
|
230
231
|
@jobs = Hash.new
|
|
231
232
|
end
|
|
232
233
|
|
|
234
|
+
def logger
|
|
235
|
+
@context.logger
|
|
236
|
+
end
|
|
237
|
+
private :logger
|
|
238
|
+
|
|
233
239
|
# Merges another StoreReportingPeriod into this one
|
|
234
240
|
def merge(other)
|
|
235
241
|
self.
|
|
@@ -34,7 +34,8 @@ module ScoutApm
|
|
|
34
34
|
SQLITE_REMOVE_INTEGERS = /(?<!LIMIT )\b\d+\b/.freeze
|
|
35
35
|
|
|
36
36
|
# => "EXEC sp_executesql N'SELECT [users].* FROM [users] WHERE (age > 50) ORDER BY [users].[id] ASC OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY', N'@0 int', @0 = 10"
|
|
37
|
-
|
|
37
|
+
SQLSERVER_REMOVE_EXECUTESQL = /EXEC sp_executesql (N')?/.freeze
|
|
38
|
+
SQLSERVER_REMOVE_STRINGS = /'(?:[^']|'')*'/.freeze
|
|
38
39
|
SQLSERVER_REMOVE_INTEGERS = /(?<!LIMIT )\b(?<!@)\d+\b/.freeze
|
|
39
40
|
SQLSERVER_IN_CLAUSE = /IN\s+\(\?[^\)]*\)/.freeze
|
|
40
41
|
|
|
@@ -67,7 +68,8 @@ module ScoutApm
|
|
|
67
68
|
private
|
|
68
69
|
|
|
69
70
|
def to_s_sqlserver
|
|
70
|
-
sql.gsub!(
|
|
71
|
+
sql.gsub!(SQLSERVER_REMOVE_EXECUTESQL, '')
|
|
72
|
+
sql.gsub!(SQLSERVER_REMOVE_STRINGS, '?')
|
|
71
73
|
sql.gsub!(SQLSERVER_REMOVE_INTEGERS, '?')
|
|
72
74
|
sql.gsub!(SQLSERVER_IN_CLAUSE, 'IN (?)')
|
|
73
75
|
sql
|
data/lib/scout_apm/version.rb
CHANGED
|
@@ -3,8 +3,25 @@ require 'scout_apm/request_manager'
|
|
|
3
3
|
require 'scout_apm/background_job_integrations/sidekiq'
|
|
4
4
|
|
|
5
5
|
class SidekiqTest < Minitest::Test
|
|
6
|
+
SidekiqIntegration = ScoutApm::BackgroundJobIntegrations::Sidekiq
|
|
6
7
|
SidekiqMiddleware = ScoutApm::BackgroundJobIntegrations::SidekiqMiddleware
|
|
7
8
|
|
|
9
|
+
########################################
|
|
10
|
+
# Install
|
|
11
|
+
########################################
|
|
12
|
+
if (ENV["SCOUT_TEST_FEATURES"] || "").include?("sidekiq_install")
|
|
13
|
+
require 'sidekiq'
|
|
14
|
+
|
|
15
|
+
# Sidekiq::CLI needs to be defined in order for `Sidekiq.configure_server` to work
|
|
16
|
+
Sidekiq::CLI = nil
|
|
17
|
+
|
|
18
|
+
def test_starts_on_startup
|
|
19
|
+
::ScoutApm::Agent.any_instance.expects(:start)
|
|
20
|
+
SidekiqIntegration.new.install
|
|
21
|
+
Sidekiq.options[:lifecycle_events][:startup].map(&:call)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
8
25
|
########################################
|
|
9
26
|
# Middleware
|
|
10
27
|
########################################
|
|
@@ -29,7 +29,7 @@ class ActiveRecordTest < Minitest::Test
|
|
|
29
29
|
agent_context.recorder = recorder
|
|
30
30
|
|
|
31
31
|
instrument = ScoutApm::Instruments::ActiveRecord.new(agent_context)
|
|
32
|
-
instrument.install
|
|
32
|
+
instrument.install(prepend: false)
|
|
33
33
|
|
|
34
34
|
ScoutApm::Tracer.instrument("Controller", "foo/bar") do
|
|
35
35
|
user = User.create
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
if (ENV["SCOUT_TEST_FEATURES"] || "").include?("instruments")
|
|
2
|
+
require 'test_helper'
|
|
3
|
+
|
|
4
|
+
require 'scout_apm/instruments/http_client'
|
|
5
|
+
|
|
6
|
+
require 'httpclient'
|
|
7
|
+
|
|
8
|
+
class HttpClientTest < Minitest::Test
|
|
9
|
+
def setup
|
|
10
|
+
@context = ScoutApm::AgentContext.new
|
|
11
|
+
@instance = ScoutApm::Instruments::HttpClient.new(@context)
|
|
12
|
+
@instrument_manager = ScoutApm::InstrumentManager.new(@context)
|
|
13
|
+
@instance.install(prepend: @instrument_manager.prepend_for_instrument?(@instance.class))
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def test_installs_using_proper_method
|
|
17
|
+
if @instrument_manager.prepend_for_instrument?(@instance.class) == true
|
|
18
|
+
assert ::HTTPClient.ancestors.include?(ScoutApm::Instruments::HttpClientInstrumentationPrepend)
|
|
19
|
+
else
|
|
20
|
+
assert_equal false, ::HTTPClient.ancestors.include?(ScoutApm::Instruments::HttpClientInstrumentationPrepend)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
if (ENV["SCOUT_TEST_FEATURES"] || "").include?("instruments")
|
|
2
|
+
require 'test_helper'
|
|
3
|
+
|
|
4
|
+
require 'scout_apm/instruments/http'
|
|
5
|
+
|
|
6
|
+
require 'http'
|
|
7
|
+
|
|
8
|
+
class HttpTest < Minitest::Test
|
|
9
|
+
def setup
|
|
10
|
+
@context = ScoutApm::AgentContext.new
|
|
11
|
+
@instance = ScoutApm::Instruments::HTTP.new(@context)
|
|
12
|
+
@instrument_manager = ScoutApm::InstrumentManager.new(@context)
|
|
13
|
+
@instance.install(prepend: @instrument_manager.prepend_for_instrument?(@instance.class))
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def test_installs_using_proper_method
|
|
17
|
+
if @instrument_manager.prepend_for_instrument?(@instance.class) == true
|
|
18
|
+
assert ::HTTP::Client.ancestors.include?(ScoutApm::Instruments::HTTPInstrumentationPrepend)
|
|
19
|
+
else
|
|
20
|
+
assert_equal false, ::HTTP::Client.ancestors.include?(ScoutApm::Instruments::HTTPInstrumentationPrepend)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
if (ENV["SCOUT_TEST_FEATURES"] || "").include?("instruments")
|
|
2
|
+
require 'test_helper'
|
|
3
|
+
|
|
4
|
+
require 'scout_apm/instruments/moped'
|
|
5
|
+
|
|
6
|
+
require 'moped'
|
|
7
|
+
|
|
8
|
+
class MopedTest < Minitest::Test
|
|
9
|
+
def setup
|
|
10
|
+
@context = ScoutApm::AgentContext.new
|
|
11
|
+
@instance = ScoutApm::Instruments::Moped.new(@context)
|
|
12
|
+
@instrument_manager = ScoutApm::InstrumentManager.new(@context)
|
|
13
|
+
@instance.install(prepend: @instrument_manager.prepend_for_instrument?(@instance.class))
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def test_installs_using_proper_method
|
|
17
|
+
if @instrument_manager.prepend_for_instrument?(@instance.class) == true
|
|
18
|
+
assert ::Moped::Node.ancestors.include?(ScoutApm::Instruments::MopedInstrumentationPrepend)
|
|
19
|
+
else
|
|
20
|
+
assert_equal false, ::Moped::Node.ancestors.include?(ScoutApm::Instruments::MopedInstrumentationPrepend)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -7,7 +7,9 @@ require 'addressable/uri'
|
|
|
7
7
|
class NetHttpTest < Minitest::Test
|
|
8
8
|
def setup
|
|
9
9
|
@context = ScoutApm::AgentContext.new
|
|
10
|
-
ScoutApm::Instruments::NetHttp.new(@context)
|
|
10
|
+
@instance = ScoutApm::Instruments::NetHttp.new(@context)
|
|
11
|
+
@instrument_manager = ScoutApm::InstrumentManager.new(@context)
|
|
12
|
+
@instance.install(prepend: @instrument_manager.prepend_for_instrument?(@instance.class))
|
|
11
13
|
end
|
|
12
14
|
|
|
13
15
|
def test_request_scout_description_for_uri
|
|
@@ -24,4 +26,12 @@ class NetHttpTest < Minitest::Test
|
|
|
24
26
|
req = Net::HTTP::Get.new(Addressable::URI.parse('http://example.org/here'))
|
|
25
27
|
assert_equal '/here', Net::HTTP.new('').request_scout_description(req)
|
|
26
28
|
end
|
|
29
|
+
|
|
30
|
+
def test_installs_using_proper_method
|
|
31
|
+
if @instrument_manager.prepend_for_instrument?(@instance.class) == true
|
|
32
|
+
assert Net::HTTP.ancestors.include?(ScoutApm::Instruments::NetHttpInstrumentationPrepend)
|
|
33
|
+
else
|
|
34
|
+
assert_equal false, Net::HTTP.ancestors.include?(ScoutApm::Instruments::NetHttpInstrumentationPrepend)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
27
37
|
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
if (ENV["SCOUT_TEST_FEATURES"] || "").include?("instruments")
|
|
2
|
+
require 'test_helper'
|
|
3
|
+
|
|
4
|
+
require 'scout_apm/instruments/redis'
|
|
5
|
+
|
|
6
|
+
require 'redis'
|
|
7
|
+
|
|
8
|
+
class RedisTest < Minitest::Test
|
|
9
|
+
def setup
|
|
10
|
+
@context = ScoutApm::AgentContext.new
|
|
11
|
+
@instance = ScoutApm::Instruments::Redis.new(@context)
|
|
12
|
+
@instrument_manager = ScoutApm::InstrumentManager.new(@context)
|
|
13
|
+
@instance.install(prepend: @instrument_manager.prepend_for_instrument?(@instance.class))
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def test_installs_using_proper_method
|
|
17
|
+
if @instrument_manager.prepend_for_instrument?(@instance.class) == true
|
|
18
|
+
assert ::Redis::Client.ancestors.include?(ScoutApm::Instruments::RedisClientInstrumentationPrepend)
|
|
19
|
+
else
|
|
20
|
+
assert_equal false, ::Redis::Client.ancestors.include?(ScoutApm::Instruments::RedisClientInstrumentationPrepend)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -10,7 +10,7 @@ if (ENV["SCOUT_TEST_FEATURES"] || "").include?("typhoeus")
|
|
|
10
10
|
@context = ScoutApm::AgentContext.new
|
|
11
11
|
@recorder = FakeRecorder.new
|
|
12
12
|
ScoutApm::Agent.instance.context.recorder = @recorder
|
|
13
|
-
ScoutApm::Instruments::Typhoeus.new(@context).install
|
|
13
|
+
ScoutApm::Instruments::Typhoeus.new(@context).install(prepend: false)
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
def test_instruments_typhoeus_hydra
|
|
@@ -123,27 +123,27 @@ module ScoutApm
|
|
|
123
123
|
end
|
|
124
124
|
|
|
125
125
|
def test_sqlserver_integers
|
|
126
|
-
skip "SQLServer Support requires Ruby 1.9+ For Regexes"
|
|
127
|
-
|
|
128
126
|
sql = "EXEC sp_executesql N'SELECT [users].* FROM [users] WHERE (age > 50) ORDER BY [users].[id] ASC OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY', N'@0 int', @0 = 10"
|
|
129
127
|
ss = SqlSanitizer.new(sql).tap{ |it| it.database_engine = :sqlserver }
|
|
130
|
-
assert_equal
|
|
128
|
+
assert_equal "SELECT [users].* FROM [users] WHERE (age > ?) ORDER BY [users].[id] ASC OFFSET ? ROWS FETCH NEXT @0 ROWS ONLY?@0 int', @0 = ?", ss.to_s
|
|
131
129
|
end
|
|
132
130
|
|
|
133
131
|
def test_sqlserver_strings
|
|
134
|
-
|
|
132
|
+
sql = "EXEC sp_executesql N'SELECT [users].* FROM [users] WHERE first_name = N'john' AND last_name = N'doe' ORDER BY [users].[id] ASC OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY', N'@0 int', @0 = 10"
|
|
133
|
+
ss = SqlSanitizer.new(sql).tap{ |it| it.database_engine = :sqlserver }
|
|
134
|
+
assert_equal "SELECT [users].* FROM [users] WHERE first_name = N? AND last_name = N? ORDER BY [users].[id] ASC OFFSET ? ROWS FETCH NEXT @0 ROWS ONLY?@0 int', @0 = ?", ss.to_s
|
|
135
|
+
end
|
|
135
136
|
|
|
136
|
-
|
|
137
|
+
def test_sqlserver_strings_no_executesql
|
|
138
|
+
sql = "EXEC Authenticate @username = N'abraham.lincoln', @password = N'somepassword!', @token = NULL, @app_name = N'Central Auth Service', @log_login = true, @ip_address = N'127.0.0.1', @external_type = NULL, @external_success = NULL"
|
|
137
139
|
ss = SqlSanitizer.new(sql).tap{ |it| it.database_engine = :sqlserver }
|
|
138
|
-
assert_equal
|
|
140
|
+
assert_equal "EXEC Authenticate @username = N?, @password = N?, @token = NULL, @app_name = N?, @log_login = true, @ip_address = N?, @external_type = NULL, @external_success = NULL", ss.to_s
|
|
139
141
|
end
|
|
140
142
|
|
|
141
143
|
def test_sqlserver_in_clause
|
|
142
|
-
skip "SQLServer Support requires Ruby 1.9+ For Regexes"
|
|
143
|
-
|
|
144
144
|
sql = "EXEC sp_executesql N'SELECT [users].* FROM [users] WHERE (id IN (1,2,3)) ORDER BY [users].[id] ASC OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY', N'@0 int', @0 = 10"
|
|
145
145
|
ss = SqlSanitizer.new(sql).tap{ |it| it.database_engine = :sqlserver }
|
|
146
|
-
assert_equal
|
|
146
|
+
assert_equal "SELECT [users].* FROM [users] WHERE (id IN (?)) ORDER BY [users].[id] ASC OFFSET ? ROWS FETCH NEXT @0 ROWS ONLY?@0 int', @0 = ?", ss.to_s
|
|
147
147
|
end
|
|
148
148
|
|
|
149
149
|
def test_scrubs_invalid_encoding
|
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: 5.
|
|
4
|
+
version: 5.3.0
|
|
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:
|
|
12
|
+
date: 2022-08-16 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: minitest
|
|
@@ -232,11 +232,13 @@ files:
|
|
|
232
232
|
- ext/rusage/extconf.rb
|
|
233
233
|
- ext/rusage/rusage.c
|
|
234
234
|
- gems/README.md
|
|
235
|
+
- gems/instruments.gemfile
|
|
235
236
|
- gems/octoshark.gemfile
|
|
236
237
|
- gems/rails3.gemfile
|
|
237
238
|
- gems/rails4.gemfile
|
|
238
239
|
- gems/rails5.gemfile
|
|
239
240
|
- gems/rails6.gemfile
|
|
241
|
+
- gems/sidekiq.gemfile
|
|
240
242
|
- gems/typhoeus.gemfile
|
|
241
243
|
- lib/scout_apm.rb
|
|
242
244
|
- lib/scout_apm/agent.rb
|
|
@@ -440,8 +442,12 @@ files:
|
|
|
440
442
|
- test/unit/histogram_test.rb
|
|
441
443
|
- test/unit/ignored_uris_test.rb
|
|
442
444
|
- test/unit/instruments/active_record_test.rb
|
|
445
|
+
- test/unit/instruments/http_client_test.rb
|
|
446
|
+
- test/unit/instruments/http_test.rb
|
|
447
|
+
- test/unit/instruments/moped_test.rb
|
|
443
448
|
- test/unit/instruments/net_http_test.rb
|
|
444
449
|
- test/unit/instruments/percentile_sampler_test.rb
|
|
450
|
+
- test/unit/instruments/redis_test.rb
|
|
445
451
|
- test/unit/instruments/typhoeus_test.rb
|
|
446
452
|
- test/unit/layaway_test.rb
|
|
447
453
|
- test/unit/layer_children_set_test.rb
|