scout_apm 2.4.0.pre3 → 2.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|