scout_apm 3.0.0.pre20 → 3.0.0.pre21

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: f047a3fde038ff766a4257bd06039aaa57bc5eda
4
- data.tar.gz: 2e3aecc744bff0176bb449f0bade29a43ff2810d
3
+ metadata.gz: eb5a7880c0007cdc98449e7598022481be64b83f
4
+ data.tar.gz: b195f2ea2a704b97be089d38af6cb84145d96856
5
5
  SHA512:
6
- metadata.gz: 57f0e123ba394164ea2263195a204f77787e254e8396bb5a0ca346523470f4e447e53b456005a082949e6f7f6a9154ac55b71cf701b19a7e8517f709591761fd
7
- data.tar.gz: 555e23d6f39fd9c1ea919ab15f7fa28b868fef854c7f0dec610db7bc9ea20438de8d30a1c6c932e7d389cd5bd40f2a3b58af53b29e9fe44e965c8ff8b7ca2d8a
6
+ metadata.gz: 3d181d12bf746066430840488485e2e96370a33ebfc6db4b7e6c25d9cb07763d380867bf6aabf3595044451ba1a657a6d03b1d739b567e430da431f2de854a59
7
+ data.tar.gz: f4149e4757f16f481ca9e9d4a3ababc1ec9ba3cb66718bffe2de207ae12b01f56fa81d0f14cf0d1b3348d7c8cf97d28809a6ec75ad6bdbb1a3af573a2de684bd
@@ -1,8 +1,13 @@
1
+ # Disable all cops by default
2
+ AllCops:
3
+ DisabledByDefault: true
4
+
1
5
  # 80 is stifling, especially with a few levels of nesting before we even start.
2
6
  # So bump it to 100 to keep really long lines from creeping in.
3
7
  Metrics/LineLength:
8
+ Enabled: false
4
9
  Max: 100
5
10
 
6
- Style/UseHashRocketsWithSymbolValues: false
7
-
8
-
11
+ Style/HashSyntax:
12
+ Enabled: true
13
+ EnforcedStyle: hash_rockets
@@ -0,0 +1,14 @@
1
+ language: ruby
2
+ rvm:
3
+ - "1.8.7"
4
+ - "1.9.3"
5
+ - "2.0"
6
+ - "2.2"
7
+ - "2.4"
8
+ - "2.5"
9
+ cache: bundler
10
+ jobs:
11
+ include:
12
+ - script: bundle exec rake test
13
+ - script: bundle exec rubocop
14
+ rvm: "2.5"
@@ -2,6 +2,18 @@
2
2
 
3
3
  * ScoutProf BETA
4
4
 
5
+ # 2.4.9
6
+
7
+ * ScoutApm::Transaction#rename and #ignore API
8
+ * Explicit custom instrumentation with ScoutApm::Tracer#instrument blocks,
9
+ without needing to include a module
10
+ * Quieter logging in normal startup cases
11
+ * Upgraded testing infrastructure
12
+
13
+ # 2.4.8
14
+
15
+ * Fix issue with detailed middleware instrumentation
16
+
5
17
  # 2.4.7
6
18
 
7
19
  * Fix issue recording backtraces
data/Gemfile CHANGED
@@ -2,3 +2,11 @@ source "http://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in scout_apm.gemspec
4
4
  gemspec
5
+
6
+ # Pin development dependencies more conservatively for Ruby 1.8.7
7
+ if RUBY_VERSION <= "1.8.7"
8
+ gem "activesupport", "~> 3.2"
9
+ gem "i18n", "~> 0.6.11"
10
+ gem "pry", "~> 0.9.12"
11
+ gem "rake", "~> 10.5"
12
+ end
@@ -1,5 +1,7 @@
1
1
  # ScoutApm Ruby Agent
2
2
 
3
+ [![Build Status](https://travis-ci.org/scoutapp/scout_apm_ruby.svg?branch=master)](https://travis-ci.org/scoutapp/scout_apm_ruby)
4
+
3
5
  A Ruby gem for detailed Rails application performance analysis. Metrics are
4
6
  reported to [Scout](https://scoutapp.com), a hosted application monitoring
5
7
  service.
@@ -129,6 +129,7 @@ require 'scout_apm/db_query_metric_set'
129
129
  require 'scout_apm/store'
130
130
  require 'scout_apm/fake_store'
131
131
  require 'scout_apm/tracer'
132
+ require 'scout_apm/transaction'
132
133
  require 'scout_apm/context'
133
134
  require 'scout_apm/instant_reporting'
134
135
  require 'scout_apm/trace_compactor'
@@ -4,20 +4,24 @@ module ScoutApm
4
4
  # The preconditions here must be a 2 element hash, with :message and :check.
5
5
  # message: Proc that takes the environment, and returns a string
6
6
  # check: Proc that takes an AgentContext and returns true if precondition was met, if false, we shouldn't start.
7
+ # severity: Severity of the log message (one of: :debug, :info, :warn, :error or :fatal)
7
8
  PRECONDITIONS = [
8
9
  PRECONDITION_ENABLED = {
9
10
  :message => proc {|environ| "Monitoring isn't enabled for the [#{environ.env}] environment." },
10
11
  :check => proc { |context| context.config.value('monitor') },
12
+ :severity => :info,
11
13
  },
12
14
 
13
15
  PRECONDITION_APP_NAME = {
14
16
  :message => proc {|environ| "An application name could not be determined. Specify the :name value in scout_apm.yml." },
15
17
  :check => proc { |context| context.environment.application_name },
18
+ :severity => :warn,
16
19
  },
17
20
 
18
21
  PRECONDITION_INTERACTIVE = {
19
22
  :message => proc {|environ| "Agent attempting to load in interactive mode." },
20
23
  :check => proc { |context| ! context.environment.interactive? },
24
+ :severity => :info,
21
25
  },
22
26
 
23
27
  PRECONDITION_DETECTED_SERVER = {
@@ -28,16 +32,19 @@ module ScoutApm
28
32
 
29
33
  !app_server_missing && !background_job_missing
30
34
  },
35
+ :severity => :info,
31
36
  },
32
37
 
33
38
  PRECONDITION_ALREADY_STARTED = {
34
39
  :message => proc {|environ| "Already started agent." },
35
40
  :check => proc { |context| !context.started? },
41
+ :severity => :info,
36
42
  },
37
43
 
38
44
  PRECONDITION_OLD_SCOUT_RAILS = {
39
45
  :message => proc {|environ| "ScoutAPM is incompatible with the old Scout Rails plugin. Please remove scout_rails from your Gemfile" },
40
46
  :check => proc { !defined?(::ScoutRails) },
47
+ :severity => :warn,
41
48
  },
42
49
  ]
43
50
 
@@ -45,13 +52,18 @@ module ScoutApm
45
52
  @check_result ||=
46
53
  begin
47
54
  failed_preconditions = PRECONDITIONS.inject(Array.new) { |errors, condition|
48
- met = condition[:check].call(context)
49
- errors << condition[:message].call(context.environment) unless met
55
+ unless condition[:check].call(context)
56
+ errors << {
57
+ :severity => condition[:severity],
58
+ :message => condition[:message].call(context.environment),
59
+ }
60
+ end
61
+
50
62
  errors
51
63
  }
52
64
 
53
65
  if failed_preconditions.any?
54
- failed_preconditions.each {|msg| context.logger.warn(msg) }
66
+ failed_preconditions.each {|error| context.logger.send(error[:severity], error[:message]) }
55
67
  force? # if forced, return true anyway
56
68
  else
57
69
  # No errors, we met preconditions
@@ -30,7 +30,7 @@ module ScoutApm
30
30
 
31
31
  ActionDispatch::MiddlewareStack::Middleware.class_eval do
32
32
  def build(app)
33
- logger.info("Building Middleware #{klass.name}")
33
+ ScoutApm::Agent.instance.context.logger.info("Instrumenting Middleware #{klass.name}")
34
34
  new_mw = klass.new(app, *args, &block)
35
35
  MiddlewareWrapper.new(new_mw, klass.name)
36
36
  end
@@ -12,31 +12,36 @@ module ScoutApm
12
12
  klass.extend ClassMethods
13
13
  end
14
14
 
15
+ # Type: the Layer type - "View" or similar
16
+ # Name: specific name - "users/_gravatar". The object must respond to "#to_s". This allows us to be more efficient - in most cases, the metric name isn't needed unless we are processing a slow transaction.
17
+ # A Block: The code to be instrumented
18
+ #
19
+ # Options:
20
+ # * :ignore_children - will not instrument any method calls beneath this call. Example use case: InfluxDB uses Net::HTTP, which is instrumented. However, we can provide more specific data if we know we're doing an influx call, so we'd rather just instrument the Influx call and ignore Net::HTTP.
21
+ # when rendering the transaction tree in the UI.
22
+ # * :desc - Additional capture, SQL, or HTTP url or similar
23
+ # * :scope - set to true if you want to make this layer a subscope
24
+ def self.instrument(type, name, options={}) # Takes a block
25
+ layer = ScoutApm::Layer.new(type, name)
26
+ layer.desc = options[:desc] if options[:desc]
27
+ layer.subscopable! if options[:scope]
28
+
29
+ req = ScoutApm::RequestManager.lookup
30
+ req.start_layer(layer)
31
+ req.ignore_children! if options[:ignore_children]
32
+
33
+ begin
34
+ yield
35
+ ensure
36
+ req.acknowledge_children! if options[:ignore_children]
37
+ req.stop_layer
38
+ end
39
+ end
40
+
15
41
  module ClassMethods
16
- # Type: the Layer type - "View" or similar
17
- # Name: specific name - "users/_gravatar". The object must respond to "#to_s". This allows us to be more efficient - in most cases, the metric name isn't needed unless we are processing a slow transaction.
18
- # A Block: The code to be instrumented
19
- #
20
- # Options:
21
- # * :ignore_children - will not instrument any method calls beneath this call. Example use case: InfluxDB uses Net::HTTP, which is instrumented. However, we can provide more specific data if we know we're doing an influx call, so we'd rather just instrument the Influx call and ignore Net::HTTP.
22
- # when rendering the transaction tree in the UI.
23
- # * :desc - Additional capture, SQL, or HTTP url or similar
24
- # * :scope - set to true if you want to make this layer a subscope
25
- def instrument(type, name, options={}) # Takes a block
26
- layer = ScoutApm::Layer.new(type, name)
27
- layer.desc = options[:desc] if options[:desc]
28
- layer.subscopable! if options[:scope]
29
-
30
- req = ScoutApm::RequestManager.lookup
31
- req.start_layer(layer)
32
- req.ignore_children! if options[:ignore_children]
33
-
34
- begin
35
- yield
36
- ensure
37
- req.acknowledge_children! if options[:ignore_children]
38
- req.stop_layer
39
- end
42
+ # See ScoutApm::Tracer.instrument
43
+ def instrument(type, name, options={}, &block)
44
+ ScoutApm::Tracer.instrument(type, name, options, &block)
40
45
  end
41
46
 
42
47
  # Wraps a method in a call to #instrument via aggressive monkey patching.
@@ -85,7 +90,6 @@ module ScoutApm
85
90
  end
86
91
 
87
92
  def _instrumented_method_string(instrumented_name, uninstrumented_name, type, name, options={})
88
- klass = (self === Module) ? "self" : "self.class"
89
93
  method_str = <<-EOF
90
94
  def #{instrumented_name}(*args, &block)
91
95
  name = begin
@@ -95,7 +99,7 @@ module ScoutApm
95
99
  "Unknown"
96
100
  end
97
101
 
98
- #{klass}.instrument( "#{type}",
102
+ ::ScoutApm::Tracer.instrument( "#{type}",
99
103
  name,
100
104
  {:scope => #{options[:scope] || false}}
101
105
  ) do
@@ -38,6 +38,10 @@ module ScoutApm
38
38
  # An object that responds to `record!(TrackedRequest)` to store this tracked request
39
39
  attr_reader :recorder
40
40
 
41
+ # If specified, an override for the name of the request. If unspecified,
42
+ # the name is determined from the name of the Controller or Job layer.
43
+ attr_accessor :name_override
44
+
41
45
  # When we see these layers, it means a real request is going through the
42
46
  # system. We toggle a flag to turn on some slightly more expensive
43
47
  # instrumentation (backtrace collection and the like) that would be too
@@ -294,6 +298,8 @@ module ScoutApm
294
298
  # Bail out early if the user asked us to ignore this uri
295
299
  return if @agent_context.ignored_uris.ignore?(annotations[:uri])
296
300
 
301
+ apply_name_override
302
+
297
303
  converters = [
298
304
  LayerConverters::Histograms,
299
305
  LayerConverters::MetricConverter,
@@ -491,5 +497,16 @@ module ScoutApm
491
497
  @recorder = @agent_context.recorder
492
498
  @store = @agent_context.store
493
499
  end
500
+
501
+ private
502
+
503
+ def apply_name_override
504
+ return unless name_override
505
+
506
+ scope_layer = layer_finder.scope
507
+ if scope_layer
508
+ scope_layer.name = name_override
509
+ end
510
+ end
494
511
  end
495
512
  end
@@ -0,0 +1,13 @@
1
+ module ScoutApm
2
+ module Transaction
3
+ # Ignores the current request
4
+ def self.ignore!
5
+ ::ScoutApm::RequestManager.lookup.ignore_request!
6
+ end
7
+
8
+ # Renames the last Controller or Job layer
9
+ def self.rename(name)
10
+ ::ScoutApm::RequestManager.lookup.name_override = name
11
+ end
12
+ end
13
+ end
@@ -1,3 +1,3 @@
1
1
  module ScoutApm
2
- VERSION = "3.0.0.pre20"
2
+ VERSION = "3.0.0.pre21"
3
3
  end
@@ -23,13 +23,17 @@ Gem::Specification.new do |s|
23
23
  s.extensions << 'ext/rusage/extconf.rb'
24
24
 
25
25
  s.add_development_dependency "minitest"
26
- s.add_development_dependency 'mocha'
26
+ s.add_development_dependency "mocha"
27
27
  s.add_development_dependency "pry"
28
- s.add_development_dependency "m"
29
28
  s.add_development_dependency "simplecov"
30
29
  s.add_development_dependency "rake-compiler"
31
30
  s.add_development_dependency "addressable"
32
- s.add_development_dependency "guard"
33
- s.add_development_dependency "guard-minitest"
34
31
  s.add_development_dependency "activesupport"
32
+
33
+ if RUBY_VERSION >= "1.9.3"
34
+ s.add_development_dependency "rubocop"
35
+ s.add_development_dependency "guard"
36
+ s.add_development_dependency "guard-minitest"
37
+ s.add_development_dependency "m"
38
+ end
35
39
  end
@@ -68,6 +68,7 @@ end
68
68
  # Helpers available to all tests
69
69
  class Minitest::Test
70
70
  def setup
71
+ Thread.current[:scout_request] = nil
71
72
  reopen_logger
72
73
  FileUtils.mkdir_p(DATA_FILE_DIR)
73
74
  ENV['SCOUT_DATA_FILE'] = DATA_FILE_PATH
@@ -106,6 +107,26 @@ class Minitest::Test
106
107
  DATA_FILE_PATH = "#{DATA_FILE_DIR}/scout_apm.db"
107
108
  end
108
109
 
110
+ class FakeRecorder
111
+ attr_reader :requests
112
+
113
+ def initialize
114
+ @requests = []
115
+ end
116
+
117
+ def start
118
+ # nothing to do
119
+ self
120
+ end
121
+
122
+ def stop
123
+ # nothing to do
124
+ end
125
+
126
+ def record!(request)
127
+ @requests << request
128
+ end
129
+ end
109
130
 
110
131
  module CustomAsserts
111
132
  def assert_false(thing)
@@ -33,7 +33,7 @@ class ConfigTest < Minitest::Test
33
33
 
34
34
  def test_loading_file_without_env_in_file
35
35
  conf_file = File.expand_path("../../data/config_test_1.yml", __FILE__)
36
- conf = ScoutApm::Config.with_file(@context, conf_file, environment: "staging")
36
+ conf = ScoutApm::Config.with_file(@context, conf_file, :environment => "staging")
37
37
 
38
38
  assert_equal "info", conf.value('log_level') # the default value
39
39
  assert_nil nil, conf.value('name') # the default value
@@ -7,7 +7,8 @@ class DbQueryMetricSetTest < Minitest::Test
7
7
  def test_hard_limit
8
8
  config = make_fake_config(
9
9
  'database_metric_limit' => 5, # The hard limit on db metrics
10
- 'database_metric_report_limit' => 2,)
10
+ 'database_metric_report_limit' => 2
11
+ )
11
12
  context = ScoutApm::AgentContext.new().tap{|c| c.config = config }
12
13
  set = DbQueryMetricSet.new(context)
13
14
 
@@ -24,7 +25,8 @@ class DbQueryMetricSetTest < Minitest::Test
24
25
  def test_report_limit
25
26
  config = make_fake_config(
26
27
  'database_metric_limit' => 50, # much larger max, uninterested in hitting it.
27
- 'database_metric_report_limit' => 2,)
28
+ 'database_metric_report_limit' => 2
29
+ )
28
30
  context = ScoutApm::AgentContext.new().tap{|c| c.config = config }
29
31
  set = DbQueryMetricSet.new(context)
30
32
  set << fake_stat("a", 10)
@@ -41,7 +43,8 @@ class DbQueryMetricSetTest < Minitest::Test
41
43
  def test_combine
42
44
  config = make_fake_config(
43
45
  'database_metric_limit' => 5, # The hard limit on db metrics
44
- 'database_metric_report_limit' => 2,)
46
+ 'database_metric_report_limit' => 2
47
+ )
45
48
  context = ScoutApm::AgentContext.new().tap{|c| c.config = config }
46
49
  set1 = DbQueryMetricSet.new(context)
47
50
  set1 << fake_stat("a", 10)
@@ -51,13 +54,14 @@ class DbQueryMetricSetTest < Minitest::Test
51
54
  set2 << fake_stat("d", 20)
52
55
 
53
56
  combined = set1.combine!(set2)
54
- assert_equal ["a", "b", "c", "d"], combined.metrics.map{|_k, m| m.key}
57
+ assert_equal ["a", "b", "c", "d"], combined.metrics.map{|_k, m| m.key}.sort
55
58
  end
56
59
 
57
60
  def fake_stat(key, call_time)
58
61
  OpenStruct.new(
59
- key: key,
60
- call_time: call_time)
62
+ :key => key,
63
+ :call_time => call_time
64
+ )
61
65
  end
62
66
  end
63
67
  end
@@ -8,20 +8,20 @@ class DbQueryMetricStatsTest < Minitest::Test
8
8
  stat = build("table", "op", "Controller/public/index", 1, 10, 20)
9
9
 
10
10
  assert_equal({
11
- model_name: "table",
12
- operation: "op",
13
- call_count: 1,
14
- transaction_count: 0,
15
- scope: "Controller/public/index",
16
- histogram: [[10.0, 1]],
17
-
18
- max_call_time: 10.0,
19
- min_call_time: 10.0,
20
- call_time: 10.0,
21
-
22
- max_rows_returned: 20,
23
- min_rows_returned: 20,
24
- rows_returned: 20,
11
+ :model_name => "table",
12
+ :operation => "op",
13
+ :call_count => 1,
14
+ :transaction_count => 0,
15
+ :scope => "Controller/public/index",
16
+ :histogram => [[10.0, 1]],
17
+
18
+ :max_call_time => 10.0,
19
+ :min_call_time => 10.0,
20
+ :call_time => 10.0,
21
+
22
+ :max_rows_returned => 20,
23
+ :min_rows_returned => 20,
24
+ :rows_returned => 20,
25
25
  }, stat.as_json)
26
26
  end
27
27
 
@@ -90,9 +90,9 @@ class DbQueryMetricStatsTest < Minitest::Test
90
90
  # Helpers #
91
91
  #############
92
92
  DEFAULTS = {
93
- call_count: 1,
94
- call_time: 10.0,
95
- rows_returned: 20,
93
+ :call_count => 1,
94
+ :call_time => 10.0,
95
+ :rows_returned => 20,
96
96
  }
97
97
 
98
98
  def build(model_name="User",
@@ -35,8 +35,8 @@ class HistogramTest < Minitest::Test
35
35
  end
36
36
  }
37
37
 
38
- assert_equal 1.5, hist.quantile(0).round(1)
39
- assert_equal 9.5, hist.quantile(100).round(1)
38
+ assert_equal 1.5, round(hist.quantile(0), 1)
39
+ assert_equal 9.5, round(hist.quantile(100), 1)
40
40
  end
41
41
 
42
42
  def test_combine
@@ -55,8 +55,8 @@ class HistogramTest < Minitest::Test
55
55
  }
56
56
 
57
57
  combined = hist1.combine!(hist2)
58
- assert_equal 1.5, combined.quantile(0).round(1)
59
- assert_equal 9.5, combined.quantile(100).round(1)
58
+ assert_equal 1.5, round(combined.quantile(0), 1)
59
+ assert_equal 9.5, round(combined.quantile(100), 1)
60
60
  assert_equal 200, combined.total
61
61
  end
62
62
 
@@ -103,5 +103,12 @@ class HistogramTest < Minitest::Test
103
103
 
104
104
  assert_equal 5.5, hist.mean
105
105
  end
106
+
107
+ private
108
+
109
+ # Ruby 1.8 compatible round with precision
110
+ def round(number, precision)
111
+ ((number * 10**precision).round.to_f) / (10**precision)
112
+ end
106
113
  end
107
114
 
@@ -1,4 +1,4 @@
1
- require_relative '../test_helper'
1
+ require 'test_helper'
2
2
 
3
3
  require 'scout_apm/ignored_uris'
4
4
 
@@ -2,7 +2,7 @@ require 'test_helper'
2
2
 
3
3
  require 'scout_apm/instruments/net_http'
4
4
 
5
- require 'addressable'
5
+ require 'addressable/uri'
6
6
 
7
7
  class NetHttpTest < Minitest::Test
8
8
  def setup
@@ -11,7 +11,12 @@ class NetHttpTest < Minitest::Test
11
11
  end
12
12
 
13
13
  def test_request_scout_description_for_uri
14
- req = Net::HTTP::Get.new(URI('http://example.org/here'))
14
+ if RUBY_VERSION <= '1.9.3'
15
+ req = Net::HTTP::Get.new('/here')
16
+ else
17
+ req = Net::HTTP::Get.new(URI('http://example.org/here'))
18
+ end
19
+
15
20
  assert_equal '/here', Net::HTTP.new('').request_scout_description(req)
16
21
  end
17
22
 
@@ -25,6 +25,10 @@ class DepthFirstWalkerTest < Minitest::Test
25
25
  # / \
26
26
  # F G
27
27
  def test_walk_interesting_tree
28
+ # The test could be rewritten to support 1.8.7, but it would likely be much
29
+ # harder to read.
30
+ skip "Lack of set ordering in Ruby 1.8.7 prevents this test from running correctly" if RUBY_VERSION.start_with?("1.8.")
31
+
28
32
  calls = []
29
33
  a = Layer.new("A", "x")
30
34
  b = Layer.new("B", "x")
@@ -1,5 +1,5 @@
1
1
  require 'test_helper'
2
- require_relative 'stubs'
2
+ require File.join(File.dirname(__FILE__), 'stubs')
3
3
 
4
4
  module ScoutApm
5
5
  module LayerConverters
@@ -4,7 +4,7 @@
4
4
  module ScoutApm
5
5
  module LayerConverters
6
6
  module Stubs
7
- def faux_walker(subscope_stubs: true)
7
+ def faux_walker(subscope_stubs = true)
8
8
  @w ||= stub
9
9
 
10
10
  if subscope_stubs && !@w_set_subscope_stubs
@@ -21,7 +21,7 @@ module ScoutApm
21
21
 
22
22
  def faux_layer_finder
23
23
  @layer_finder ||= stub
24
- @layer_finder.stubs(scope: stub)
24
+ @layer_finder.stubs(:scope => stub)
25
25
  @layer_finder
26
26
  end
27
27
 
@@ -47,7 +47,7 @@ class LimitedLayerTest < Minitest::Test
47
47
  :total_call_time => tct,
48
48
  :total_exclusive_time => tet,
49
49
  :total_allocations => a_tct,
50
- :total_exclusive_allocations => a_tet,
50
+ :total_exclusive_allocations => a_tet
51
51
  )
52
52
  end
53
53
  end
@@ -5,7 +5,7 @@ require 'scout_apm/logger'
5
5
 
6
6
  class LoggerTest < Minitest::Test
7
7
  def setup
8
- @env_root = Pathname.new(File.dirname(__FILE__)) + "../../"
8
+ @env_root = Pathname.new(File.expand_path(File.join(File.dirname(__FILE__), "..", "..")))
9
9
  FileUtils.mkdir_p(@env_root + "log")
10
10
  end
11
11
 
@@ -46,7 +46,7 @@ class PayloadSerializerTest < Minitest::Test
46
46
  stats.min_call_time = 0.034881757
47
47
  stats.sum_of_squares = 0.007382350213180609
48
48
  stats.total_call_time = 0.113403176
49
- stats.total_exclusive_time = 0.07813208899999999
49
+ stats.total_exclusive_time = 0.078132088
50
50
  }
51
51
  }
52
52
  payload = ScoutApm::Serializers::PayloadSerializerToJson.serialize({}, metrics, {}, [], [], [], {})
@@ -83,11 +83,12 @@ class PayloadSerializerTest < Minitest::Test
83
83
  "max_call_time" => 0.078521419,
84
84
  "min_call_time" => 0.034881757,
85
85
  "total_call_time" => 0.113403176,
86
- "total_exclusive_time" => 0.07813208899999999,
86
+ "total_exclusive_time" => 0.078132088,
87
87
  "traces" => []
88
88
  }
89
89
  ]
90
- assert_equal formatted_metrics, JSON.parse(payload)["metrics"]
90
+ assert_equal formatted_metrics,
91
+ JSON.parse(payload)["metrics"].sort_by { |m| m["key"]["bucket"] }
91
92
  end
92
93
 
93
94
  def test_escapes_json_quotes
@@ -10,6 +10,8 @@ module ScoutApm
10
10
  end
11
11
 
12
12
  def test_postgres_simple_select_of_first
13
+ skip "Broken on Ruby 1.8.7 because regular expressions do not support look-behinds" if RUBY_VERSION.start_with?("1.8.")
14
+
13
15
  sql = %q|SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT 1|
14
16
  ss = SqlSanitizer.new(sql).tap{ |it| it.database_engine = :postgres }
15
17
  assert_equal %q|SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT 1|, ss.to_s
@@ -55,6 +57,8 @@ module ScoutApm
55
57
  end
56
58
 
57
59
  def test_mysql_limit
60
+ skip "Broken on Ruby 1.8.7 because regular expressions do not support look-behinds" if RUBY_VERSION.start_with?("1.8.")
61
+
58
62
  sql = %q|SELECT `blogs`.* FROM `blogs` ORDER BY `blogs`.`id` ASC LIMIT 1|
59
63
  ss = SqlSanitizer.new(sql).tap{ |it| it.database_engine = :mysql }
60
64
  assert_equal %q|SELECT `blogs`.* FROM `blogs` ORDER BY `blogs`.`id` ASC LIMIT 1|, ss.to_s
@@ -86,6 +90,8 @@ module ScoutApm
86
90
  end
87
91
 
88
92
  def test_scrubs_invalid_encoding
93
+ skip "Ruby 1.8.7 has no concept of encoding" if RUBY_VERSION.start_with?("1.8.")
94
+
89
95
  sql = "SELECT `blogs`.* FROM `blogs` WHERE (title = 'a\255c')".force_encoding('UTF-8')
90
96
  assert_equal false, sql.valid_encoding?
91
97
  ss = SqlSanitizer.new(sql).tap{ |it| it.database_engine = :mysql }
@@ -0,0 +1,76 @@
1
+ require 'test_helper'
2
+
3
+ class TracerTest < Minitest::Test
4
+ def test_instrument
5
+ recorder = FakeRecorder.new
6
+ ScoutApm::Agent.instance.context.recorder = recorder
7
+
8
+ invoked = false
9
+ ScoutApm::Tracer.instrument("Test", "name") do
10
+ invoked = true
11
+ end
12
+
13
+ assert invoked, "instrumented code was not invoked"
14
+ assert_recorded(recorder, "Test", "name")
15
+ end
16
+
17
+ def test_instrument_included
18
+ recorder = FakeRecorder.new
19
+ ScoutApm::Agent.instance.context.recorder = recorder
20
+
21
+ klass = Class.new { include ScoutApm::Tracer }
22
+
23
+ invoked = false
24
+ klass.instrument("Test", "name") do
25
+ invoked = true
26
+ end
27
+
28
+ assert invoked, "instrumented code was not invoked"
29
+ assert_recorded(recorder, "Test", "name")
30
+ end
31
+
32
+ def test_instrument_inside_method
33
+ recorder = FakeRecorder.new
34
+ ScoutApm::Agent.instance.context.recorder = recorder
35
+
36
+ klass = Class.new { include ScoutApm::Tracer }
37
+ klass.class_eval %q{
38
+ attr_reader :invoked
39
+ def work
40
+ ScoutApm::Tracer.instrument("Test", "name") do
41
+ @invoked = true
42
+ end
43
+ end
44
+ }
45
+ klass_instance = klass.new
46
+ klass_instance.work
47
+
48
+ assert klass_instance.invoked, "instrumented code was not invoked"
49
+ assert_recorded(recorder, "Test", "name")
50
+ end
51
+
52
+ def test_instrument_method
53
+ recorder = FakeRecorder.new
54
+ ScoutApm::Agent.instance.context.recorder = recorder
55
+
56
+ klass = Class.new { include ScoutApm::Tracer }
57
+
58
+ invoked = false
59
+ klass.send(:define_method, :work) { invoked = true }
60
+ klass.instrument_method(:work, :type => "Test", :name => "name")
61
+
62
+ klass.new.work
63
+
64
+ assert invoked, "instrumented code was not invoked"
65
+ assert_recorded(recorder, "Test", "name")
66
+ end
67
+
68
+ private
69
+
70
+ def assert_recorded(recorder, type, name)
71
+ req = recorder.requests.first
72
+ assert req, "recorder recorded no layers"
73
+ assert_equal type, req.root_layer.type
74
+ assert_equal name, req.root_layer.name
75
+ end
76
+ end
@@ -10,19 +10,6 @@ class TrackedRequestDumpAndLoadTest < Minitest::Test
10
10
  loaded = Marshal.load(dumped)
11
11
  assert_false loaded.nil?
12
12
  end
13
-
14
- def test_restore_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")
19
-
20
- tr.prepare_to_dump!
21
- assert_nil tr.instance_variable_get("@store")
22
-
23
- tr.restore_store
24
- assert_equal context.store, tr.instance_variable_get("@store")
25
- end
26
13
  end
27
14
 
28
15
  class TrackedRequestLayerManipulationTest < Minitest::Test
@@ -48,4 +35,37 @@ class TrackedRequestLayerManipulationTest < Minitest::Test
48
35
 
49
36
  assert_equal "Controller", tr.current_layer.type
50
37
  end
38
+
39
+ def test_name_override_controller
40
+ # layers are Middleware -> Controller
41
+ middleware_layer = ScoutApm::Layer.new("Middleware", "foo")
42
+ controller_layer = ScoutApm::Layer.new("Controller", "users/index")
43
+
44
+ tr = ScoutApm::TrackedRequest.new(ScoutApm::AgentContext.new, ScoutApm::FakeStore.new)
45
+ tr.start_layer(middleware_layer)
46
+ tr.name_override = "override"
47
+ tr.start_layer(controller_layer)
48
+ tr.stop_layer
49
+ tr.stop_layer
50
+
51
+ assert_equal "override", controller_layer.name
52
+ end
53
+
54
+ def test_name_override_job
55
+ # layers are Middleware -> Queue -> Job
56
+ middleware_layer = ScoutApm::Layer.new("Middleware", "foo")
57
+ queue_layer = ScoutApm::Layer.new("Queue", "bar")
58
+ job_layer = ScoutApm::Layer.new("Job", "FooJob")
59
+
60
+ tr = ScoutApm::TrackedRequest.new(ScoutApm::AgentContext.new, ScoutApm::FakeStore.new)
61
+ tr.start_layer(middleware_layer)
62
+ tr.name_override = "override"
63
+ tr.start_layer(queue_layer)
64
+ tr.start_layer(job_layer)
65
+ tr.stop_layer
66
+ tr.stop_layer
67
+ tr.stop_layer
68
+
69
+ assert_equal "override", job_layer.name
70
+ end
51
71
  end
@@ -0,0 +1,14 @@
1
+ require 'test_helper'
2
+
3
+ class TransactionTest < Minitest::Test
4
+ def test_ignore
5
+ recorder = FakeRecorder.new
6
+ ScoutApm::Agent.instance.context.recorder = recorder
7
+
8
+ ScoutApm::Tracer.instrument("Controller", "foo/bar") do
9
+ ScoutApm::Transaction.ignore!
10
+ end
11
+
12
+ assert_equal 0, recorder.requests.length
13
+ end
14
+ end
@@ -1,4 +1,4 @@
1
- require_relative '../../test_helper'
1
+ require 'test_helper'
2
2
  require 'scout_apm/utils/backtrace_parser'
3
3
 
4
4
  class BacktraceParserTest < Minitest::Test
@@ -1,4 +1,4 @@
1
- require_relative '../../test_helper'
1
+ require 'test_helper'
2
2
  require 'scout_apm/utils/numbers'
3
3
 
4
4
  class NumbersTest < Minitest::Test
@@ -1,4 +1,4 @@
1
- require_relative '../../test_helper'
1
+ require 'test_helper'
2
2
  require 'scout_apm/utils/scm'
3
3
 
4
4
  class ScmTest < Minitest::Test
@@ -14,4 +14,4 @@ class ScmTest < Minitest::Test
14
14
  def test_relative_scm_path_not_blank_with_slashes
15
15
  assert_equal 'src/app/models/person.rb', ScoutApm::Utils::Scm.relative_scm_path('app/models/person.rb', '/src/')
16
16
  end
17
- end
17
+ 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: 3.0.0.pre20
4
+ version: 3.0.0.pre21
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-02-01 00:00:00.000000000 Z
12
+ date: 2018-03-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: minitest
@@ -54,7 +54,7 @@ dependencies:
54
54
  - !ruby/object:Gem::Version
55
55
  version: '0'
56
56
  - !ruby/object:Gem::Dependency
57
- name: m
57
+ name: simplecov
58
58
  requirement: !ruby/object:Gem::Requirement
59
59
  requirements:
60
60
  - - ">="
@@ -68,7 +68,7 @@ dependencies:
68
68
  - !ruby/object:Gem::Version
69
69
  version: '0'
70
70
  - !ruby/object:Gem::Dependency
71
- name: simplecov
71
+ name: rake-compiler
72
72
  requirement: !ruby/object:Gem::Requirement
73
73
  requirements:
74
74
  - - ">="
@@ -82,7 +82,7 @@ dependencies:
82
82
  - !ruby/object:Gem::Version
83
83
  version: '0'
84
84
  - !ruby/object:Gem::Dependency
85
- name: rake-compiler
85
+ name: addressable
86
86
  requirement: !ruby/object:Gem::Requirement
87
87
  requirements:
88
88
  - - ">="
@@ -96,7 +96,21 @@ dependencies:
96
96
  - !ruby/object:Gem::Version
97
97
  version: '0'
98
98
  - !ruby/object:Gem::Dependency
99
- name: addressable
99
+ name: activesupport
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ - !ruby/object:Gem::Dependency
113
+ name: rubocop
100
114
  requirement: !ruby/object:Gem::Requirement
101
115
  requirements:
102
116
  - - ">="
@@ -138,7 +152,7 @@ dependencies:
138
152
  - !ruby/object:Gem::Version
139
153
  version: '0'
140
154
  - !ruby/object:Gem::Dependency
141
- name: activesupport
155
+ name: m
142
156
  requirement: !ruby/object:Gem::Requirement
143
157
  requirements:
144
158
  - - ">="
@@ -163,6 +177,7 @@ extra_rdoc_files: []
163
177
  files:
164
178
  - ".gitignore"
165
179
  - ".rubocop.yml"
180
+ - ".travis.yml"
166
181
  - CHANGELOG.markdown
167
182
  - Gemfile
168
183
  - Guardfile
@@ -297,6 +312,7 @@ files:
297
312
  - lib/scout_apm/trace_compactor.rb
298
313
  - lib/scout_apm/tracer.rb
299
314
  - lib/scout_apm/tracked_request.rb
315
+ - lib/scout_apm/transaction.rb
300
316
  - lib/scout_apm/utils/active_record_metric_name.rb
301
317
  - lib/scout_apm/utils/backtrace_parser.rb
302
318
  - lib/scout_apm/utils/fake_stacks.rb
@@ -346,7 +362,9 @@ files:
346
362
  - test/unit/slow_request_policy_test.rb
347
363
  - test/unit/sql_sanitizer_test.rb
348
364
  - test/unit/store_test.rb
349
- - test/unit/test_tracked_request.rb
365
+ - test/unit/tracer_test.rb
366
+ - test/unit/tracked_request_test.rb
367
+ - test/unit/transaction_test.rb
350
368
  - test/unit/utils/active_record_metric_name_test.rb
351
369
  - test/unit/utils/backtrace_parser_test.rb
352
370
  - test/unit/utils/numbers_test.rb
@@ -411,7 +429,9 @@ test_files:
411
429
  - test/unit/slow_request_policy_test.rb
412
430
  - test/unit/sql_sanitizer_test.rb
413
431
  - test/unit/store_test.rb
414
- - test/unit/test_tracked_request.rb
432
+ - test/unit/tracer_test.rb
433
+ - test/unit/tracked_request_test.rb
434
+ - test/unit/transaction_test.rb
415
435
  - test/unit/utils/active_record_metric_name_test.rb
416
436
  - test/unit/utils/backtrace_parser_test.rb
417
437
  - test/unit/utils/numbers_test.rb