scout_apm 3.0.0.pre16 → 3.0.0.pre17

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