scout_apm 3.0.0.pre16 → 3.0.0.pre17

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 48d7c95db58d0248a431b10cb8501128892ed804
4
- data.tar.gz: cee8126c3395ee5b45c2c42b4523d95e901f2817
3
+ metadata.gz: 2ca61b61ba4135b8ee89ffb1efb4946f0c0afa44
4
+ data.tar.gz: d980d2baab58e6ceecf1d54aa97128180cf9052e
5
5
  SHA512:
6
- metadata.gz: 84c6a1840c5bbdba0770967ded0a6de09d396080c384044c723a53a872ce0b6fec3aa83bf930f8f8f3709f9a50f6b896e3641d53dbe7f9428769ff158b5a49d8
7
- data.tar.gz: fe384265d5792579373739d283da2efbcd3eb4fb1f32b0e4281100154b8050b321f7c8bf751ca38fb136e06e5c33cab9366359c80a22e0d90ac9feed180140fa
6
+ metadata.gz: 5bd058b09d66c99c304af71ca7343462d02dc588230253712462fdad6628f718bad8a33655de42f1eb27ae98e2cec39840f247173e4fe0cf1ef0110dbb727105
7
+ data.tar.gz: 2cd9079153c0d8f050055ae62e7d3c18531b6e90e6d5a4e12661c0cd5e598ab930584229304d2a44017347f00cb2fada6e407bfbc5b54a8ce871e3df91147f3d
data/CHANGELOG.markdown CHANGED
@@ -2,9 +2,31 @@
2
2
 
3
3
  * ScoutProf BETA
4
4
 
5
+ # 2.4.3
6
+
7
+ * Ensure a startup hook runs on forking webservers
8
+
9
+ # 2.4.2
10
+
11
+ * Fix shutdown hook for Passenger
12
+
13
+ # 2.4.1
14
+
15
+ * Fix logging on STDOUT only platforms (Heroku)
16
+
5
17
  # 2.4.0
6
18
 
7
19
  * Rework agent startup sequence
20
+ * Install all background job instrumentations if you're running more than one
21
+ * Capture longer individual SQL statements
22
+ * Capture multiple SQL statements if multiple are run during a single AR call.
23
+
24
+ # 2.3.5
25
+
26
+ * More robust recovery from stale layaway files
27
+ * Quiet logging when hitting unusual layaway file limits
28
+ * Better naming for Sidekiq delayed method jobs
29
+ * Webrick is only required if actually needed
8
30
 
9
31
  # 2.3.4
10
32
 
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 reported to [Scout](https://scoutapp.com), a hosted application monitoring service.
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
- Install the gem:
9
+ Add the gem to your Gemfile
8
10
 
9
- gem install scout_apm
10
-
11
- Signup for a [Scout](https://apm.scoutapp.com) account and copy the config file to `RAILS_ROOT/config/scout_apm.yml`.
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, etc, see our [help site](http://help.apm.scoutapp.com/).
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
 
@@ -48,13 +48,6 @@ module ScoutApm
48
48
  context.installed!
49
49
 
50
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
51
  start
59
52
  end
60
53
  end
@@ -75,6 +68,9 @@ module ScoutApm
75
68
 
76
69
  log_environment
77
70
 
71
+ # Save it into a variable to prevent it from ever running twice
72
+ @app_server_load ||= AppServerLoad.new(context).run
73
+
78
74
  start_background_worker
79
75
  end
80
76
 
@@ -124,6 +120,7 @@ module ScoutApm
124
120
 
125
121
  def should_load_instruments?
126
122
  return true if context.config.value('dev_trace')
123
+ return false unless context.config.value('monitor')
127
124
  context.environment.app_server_integration.found? || context.environment.background_job_integrations.any?
128
125
  end
129
126
 
@@ -220,7 +220,7 @@ module ScoutApm
220
220
  {
221
221
  :log_level => config.value('log_level'),
222
222
  :log_file_path => config.value('log_file_path'),
223
- :stdout => config.value('log_stdout'),
223
+ :stdout => config.value('log_stdout') || environment.platform_integration.log_to_stdout?,
224
224
  :stderr => config.value('log_stderr'),
225
225
  :logger_class => config.value('log_class'),
226
226
  }
@@ -51,7 +51,6 @@ module ScoutApm
51
51
  queue = job.queue || "default"
52
52
 
53
53
  req = ScoutApm::RequestManager.lookup
54
- req.job!
55
54
 
56
55
  begin
57
56
  latency = Time.now - job.created_at
@@ -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
  queue_layer = ScoutApm::Layer.new('Queue', queue)
@@ -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
  layer = ScoutApm::Layer.new("Controller", "#{controller_path}/#{resolved_name}")
84
82
 
@@ -44,7 +44,6 @@ module ScoutApm
44
44
  req.context.add_user(:ip => request.ip) rescue nil
45
45
 
46
46
  req.set_headers(request.headers)
47
- req.web!
48
47
 
49
48
  begin
50
49
  name = ["Grape",
@@ -11,7 +11,6 @@ module ScoutApm
11
11
  end
12
12
 
13
13
  req = ScoutApm::RequestManager.lookup
14
- req.job!
15
14
 
16
15
  begin
17
16
  req.start_layer(ScoutApm::Layer.new('Queue', queue))
@@ -16,6 +16,10 @@ module ScoutApm
16
16
  @scope ||= call(["Controller", "Job"])
17
17
  end
18
18
 
19
+ def controller
20
+ @controller ||= call(["Controller"])
21
+ end
22
+
19
23
  def job
20
24
  @job ||= call(["Job"])
21
25
  end
@@ -40,7 +40,11 @@ module ScoutApm
40
40
  def fatal(*args, &block); @logger.fatal(*args, &block); end
41
41
 
42
42
  def log_level=(level)
43
- @logger.level = level
43
+ @logger.level = log_level_from_opts(level)
44
+ end
45
+
46
+ def log_level
47
+ @logger.level
44
48
  end
45
49
 
46
50
  def log_file_path
@@ -48,11 +52,11 @@ module ScoutApm
48
52
  end
49
53
 
50
54
  def stdout?
51
- @opts[:stdout] || @opts[:log_file_path] == "STDOUT"
55
+ @opts[:stdout] || (@opts[:log_file_path] || "").upcase == "STDOUT"
52
56
  end
53
57
 
54
58
  def stderr?
55
- @opts[:stderr] || @opts[:log_file_path] == "STDERR"
59
+ @opts[:stderr] || (@opts[:log_file_path] || "").upcase == "STDERR"
56
60
  end
57
61
 
58
62
  private
@@ -86,13 +90,16 @@ module ScoutApm
86
90
  end
87
91
  end
88
92
 
89
- def log_level_from_opts
90
- case @opts[:log_level]
93
+ def log_level_from_opts(explicit=nil)
94
+ candidate = explicit || (@opts[:log_level] || "").downcase
95
+
96
+ case candidate
91
97
  when "debug" then ::Logger::DEBUG
92
98
  when "info" then ::Logger::INFO
93
99
  when "warn" then ::Logger::WARN
94
100
  when "error" then ::Logger::ERROR
95
101
  when "fatal" then ::Logger::FATAL
102
+ when ::Logger::DEBUG, ::Logger::INFO, ::Logger::WARN, ::Logger::ERROR, ::Logger::FATAL then candidate
96
103
  else ::Logger::INFO
97
104
  end
98
105
  end
@@ -116,11 +123,12 @@ module ScoutApm
116
123
  # Check if this path is ok for a log file.
117
124
  # Does it exist?
118
125
  # Is it writable?
119
- # XXX: Implement
120
126
  def validate_path(candidate)
121
- !candidate.nil?
122
- end
127
+ return false if candidate.nil?
123
128
 
129
+ directory = File.dirname(candidate)
130
+ File.writable?(directory)
131
+ end
124
132
 
125
133
  class DefaultFormatter < ::Logger::Formatter
126
134
  def call(severity, time, progname, msg)
@@ -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
- req.web!
14
- req.start_layer(ScoutApm::Layer.new('Controller', endpoint_name))
13
+ layer = ScoutApm::Layer.new('Controller', endpoint_name)
14
+ req.start_layer(layer)
15
15
 
16
16
  begin
17
17
  yield
@@ -29,7 +29,7 @@ module ScoutApm
29
29
  # This does run when a process stops.
30
30
  PhusionPassenger.on_event(:stopping_worker_process) do
31
31
  logger.debug "Passenger is stopping a worker process, shutting down the agent."
32
- ScoutApm::Agent.instance.shutdown
32
+ ScoutApm::Agent.instance.stop_background_worker
33
33
  end
34
34
  end
35
35
 
@@ -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.
@@ -249,20 +245,14 @@ module ScoutApm
249
245
  @headers = headers
250
246
  end
251
247
 
252
- def job!
253
- @request_type = "job"
254
- end
255
-
248
+ # This request is a job transaction iff it has a 'Job' layer
256
249
  def job?
257
- request_type == "job"
258
- end
259
-
260
- def web!
261
- @request_type = "web"
250
+ layer_finder.job != nil
262
251
  end
263
252
 
253
+ # This request is a web transaction iff it has a 'Controller' layer
264
254
  def web?
265
- request_type == "web"
255
+ layer_finder.controller != nil
266
256
  end
267
257
 
268
258
  def instant?
@@ -306,7 +296,6 @@ module ScoutApm
306
296
  LayerConverters::SlowRequestConverter,
307
297
  ]
308
298
 
309
- layer_finder = LayerConverters::FindLayerByType.new(self)
310
299
  walker = LayerConverters::DepthFirstWalker.new(self.root_layer)
311
300
  converters = converters.map do |klass|
312
301
  instance = klass.new(@agent_context, self, layer_finder, @store)
@@ -328,6 +317,10 @@ module ScoutApm
328
317
  end
329
318
  end
330
319
 
320
+ def layer_finder
321
+ @layer_finder ||= LayerConverters::FindLayerByType.new(self)
322
+ end
323
+
331
324
  # Ensure the background worker thread is up & running - a fallback if other
332
325
  # detection doesn't achieve this at boot.
333
326
  def ensure_background_worker
@@ -1,3 +1,3 @@
1
1
  module ScoutApm
2
- VERSION = "3.0.0.pre16"
2
+ VERSION = "3.0.0.pre17"
3
3
  end
@@ -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!)
@@ -0,0 +1,67 @@
1
+ require 'test_helper'
2
+
3
+ require 'scout_apm/logger'
4
+
5
+ class LoggerTest < Minitest::Test
6
+ def setup
7
+ @env_root = Pathname.new(File.dirname(__FILE__)) + "../../"
8
+ end
9
+
10
+ def test_detect_stdout
11
+ logger = ScoutApm::Logger.new("", { :log_file_path => "STDOUT"})
12
+ assert logger.stdout?
13
+ assert_equal STDOUT, logger.log_destination
14
+
15
+ # and lowercase
16
+ logger = ScoutApm::Logger.new("", { :log_file_path => "stdout"})
17
+ assert logger.stdout?
18
+ assert_equal STDOUT, logger.log_destination
19
+ end
20
+
21
+ def test_force_stdout
22
+ logger = ScoutApm::Logger.new("", { :stdout => true })
23
+ assert logger.stdout?
24
+ assert_equal STDOUT, logger.log_destination
25
+ end
26
+
27
+ def test_pick_log_file_with_no_options
28
+ logger = ScoutApm::Logger.new(@env_root, { })
29
+ assert_equal (@env_root + "log" + "scout_apm.log").to_s, logger.log_destination
30
+ end
31
+
32
+ def test_pick_log_file_with_different_dir
33
+ logger = ScoutApm::Logger.new(@env_root, { :log_file_path => "/tmp" })
34
+ assert_equal "/tmp/scout_apm.log", logger.log_destination
35
+ end
36
+
37
+ def test_pick_log_file_invalid_dir
38
+ logger = ScoutApm::Logger.new(@env_root, { :log_file_path => "/not_a_real_dir" })
39
+ assert_equal STDOUT, logger.log_destination
40
+ end
41
+
42
+ def test_pick_log_dir_not_writable
43
+ Dir.mktmpdir { |dir|
44
+ # An unwritable dir
45
+ FileUtils.chmod(0000, dir)
46
+ logger = ScoutApm::Logger.new(@env_root, { :log_file_path => dir })
47
+ assert_equal STDOUT, logger.log_destination
48
+
49
+ # so it can be deleted
50
+ FileUtils.chmod(0700, dir)
51
+ }
52
+ end
53
+
54
+ def test_set_log_level
55
+ logger = ScoutApm::Logger.new(@env_root, { :log_level => "debug" })
56
+ assert_equal ::Logger::DEBUG, logger.log_level
57
+ end
58
+
59
+ def test_set_log_level_after
60
+ logger = ScoutApm::Logger.new(@env_root, { :log_level => "debug" })
61
+ logger.log_level = "info"
62
+ assert_equal ::Logger::INFO, logger.log_level
63
+
64
+ logger.log_level = ::Logger::ERROR
65
+ assert_equal ::Logger::ERROR, logger.log_level
66
+ end
67
+ end
@@ -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
- faux = ScoutApm::FakeStore.new
16
- tr = ScoutApm::TrackedRequest.new(faux)
17
- assert_equal faux, tr.instance_variable_get("@store")
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 ScoutApm::Agent.instance.store, tr.instance_variable_get("@store")
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: 3.0.0.pre16
4
+ version: 3.0.0.pre17
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: 2018-01-04 00:00:00.000000000 Z
12
+ date: 2018-01-18 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: minitest
@@ -335,6 +335,7 @@ files:
335
335
  - test/unit/layer_converters/metric_converter_test.rb
336
336
  - test/unit/layer_converters/stubs.rb
337
337
  - test/unit/limited_layer_test.rb
338
+ - test/unit/logger_test.rb
338
339
  - test/unit/metric_set_test.rb
339
340
  - test/unit/remote/test_message.rb
340
341
  - test/unit/remote/test_router.rb
@@ -399,6 +400,7 @@ test_files:
399
400
  - test/unit/layer_converters/metric_converter_test.rb
400
401
  - test/unit/layer_converters/stubs.rb
401
402
  - test/unit/limited_layer_test.rb
403
+ - test/unit/logger_test.rb
402
404
  - test/unit/metric_set_test.rb
403
405
  - test/unit/remote/test_message.rb
404
406
  - test/unit/remote/test_router.rb