scout_apm 2.4.0.pre3 → 2.4.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 +17 -0
- data/README.markdown +15 -7
- data/lib/scout_apm.rb +0 -1
- data/lib/scout_apm/agent.rb +9 -10
- data/lib/scout_apm/background_job_integrations/delayed_job.rb +0 -1
- data/lib/scout_apm/background_job_integrations/sidekiq.rb +7 -2
- data/lib/scout_apm/config.rb +3 -0
- data/lib/scout_apm/instruments/action_controller_rails_2.rb +0 -1
- data/lib/scout_apm/instruments/action_controller_rails_3_rails4.rb +0 -2
- data/lib/scout_apm/instruments/grape.rb +0 -1
- data/lib/scout_apm/instruments/http_client.rb +4 -1
- data/lib/scout_apm/instruments/net_http.rb +3 -1
- data/lib/scout_apm/instruments/resque.rb +0 -1
- data/lib/scout_apm/layaway.rb +21 -7
- data/lib/scout_apm/layer_converters/find_layer_by_type.rb +4 -0
- data/lib/scout_apm/rack.rb +2 -2
- data/lib/scout_apm/remote/server.rb +2 -0
- data/lib/scout_apm/tracked_request.rb +8 -15
- data/lib/scout_apm/version.rb +1 -1
- data/test/unit/background_job_integrations/sidekiq_test.rb +0 -3
- data/test/unit/test_tracked_request.rb +8 -44
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 35153897d05053c188035cea90a9c9821abcd4cf
|
4
|
+
data.tar.gz: 94fe5aee4fa214256fe31ffe643973274f2d66fb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: efef5649e203008c653a8fba69e1c28de35f510d831ff3e47a4483fda8e92116cd8aa5e1e64d3ab7ffe63cef9f03113987f953cc78f65a05af076be04fa1fb7b
|
7
|
+
data.tar.gz: 37966ab847e9c50ce354c9f8a2fe3c4ecfda397e091fc2d89f02b7816b2b14bfdd8e4bf56528a1f6572e9bb92b26ab6438b7a4bb83709969c887a8f904a810a0
|
data/CHANGELOG.markdown
CHANGED
@@ -1,10 +1,27 @@
|
|
1
1
|
# 2.4.0
|
2
2
|
|
3
3
|
* Rework agent startup sequence
|
4
|
+
* Install all background job instrumentations if you're running more than one
|
5
|
+
* Capture longer individual SQL statements
|
6
|
+
* Capture multiple SQL statements if multiple are run during a single AR call.
|
7
|
+
|
8
|
+
# 2.3.5
|
9
|
+
|
10
|
+
* More robust recovery from stale layaway files
|
11
|
+
* Quiet logging when hitting unusual layaway file limits
|
12
|
+
* Better naming for Sidekiq delayed method jobs
|
13
|
+
* Webrick is only required if actually needed
|
14
|
+
|
15
|
+
# 2.3.4
|
16
|
+
|
17
|
+
* Capture 300 characters of a url from net/http and httpclient instruments (up from 100).
|
4
18
|
|
5
19
|
# 2.3.3
|
6
20
|
|
7
21
|
* Capture ActiveRecord calls that generate more complex queries
|
22
|
+
* More aggressively determine names of complex queries (to determine "User/find", "Account/create" and similar)
|
23
|
+
* Increases the maximum size of SQL queries that are sanitized to 16KB from 4 KB
|
24
|
+
* Captures all SQL individual queries generated in a given AR call (previous only a single query was captured)
|
8
25
|
|
9
26
|
# 2.3.2
|
10
27
|
|
data/README.markdown
CHANGED
@@ -1,14 +1,21 @@
|
|
1
|
-
# ScoutApm
|
1
|
+
# ScoutApm Ruby Agent
|
2
2
|
|
3
|
-
A Ruby gem for detailed Rails application performance analysis. Metrics are
|
3
|
+
A Ruby gem for detailed Rails application performance analysis. Metrics are
|
4
|
+
reported to [Scout](https://scoutapp.com), a hosted application monitoring
|
5
|
+
service.
|
4
6
|
|
5
7
|
## Getting Started
|
6
8
|
|
7
|
-
|
9
|
+
Add the gem to your Gemfile
|
8
10
|
|
9
|
-
gem
|
10
|
-
|
11
|
-
|
11
|
+
gem 'scout_apm'
|
12
|
+
|
13
|
+
Update your Gemfile
|
14
|
+
|
15
|
+
bundle install
|
16
|
+
|
17
|
+
Signup for a [Scout](https://apm.scoutapp.com) account and put the provided
|
18
|
+
config file at `RAILS_ROOT/config/scout_apm.yml`.
|
12
19
|
|
13
20
|
Your config file should look like:
|
14
21
|
|
@@ -22,7 +29,8 @@ Your config file should look like:
|
|
22
29
|
|
23
30
|
## Docs
|
24
31
|
|
25
|
-
For the complete list of supported frameworks, Rubies,
|
32
|
+
For the complete list of supported frameworks, Rubies, configuration options
|
33
|
+
and more, see our [help site](http://help.apm.scoutapp.com/).
|
26
34
|
|
27
35
|
## Help
|
28
36
|
|
data/lib/scout_apm.rb
CHANGED
data/lib/scout_apm/agent.rb
CHANGED
@@ -43,18 +43,18 @@ module ScoutApm
|
|
43
43
|
install_background_job_integrations
|
44
44
|
install_app_server_integration
|
45
45
|
|
46
|
-
# XXX: Should this happen at application start?
|
47
|
-
# Should this ever happen after fork?
|
48
|
-
# We start a thread in this, which can screw stuff up when we then fork.
|
49
|
-
#
|
50
|
-
# Save it into a variable to prevent it from ever running twice
|
51
|
-
@app_server_load ||= AppServerLoad.new(context).run
|
52
|
-
|
53
46
|
logger.info "Scout Agent [#{ScoutApm::VERSION}] installed"
|
54
47
|
|
55
48
|
context.installed!
|
56
49
|
|
57
50
|
if ScoutApm::Agent::Preconditions.check?(context) || force
|
51
|
+
# XXX: Should this happen at application start?
|
52
|
+
# Should this ever happen after fork?
|
53
|
+
# We start a thread in this, which can screw stuff up when we then fork.
|
54
|
+
#
|
55
|
+
# Save it into a variable to prevent it from ever running twice
|
56
|
+
@app_server_load ||= AppServerLoad.new(context).run
|
57
|
+
|
58
58
|
start
|
59
59
|
end
|
60
60
|
end
|
@@ -124,9 +124,8 @@ module ScoutApm
|
|
124
124
|
|
125
125
|
def should_load_instruments?
|
126
126
|
return true if context.config.value('dev_trace')
|
127
|
-
|
128
|
-
|
129
|
-
context.environment.app_server_integration.found? || context.environment.background_job_integration
|
127
|
+
return false unless context.config.value('monitor')
|
128
|
+
context.environment.app_server_integration.found? || context.environment.background_job_integrations.any?
|
130
129
|
end
|
131
130
|
|
132
131
|
#################################
|
@@ -57,7 +57,6 @@ module ScoutApm
|
|
57
57
|
class SidekiqMiddleware
|
58
58
|
def call(_worker, msg, queue)
|
59
59
|
req = ScoutApm::RequestManager.lookup
|
60
|
-
req.job!
|
61
60
|
req.annotate_request(:queue_latency => latency(msg))
|
62
61
|
|
63
62
|
begin
|
@@ -92,10 +91,16 @@ module ScoutApm
|
|
92
91
|
end
|
93
92
|
elsif job_class == DELAYED_WRAPPER_KLASS
|
94
93
|
begin
|
94
|
+
# Extract the info out of the wrapper
|
95
95
|
yml = msg['args'].first
|
96
96
|
deserialized_args = YAML.load(yml)
|
97
97
|
klass, method, *rest = deserialized_args
|
98
|
-
|
98
|
+
|
99
|
+
# If this is an instance of a class, get the class itself
|
100
|
+
# Prevents instances from coming through named like "#<Foo:0x007ffd7a9dd8a0>"
|
101
|
+
klass = klass.class unless klass.is_a? Module
|
102
|
+
|
103
|
+
job_class = [klass, method].map(&:to_s).join(".")
|
99
104
|
rescue
|
100
105
|
DELAYED_WRAPPER_KLASS
|
101
106
|
end
|
data/lib/scout_apm/config.rb
CHANGED
@@ -66,6 +66,7 @@ module ScoutApm
|
|
66
66
|
'report_format',
|
67
67
|
'scm_subdirectory',
|
68
68
|
'uri_reporting',
|
69
|
+
'instrument_http_url_length',
|
69
70
|
]
|
70
71
|
|
71
72
|
################################################################################
|
@@ -153,6 +154,7 @@ module ScoutApm
|
|
153
154
|
"monitor" => BooleanCoercion.new,
|
154
155
|
'database_metric_limit' => IntegerCoercion.new,
|
155
156
|
'database_metric_report_limit' => IntegerCoercion.new,
|
157
|
+
'instrument_http_url_length' => IntegerCoercion.new,
|
156
158
|
}
|
157
159
|
|
158
160
|
|
@@ -256,6 +258,7 @@ module ScoutApm
|
|
256
258
|
'remote_agent_port' => 7721, # picked at random
|
257
259
|
'database_metric_limit' => 5000, # The hard limit on db metrics
|
258
260
|
'database_metric_report_limit' => 1000,
|
261
|
+
'instrument_http_url_length' => 300,
|
259
262
|
}.freeze
|
260
263
|
|
261
264
|
def value(key)
|
@@ -57,7 +57,6 @@ module ScoutApm
|
|
57
57
|
req.context.add_user(:ip => request.remote_ip)
|
58
58
|
req.set_headers(request.headers)
|
59
59
|
req.start_layer( ScoutApm::Layer.new("Controller", "#{controller_path}/#{action_name}") )
|
60
|
-
req.web!
|
61
60
|
|
62
61
|
begin
|
63
62
|
perform_action_without_scout_instruments(*args, &block)
|
@@ -77,8 +77,6 @@ module ScoutApm
|
|
77
77
|
req.context.add_user(:ip => request.remote_ip) rescue nil
|
78
78
|
req.set_headers(request.headers)
|
79
79
|
|
80
|
-
req.web!
|
81
|
-
|
82
80
|
resolved_name = scout_action_name(*args)
|
83
81
|
req.start_layer( ScoutApm::Layer.new("Controller", "#{controller_path}/#{resolved_name}") )
|
84
82
|
begin
|
@@ -26,9 +26,12 @@ module ScoutApm
|
|
26
26
|
include ScoutApm::Tracer
|
27
27
|
|
28
28
|
def request_with_scout_instruments(*args, &block)
|
29
|
+
|
29
30
|
method = args[0].to_s
|
30
31
|
url = args[1]
|
31
|
-
|
32
|
+
|
33
|
+
max_length = ScoutApm::Agent.instance.context.config.value('instrument_http_url_length')
|
34
|
+
url = url && url.to_s[0..(max_length - 1)]
|
32
35
|
|
33
36
|
self.class.instrument("HTTP", method, :desc => url) do
|
34
37
|
request_without_scout_instruments(*args, &block)
|
@@ -34,7 +34,9 @@ module ScoutApm
|
|
34
34
|
def request_scout_description(req)
|
35
35
|
path = req.path
|
36
36
|
path = path.path if path.respond_to?(:path)
|
37
|
-
|
37
|
+
|
38
|
+
max_length = ScoutApm::Agent.instance.context.config.value('instrument_http_url_length')
|
39
|
+
(@address + path.split('?').first)[0..(max_length - 1)]
|
38
40
|
end
|
39
41
|
|
40
42
|
alias request_without_scout_instruments request
|
data/lib/scout_apm/layaway.rb
CHANGED
@@ -51,7 +51,8 @@ module ScoutApm
|
|
51
51
|
|
52
52
|
def write_reporting_period(reporting_period, files_limit = MAX_FILES_LIMIT)
|
53
53
|
if at_layaway_file_limit?(files_limit)
|
54
|
-
|
54
|
+
# This will happen constantly once we hit this case, so only log the first time
|
55
|
+
@wrote_layaway_limit_error_message ||= logger.error("Hit layaway file limit. Not writing to layaway file")
|
55
56
|
return false
|
56
57
|
end
|
57
58
|
filename = file_for(reporting_period.timestamp)
|
@@ -59,9 +60,22 @@ module ScoutApm
|
|
59
60
|
layaway_file.write(reporting_period)
|
60
61
|
end
|
61
62
|
|
62
|
-
# Claims a given timestamp
|
63
|
-
#
|
64
|
-
#
|
63
|
+
# Claims a given timestamp by getting an exclusive lock on a timestamped
|
64
|
+
# coordinator file. The coordinator file never contains data, it's just a
|
65
|
+
# syncronization mechanism.
|
66
|
+
#
|
67
|
+
# Once the 'claim' is obtained:
|
68
|
+
# * load and yield each ReportingPeriod from the layaway files.
|
69
|
+
# * if there are reporting periods:
|
70
|
+
# * yields any ReportingPeriods collected up from all the files.
|
71
|
+
# * deletes all of the layaway files (including the coordinator) for the timestamp
|
72
|
+
# * if not
|
73
|
+
# * delete the coordinator
|
74
|
+
# * remove any stale layaway files that may be hanging around.
|
75
|
+
# * Finally unlock and ensure the coordinator file is cleared.
|
76
|
+
#
|
77
|
+
# If a claim file can't be obtained, return false without doing any work
|
78
|
+
# Another process is handling the reporting.
|
65
79
|
def with_claim(timestamp)
|
66
80
|
coordinator_file = glob_pattern(timestamp, :coordinator)
|
67
81
|
|
@@ -86,14 +100,14 @@ module ScoutApm
|
|
86
100
|
|
87
101
|
logger.debug("Deleting the now-reported layaway files for #{timestamp.to_s}")
|
88
102
|
delete_files_for(timestamp) # also removes the coodinator_file
|
89
|
-
|
90
|
-
logger.debug("Checking for any Stale layaway files")
|
91
|
-
delete_stale_files(timestamp.to_time - STALE_AGE)
|
92
103
|
else
|
93
104
|
File.unlink(coordinator_file)
|
94
105
|
logger.debug("No layaway files to report")
|
95
106
|
end
|
96
107
|
|
108
|
+
logger.debug("Checking for any Stale layaway files")
|
109
|
+
delete_stale_files(timestamp.to_time - STALE_AGE)
|
110
|
+
|
97
111
|
true
|
98
112
|
rescue Exception => e
|
99
113
|
logger.debug("Caught an exception in with_claim, with the coordination file locked: #{e.message}, #{e.backtrace.inspect}")
|
data/lib/scout_apm/rack.rb
CHANGED
@@ -10,8 +10,8 @@ module ScoutApm
|
|
10
10
|
req.annotate_request(:uri => env["REQUEST_PATH"]) rescue nil
|
11
11
|
req.context.add_user(:ip => env["REMOTE_ADDR"]) rescue nil
|
12
12
|
|
13
|
-
|
14
|
-
req.start_layer(
|
13
|
+
layer = ScoutApm::Layer.new('Controller', endpoint_name)
|
14
|
+
req.start_layer(layer)
|
15
15
|
|
16
16
|
begin
|
17
17
|
yield
|
@@ -26,10 +26,6 @@ module ScoutApm
|
|
26
26
|
# Can be nil if we never reach a Rails Controller
|
27
27
|
attr_reader :headers
|
28
28
|
|
29
|
-
# What kind of request is this? A trace of a web request, or a background job?
|
30
|
-
# Use job! and web! to set, and job? and web? to query
|
31
|
-
attr_reader :request_type
|
32
|
-
|
33
29
|
# This maintains a lookup hash of Layer names and call counts. It's used to trigger fetching a backtrace on n+1 calls.
|
34
30
|
# Note that layer names might not be Strings - can alse be Utils::ActiveRecordMetricName. Also, this would fail for layers
|
35
31
|
# with same names across multiple types.
|
@@ -222,20 +218,14 @@ module ScoutApm
|
|
222
218
|
@headers = headers
|
223
219
|
end
|
224
220
|
|
225
|
-
|
226
|
-
@request_type = "job"
|
227
|
-
end
|
228
|
-
|
221
|
+
# This request is a job transaction iff it has a 'Job' layer
|
229
222
|
def job?
|
230
|
-
|
231
|
-
end
|
232
|
-
|
233
|
-
def web!
|
234
|
-
@request_type = "web"
|
223
|
+
layer_finder.job != nil
|
235
224
|
end
|
236
225
|
|
226
|
+
# This request is a web transaction iff it has a 'Controller' layer
|
237
227
|
def web?
|
238
|
-
|
228
|
+
layer_finder.controller != nil
|
239
229
|
end
|
240
230
|
|
241
231
|
def instant?
|
@@ -279,7 +269,6 @@ module ScoutApm
|
|
279
269
|
LayerConverters::SlowRequestConverter,
|
280
270
|
]
|
281
271
|
|
282
|
-
layer_finder = LayerConverters::FindLayerByType.new(self)
|
283
272
|
walker = LayerConverters::DepthFirstWalker.new(self.root_layer)
|
284
273
|
converters = converters.map do |klass|
|
285
274
|
instance = klass.new(@agent_context, self, layer_finder, @store)
|
@@ -301,6 +290,10 @@ module ScoutApm
|
|
301
290
|
end
|
302
291
|
end
|
303
292
|
|
293
|
+
def layer_finder
|
294
|
+
@layer_finder ||= LayerConverters::FindLayerByType.new(self)
|
295
|
+
end
|
296
|
+
|
304
297
|
# Ensure the background worker thread is up & running - a fallback if other
|
305
298
|
# detection doesn't achieve this at boot.
|
306
299
|
def ensure_background_worker
|
data/lib/scout_apm/version.rb
CHANGED
@@ -11,7 +11,6 @@ class SidekiqTest < Minitest::Test
|
|
11
11
|
def test_middleware_call_happy_path
|
12
12
|
fake_request = mock
|
13
13
|
fake_request.expects(:annotate_request)
|
14
|
-
fake_request.expects(:job!)
|
15
14
|
fake_request.expects(:start_layer).twice
|
16
15
|
fake_request.expects(:stop_layer).twice
|
17
16
|
fake_request.expects(:error!).never
|
@@ -29,7 +28,6 @@ class SidekiqTest < Minitest::Test
|
|
29
28
|
def test_middleware_call_job_exception
|
30
29
|
fake_request = mock
|
31
30
|
fake_request.expects(:annotate_request)
|
32
|
-
fake_request.expects(:job!)
|
33
31
|
fake_request.expects(:start_layer).twice
|
34
32
|
fake_request.expects(:stop_layer).twice
|
35
33
|
fake_request.expects(:error!)
|
@@ -47,7 +45,6 @@ class SidekiqTest < Minitest::Test
|
|
47
45
|
def test_middleware_call_edge_cases
|
48
46
|
fake_request = mock
|
49
47
|
fake_request.expects(:annotate_request)
|
50
|
-
fake_request.expects(:job!)
|
51
48
|
fake_request.expects(:start_layer).twice
|
52
49
|
fake_request.expects(:stop_layer).twice
|
53
50
|
fake_request.expects(:error!)
|
@@ -3,7 +3,7 @@ require 'test_helper'
|
|
3
3
|
class TrackedRequestDumpAndLoadTest < Minitest::Test
|
4
4
|
# TrackedRequest must be marshalable
|
5
5
|
def test_marshal_dump_load
|
6
|
-
tr = ScoutApm::TrackedRequest.new(ScoutApm::FakeStore.new)
|
6
|
+
tr = ScoutApm::TrackedRequest.new(ScoutApm::AgentContext.new, ScoutApm::FakeStore.new)
|
7
7
|
tr.prepare_to_dump!
|
8
8
|
|
9
9
|
dumped = Marshal.dump(tr)
|
@@ -12,58 +12,22 @@ class TrackedRequestDumpAndLoadTest < Minitest::Test
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def test_restore_store
|
15
|
-
|
16
|
-
|
17
|
-
|
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")
|
18
19
|
|
19
20
|
tr.prepare_to_dump!
|
20
21
|
assert_nil tr.instance_variable_get("@store")
|
21
22
|
|
22
23
|
tr.restore_store
|
23
|
-
assert_equal
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
class TrackedRequestFlagsTest < Minitest::Test
|
28
|
-
def test_set_web
|
29
|
-
tr = ScoutApm::TrackedRequest.new(ScoutApm::FakeStore.new)
|
30
|
-
assert_false tr.web?
|
31
|
-
tr.web!
|
32
|
-
assert tr.web?
|
33
|
-
end
|
34
|
-
|
35
|
-
def test_set_job
|
36
|
-
tr = ScoutApm::TrackedRequest.new(ScoutApm::FakeStore.new)
|
37
|
-
assert ! tr.job?
|
38
|
-
tr.job!
|
39
|
-
assert tr.job?
|
40
|
-
end
|
41
|
-
|
42
|
-
def test_set_error
|
43
|
-
tr = ScoutApm::TrackedRequest.new(ScoutApm::FakeStore.new)
|
44
|
-
assert_false tr.error?
|
45
|
-
tr.error!
|
46
|
-
assert tr.error?
|
47
|
-
end
|
48
|
-
|
49
|
-
def test_set_error_and_web
|
50
|
-
tr = ScoutApm::TrackedRequest.new(ScoutApm::FakeStore.new)
|
51
|
-
assert_false tr.error?
|
52
|
-
assert_false tr.web?
|
53
|
-
|
54
|
-
tr.web!
|
55
|
-
assert_false tr.error?
|
56
|
-
assert tr.web?
|
57
|
-
|
58
|
-
tr.error!
|
59
|
-
assert tr.error?
|
60
|
-
assert tr.web?
|
24
|
+
assert_equal context.store, tr.instance_variable_get("@store")
|
61
25
|
end
|
62
26
|
end
|
63
27
|
|
64
28
|
class TrackedRequestLayerManipulationTest < Minitest::Test
|
65
29
|
def test_start_layer
|
66
|
-
tr = ScoutApm::TrackedRequest.new(ScoutApm::FakeStore.new)
|
30
|
+
tr = ScoutApm::TrackedRequest.new(ScoutApm::AgentContext.new, ScoutApm::FakeStore.new)
|
67
31
|
tr.start_layer(ScoutApm::Layer.new("Foo", "Bar"))
|
68
32
|
|
69
33
|
assert_equal "Foo", tr.current_layer.type
|
@@ -74,7 +38,7 @@ class TrackedRequestLayerManipulationTest < Minitest::Test
|
|
74
38
|
controller_layer = ScoutApm::Layer.new("Controller", "users/index")
|
75
39
|
ar_layer = ScoutApm::Layer.new("ActiveRecord", "Users#find")
|
76
40
|
|
77
|
-
tr = ScoutApm::TrackedRequest.new(ScoutApm::FakeStore.new)
|
41
|
+
tr = ScoutApm::TrackedRequest.new(ScoutApm::AgentContext.new, ScoutApm::FakeStore.new)
|
78
42
|
tr.start_layer(controller_layer)
|
79
43
|
tr.start_layer(ar_layer)
|
80
44
|
|
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.0
|
4
|
+
version: 2.4.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: 2018-01-13 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: minitest
|
@@ -360,9 +360,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
360
360
|
version: '0'
|
361
361
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
362
362
|
requirements:
|
363
|
-
- - "
|
363
|
+
- - ">="
|
364
364
|
- !ruby/object:Gem::Version
|
365
|
-
version:
|
365
|
+
version: '0'
|
366
366
|
requirements: []
|
367
367
|
rubyforge_project: scout_apm
|
368
368
|
rubygems_version: 2.4.5.2
|