scout_apm 2.0.0 → 2.1.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/CHANGELOG.markdown +6 -0
- data/lib/scout_apm/agent.rb +3 -0
- data/lib/scout_apm/config.rb +20 -1
- data/lib/scout_apm/ignored_uris.rb +15 -0
- data/lib/scout_apm/instant/middleware.rb +10 -5
- data/lib/scout_apm/layer_converters/slow_request_converter.rb +0 -7
- data/lib/scout_apm/tracked_request.rb +3 -0
- data/lib/scout_apm/utils/backtrace_parser.rb +10 -8
- data/lib/scout_apm/version.rb +1 -1
- data/lib/scout_apm.rb +4 -5
- data/test/unit/ignored_uris_test.rb +16 -0
- data/test/unit/utils/backtrace_parser_test.rb +52 -0
- metadata +9 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bf1eaf130d67f52fcfcf414c6db4347fa4b94521
|
4
|
+
data.tar.gz: 0386d415a40a707645a65662237f0d44b9bbbdd8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 71d5d59042427c3bf1afbd753fb8646e012c6187c940a0f6a2854a6123cbc5259b8297ca168a5d91793d6722b6082cd0a7c5da520399a13085b4ca7fc274cf3a
|
7
|
+
data.tar.gz: a2ca63e84f57dd17828072076d0c1bd1b757caf1ef3f82a7954ca928b4d09c973ebbda094cb6a5d1ecbbf1c28c3813838239ca55be7c2b1c24c50f430fe49559
|
data/CHANGELOG.markdown
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
# 2.1.0
|
2
|
+
|
3
|
+
* Added ignore key to configuration to entirely ignore an endpoint. No traces
|
4
|
+
or metrics will be collected. Useful for health-check endpoints.
|
5
|
+
* Better logging for DevTrace
|
6
|
+
|
1
7
|
# 2.0.0
|
2
8
|
|
3
9
|
* Reporting object allocation & mem delta metrics and mem delta for requests and jobs.
|
data/lib/scout_apm/agent.rb
CHANGED
@@ -20,6 +20,7 @@ module ScoutApm
|
|
20
20
|
attr_reader :slow_request_policy
|
21
21
|
attr_reader :slow_job_policy
|
22
22
|
attr_reader :process_start_time # used when creating slow transactions to report how far from startup the transaction was recorded.
|
23
|
+
attr_reader :ignored_uris
|
23
24
|
|
24
25
|
# Histogram of the cumulative requests since the start of the process
|
25
26
|
attr_reader :request_histograms
|
@@ -115,6 +116,8 @@ module ScoutApm
|
|
115
116
|
init_logger
|
116
117
|
logger.info "Attempting to start Scout Agent [#{ScoutApm::VERSION}] on [#{environment.hostname}]"
|
117
118
|
|
119
|
+
@ignored_uris = ScoutApm::IgnoredUris.new(config.value('ignore'))
|
120
|
+
|
118
121
|
if environment.deploy_integration
|
119
122
|
logger.info "Starting monitoring for [#{environment.deploy_integration.name}]]."
|
120
123
|
return environment.deploy_integration.install
|
data/lib/scout_apm/config.rb
CHANGED
@@ -75,6 +75,23 @@ module ScoutApm
|
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
78
|
+
# If the passed value is a string, attempt to decode as json
|
79
|
+
# This is a no-op unless the `JSON` constant is defined
|
80
|
+
class JsonCoercion
|
81
|
+
def coerce(val)
|
82
|
+
case val
|
83
|
+
when String
|
84
|
+
if defined?(JSON) && JSON.respond_to?(:parse)
|
85
|
+
JSON.parse(val)
|
86
|
+
else
|
87
|
+
val
|
88
|
+
end
|
89
|
+
else
|
90
|
+
val
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
78
95
|
# Simply returns the passed in value, without change
|
79
96
|
class NullCoercion
|
80
97
|
def coerce(val)
|
@@ -82,10 +99,12 @@ module ScoutApm
|
|
82
99
|
end
|
83
100
|
end
|
84
101
|
|
102
|
+
|
85
103
|
SETTING_COERCIONS = {
|
86
104
|
"monitor" => BooleanCoercion.new,
|
87
105
|
"enable_background_jobs" => BooleanCoercion.new,
|
88
106
|
"dev_trace" => BooleanCoercion.new,
|
107
|
+
"ignore" => JsonCoercion.new,
|
89
108
|
}
|
90
109
|
|
91
110
|
|
@@ -137,7 +156,7 @@ module ScoutApm
|
|
137
156
|
'report_format' => 'json',
|
138
157
|
'disabled_instruments' => [],
|
139
158
|
'enable_background_jobs' => true,
|
140
|
-
'
|
159
|
+
'ignore' => [],
|
141
160
|
'dev_trace' => false, # false for now so code can live in main branch
|
142
161
|
}.freeze
|
143
162
|
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# On first run, caches the regexes made by the `ignored` configuration setting
|
2
|
+
module ScoutApm
|
3
|
+
class IgnoredUris
|
4
|
+
attr_reader :regex
|
5
|
+
|
6
|
+
def initialize(prefixes)
|
7
|
+
regexes = Array(prefixes).map {|prefix| %r{\A#{prefix}} }
|
8
|
+
@regex = Regexp.union(*regexes)
|
9
|
+
end
|
10
|
+
|
11
|
+
def ignore?(uri)
|
12
|
+
!! regex.match(uri)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -41,12 +41,13 @@ module ScoutApm
|
|
41
41
|
# Note that this middleware never even gets inserted unless Rails environment is development (See Railtie)
|
42
42
|
class Middleware
|
43
43
|
def initialize(app)
|
44
|
+
ScoutApm::Agent.instance.logger.info("Activating Scout DevTrace because environment=development and dev_trace=true in scout_apm config")
|
44
45
|
@app = app
|
45
46
|
end
|
46
47
|
|
47
48
|
def call(env)
|
48
49
|
status, headers, response = @app.call(env)
|
49
|
-
|
50
|
+
path, content_type = env['PATH_INFO'], headers['Content-Type']
|
50
51
|
if ScoutApm::Agent.instance.config.value('dev_trace')
|
51
52
|
if response.respond_to?(:body)
|
52
53
|
req = ScoutApm::RequestManager.lookup
|
@@ -63,8 +64,9 @@ module ScoutApm
|
|
63
64
|
hash.merge!(metadata:metadata)
|
64
65
|
payload = ScoutApm::Serializers::PayloadSerializerToJson.jsonify_hash(hash)
|
65
66
|
|
66
|
-
if env['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'
|
67
|
-
|
67
|
+
if env['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest' || content_type.include?("application/json")
|
68
|
+
ScoutApm::Agent.instance.logger.debug("DevTrace: in middleware, dev_trace is active, and response has a body. This is either AJAX or JSON. Path=#{path}; ContentType=#{content_type}")
|
69
|
+
# Add the payload as a header if it's an AJAX call or JSON
|
68
70
|
headers['X-scoutapminstant'] = payload
|
69
71
|
[status, headers, response]
|
70
72
|
else
|
@@ -77,24 +79,27 @@ module ScoutApm
|
|
77
79
|
page.add_to_body("<script src='#{apm_host}/instant/scout_instant.js?cachebust=#{Time.now.to_i}'></script>")
|
78
80
|
page.add_to_body("<script>var scoutInstantPageTrace=#{payload};window.scoutInstant=window.scoutInstant('#{apm_host}', scoutInstantPageTrace)</script>")
|
79
81
|
|
80
|
-
|
81
82
|
if response.is_a?(ActionDispatch::Response)
|
83
|
+
ScoutApm::Agent.instance.logger.debug("DevTrace: in middleware, dev_trace is active, and response has a body. This appears to be an HTML page and an ActionDispatch::Response. Path=#{path}; ContentType=#{content_type}")
|
82
84
|
# preserve the ActionDispatch::Response when applicable
|
83
85
|
response.body=[page.res]
|
84
86
|
[status, headers, response]
|
85
87
|
else
|
88
|
+
ScoutApm::Agent.instance.logger.debug("DevTrace: in middleware, dev_trace is active, and response has a body. This appears to be an HTML page but not an ActionDispatch::Response. Path=#{path}; ContentType=#{content_type}")
|
86
89
|
# otherwise, just return an array
|
87
|
-
# TODO: this will break ActionCable repsponse
|
88
90
|
[status, headers, [page.res]]
|
89
91
|
end
|
90
92
|
end
|
91
93
|
else
|
94
|
+
ScoutApm::Agent.instance.logger.debug("DevTrace: in middleware, dev_trace is active, and response has a body, but no trace was found. Path=#{path}; ContentType=#{content_type}")
|
92
95
|
[status, headers, response]
|
93
96
|
end
|
94
97
|
else
|
98
|
+
# don't log anything here - this is the path for all assets served in development, and the log would get noisy
|
95
99
|
[status, headers, response]
|
96
100
|
end
|
97
101
|
else
|
102
|
+
ScoutApm::Agent.instance.logger.debug("DevTrace: isn't activated via config. Try: SCOUT_DEV_TRACE=true rails server")
|
98
103
|
[status, headers, response]
|
99
104
|
end
|
100
105
|
end
|
@@ -39,13 +39,6 @@ module ScoutApm
|
|
39
39
|
allocation_metrics = {}
|
40
40
|
end
|
41
41
|
|
42
|
-
(ScoutApm::Agent.instance.config.value("ignore_traces") || []).each do |pattern|
|
43
|
-
if /#{pattern}/ =~ uri
|
44
|
-
ScoutApm::Agent.instance.logger.debug("Skipped recording a trace for #{uri} due to `ignore_traces` pattern: #{pattern}")
|
45
|
-
return nil
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
42
|
SlowTransaction.new(uri,
|
50
43
|
scope.legacy_metric_name,
|
51
44
|
root_layer.total_call_time,
|
@@ -222,6 +222,9 @@ module ScoutApm
|
|
222
222
|
def record!
|
223
223
|
@recorded = true
|
224
224
|
|
225
|
+
# Bail out early if the user asked us to ignore this uri
|
226
|
+
return if ScoutApm::Agent.instance.ignored_uris.ignore?(annotations[:uri])
|
227
|
+
|
225
228
|
# Update immediate and long-term histograms for both job and web requests
|
226
229
|
if unique_name != :unknown
|
227
230
|
ScoutApm::Agent.instance.request_histograms.add(unique_name, root_layer.total_call_time)
|
@@ -1,25 +1,27 @@
|
|
1
1
|
require 'scout_apm/environment'
|
2
2
|
|
3
|
-
#
|
4
|
-
#
|
3
|
+
# Given a call stack Array, grabs the first +APP_FRAMES+ callers within the
|
4
|
+
# application root directory.
|
5
|
+
#
|
5
6
|
module ScoutApm
|
6
7
|
module Utils
|
7
8
|
class BacktraceParser
|
8
9
|
|
9
10
|
APP_FRAMES = 3 # will return up to 3 frames from the app stack.
|
10
11
|
|
11
|
-
|
12
|
+
attr_reader :call_stack
|
13
|
+
|
14
|
+
def initialize(call_stack, root=ScoutApm::Environment.instance.root)
|
12
15
|
@call_stack = call_stack
|
13
16
|
# We can't use a constant as it'd be too early to fetch environment info
|
14
|
-
@@app_dir_regex
|
17
|
+
@@app_dir_regex = %r|#{root}/(.*)|
|
15
18
|
end
|
16
19
|
|
17
|
-
# Given a call stack Array, grabs the first +APP_FRAMES+ callers within the application root directory.
|
18
20
|
def call
|
19
21
|
stack = []
|
20
|
-
|
22
|
+
call_stack.each do |c|
|
21
23
|
if m = c.match(@@app_dir_regex)
|
22
|
-
stack << m[
|
24
|
+
stack << m[1]
|
23
25
|
break if stack.size == APP_FRAMES
|
24
26
|
end
|
25
27
|
end
|
@@ -28,4 +30,4 @@ module ScoutApm
|
|
28
30
|
|
29
31
|
end
|
30
32
|
end
|
31
|
-
end
|
33
|
+
end
|
data/lib/scout_apm/version.rb
CHANGED
data/lib/scout_apm.rb
CHANGED
@@ -63,7 +63,7 @@ require 'scout_apm/platform_integrations/server'
|
|
63
63
|
require 'scout_apm/histogram'
|
64
64
|
|
65
65
|
require 'scout_apm/deploy_integrations/capistrano_3'
|
66
|
-
#require 'scout_apm/deploy_integrations/capistrano_2'
|
66
|
+
# require 'scout_apm/deploy_integrations/capistrano_2'
|
67
67
|
|
68
68
|
require 'scout_apm/instruments/net_http'
|
69
69
|
require 'scout_apm/instruments/http_client'
|
@@ -88,6 +88,7 @@ require 'allocations'
|
|
88
88
|
|
89
89
|
require 'scout_apm/app_server_load'
|
90
90
|
|
91
|
+
require 'scout_apm/ignored_uris.rb'
|
91
92
|
require 'scout_apm/utils/active_record_metric_name'
|
92
93
|
require 'scout_apm/utils/backtrace_parser'
|
93
94
|
require 'scout_apm/utils/installed_gems'
|
@@ -145,7 +146,7 @@ require 'scout_apm/instant/middleware'
|
|
145
146
|
if defined?(Rails) && defined?(Rails::VERSION) && defined?(Rails::VERSION::MAJOR) && Rails::VERSION::MAJOR >= 3 && defined?(Rails::Railtie)
|
146
147
|
module ScoutApm
|
147
148
|
class Railtie < Rails::Railtie
|
148
|
-
initializer
|
149
|
+
initializer 'scout_apm.start' do |app|
|
149
150
|
# attempt to start on first-request if not otherwise started, which is
|
150
151
|
# a good catch-all for Webrick, and Passenger and similar, where we
|
151
152
|
# can't detect the running app server until actual requests come in.
|
@@ -153,11 +154,10 @@ if defined?(Rails) && defined?(Rails::VERSION) && defined?(Rails::VERSION::MAJOR
|
|
153
154
|
|
154
155
|
# Attempt to start right away, this will work best for preloading apps, Unicorn & Puma & similar
|
155
156
|
ScoutApm::Agent.instance.start
|
156
|
-
|
157
157
|
end
|
158
158
|
end
|
159
159
|
class Railtie < Rails::Railtie
|
160
|
-
initializer
|
160
|
+
initializer 'scout_apm.start' do |app|
|
161
161
|
if Rails.env.development?
|
162
162
|
app.middleware.use ScoutApm::Instant::Middleware
|
163
163
|
end
|
@@ -167,4 +167,3 @@ if defined?(Rails) && defined?(Rails::VERSION) && defined?(Rails::VERSION::MAJOR
|
|
167
167
|
else
|
168
168
|
ScoutApm::Agent.instance.start
|
169
169
|
end
|
170
|
-
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
|
3
|
+
require 'scout_apm/ignored_uris'
|
4
|
+
|
5
|
+
class IgnoredUrlsTest < Minitest::Test
|
6
|
+
def test_ignores_prefix
|
7
|
+
i = ScoutApm::IgnoredUris.new(["/slow", "/health"])
|
8
|
+
assert_equal true, i.ignore?("/slow/foo/bar")
|
9
|
+
assert_equal true, i.ignore?("/health?leeches=true")
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_does_not_ignore_inner
|
13
|
+
i = ScoutApm::IgnoredUris.new(["/slow", "/health"])
|
14
|
+
assert_equal false, i.ignore?("/users/2/health")
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require_relative '../../test_helper'
|
2
|
+
require 'scout_apm/utils/backtrace_parser'
|
3
|
+
|
4
|
+
class BacktraceParserTest < Minitest::Test
|
5
|
+
|
6
|
+
################################################################################
|
7
|
+
# Helpers
|
8
|
+
|
9
|
+
def root
|
10
|
+
"/Users/scout/secret-next-big-thing/current"
|
11
|
+
end
|
12
|
+
|
13
|
+
def raw_backtrace(count=10)
|
14
|
+
count.times.map {|i| "#{root}/app/controllers/best_#{i}_controller.rb"}
|
15
|
+
end
|
16
|
+
|
17
|
+
################################################################################
|
18
|
+
# Tests
|
19
|
+
|
20
|
+
def test_maxes_at_APP_FRAMES
|
21
|
+
result = ScoutApm::Utils::BacktraceParser.new(raw_backtrace, root).call
|
22
|
+
|
23
|
+
assert_equal ScoutApm::Utils::BacktraceParser::APP_FRAMES, result.length
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_picks_off_top_of_trace
|
27
|
+
result = ScoutApm::Utils::BacktraceParser.new(raw_backtrace, root).call
|
28
|
+
|
29
|
+
assert_equal false, (result[0] =~ %r|app/controllers/best_0_controller.rb|).nil?
|
30
|
+
assert_equal false, (result[1] =~ %r|app/controllers/best_1_controller.rb|).nil?
|
31
|
+
assert_equal false, (result[2] =~ %r|app/controllers/best_2_controller.rb|).nil?
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_trims_off_root_dir
|
35
|
+
result = ScoutApm::Utils::BacktraceParser.new(raw_backtrace, root).call
|
36
|
+
|
37
|
+
result.each do |r|
|
38
|
+
assert_equal true, (r =~ %r|#{root}|).nil?
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_works_on_shorter_backtraces
|
43
|
+
result = ScoutApm::Utils::BacktraceParser.new(raw_backtrace(1), root).call
|
44
|
+
|
45
|
+
assert_equal 1, result.length
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_works_with_no_in_app_frames
|
49
|
+
result = ScoutApm::Utils::BacktraceParser.new(raw_backtrace, "/Users/scout/different-secrets").call
|
50
|
+
assert_equal 0, result.length
|
51
|
+
end
|
52
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: scout_apm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.1.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: 2016-08-
|
12
|
+
date: 2016-08-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rusage
|
@@ -137,6 +137,7 @@ files:
|
|
137
137
|
- lib/scout_apm/framework_integrations/ruby.rb
|
138
138
|
- lib/scout_apm/framework_integrations/sinatra.rb
|
139
139
|
- lib/scout_apm/histogram.rb
|
140
|
+
- lib/scout_apm/ignored_uris.rb
|
140
141
|
- lib/scout_apm/instant/assets/xmlhttp_instrumentation.html
|
141
142
|
- lib/scout_apm/instant/middleware.rb
|
142
143
|
- lib/scout_apm/instant_reporting.rb
|
@@ -226,6 +227,7 @@ files:
|
|
226
227
|
- test/unit/config_test.rb
|
227
228
|
- test/unit/environment_test.rb
|
228
229
|
- test/unit/histogram_test.rb
|
230
|
+
- test/unit/ignored_uris_test.rb
|
229
231
|
- test/unit/instruments/active_record_instruments_test.rb
|
230
232
|
- test/unit/layaway_test.rb
|
231
233
|
- test/unit/metric_set_test.rb
|
@@ -236,6 +238,7 @@ files:
|
|
236
238
|
- test/unit/slow_request_policy_test.rb
|
237
239
|
- test/unit/sql_sanitizer_test.rb
|
238
240
|
- test/unit/utils/active_record_metric_name_test.rb
|
241
|
+
- test/unit/utils/backtrace_parser_test.rb
|
239
242
|
homepage: https://github.com/scoutapp/scout_apm_ruby
|
240
243
|
licenses:
|
241
244
|
- Proprietary (See LICENSE.md)
|
@@ -257,7 +260,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
257
260
|
version: '0'
|
258
261
|
requirements: []
|
259
262
|
rubyforge_project: scout_apm
|
260
|
-
rubygems_version: 2.
|
263
|
+
rubygems_version: 2.6.2
|
261
264
|
signing_key:
|
262
265
|
specification_version: 4
|
263
266
|
summary: Ruby application performance monitoring
|
@@ -268,6 +271,7 @@ test_files:
|
|
268
271
|
- test/unit/config_test.rb
|
269
272
|
- test/unit/environment_test.rb
|
270
273
|
- test/unit/histogram_test.rb
|
274
|
+
- test/unit/ignored_uris_test.rb
|
271
275
|
- test/unit/instruments/active_record_instruments_test.rb
|
272
276
|
- test/unit/layaway_test.rb
|
273
277
|
- test/unit/metric_set_test.rb
|
@@ -278,3 +282,5 @@ test_files:
|
|
278
282
|
- test/unit/slow_request_policy_test.rb
|
279
283
|
- test/unit/sql_sanitizer_test.rb
|
280
284
|
- test/unit/utils/active_record_metric_name_test.rb
|
285
|
+
- test/unit/utils/backtrace_parser_test.rb
|
286
|
+
has_rdoc:
|