newrelic_rpm 3.16.0.318 → 3.16.1.320

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +13 -4
  3. data/CHANGELOG +41 -2
  4. data/lib/new_relic/agent/database.rb +15 -4
  5. data/lib/new_relic/agent/database/explain_plan_helpers.rb +2 -1
  6. data/lib/new_relic/agent/datastores.rb +13 -13
  7. data/lib/new_relic/agent/datastores/metric_helper.rb +33 -2
  8. data/lib/new_relic/agent/datastores/mongo/metric_translator.rb +3 -9
  9. data/lib/new_relic/agent/error_collector.rb +2 -2
  10. data/lib/new_relic/agent/instrumentation/active_record.rb +9 -19
  11. data/lib/new_relic/agent/instrumentation/active_record_helper.rb +2 -6
  12. data/lib/new_relic/agent/instrumentation/active_record_subscriber.rb +49 -40
  13. data/lib/new_relic/agent/instrumentation/data_mapper.rb +29 -23
  14. data/lib/new_relic/agent/instrumentation/grape.rb +20 -11
  15. data/lib/new_relic/agent/instrumentation/memcache.rb +8 -10
  16. data/lib/new_relic/agent/instrumentation/mongo.rb +25 -16
  17. data/lib/new_relic/agent/instrumentation/mongodb_command_subscriber.rb +14 -19
  18. data/lib/new_relic/agent/method_tracer_helpers.rb +4 -8
  19. data/lib/new_relic/agent/sql_sampler.rb +14 -1
  20. data/lib/new_relic/agent/stats_engine/metric_stats.rb +18 -0
  21. data/lib/new_relic/agent/supported_versions.rb +2 -3
  22. data/lib/new_relic/agent/traced_method_stack.rb +7 -1
  23. data/lib/new_relic/agent/transaction.rb +6 -0
  24. data/lib/new_relic/agent/transaction/abstract_segment.rb +73 -0
  25. data/lib/new_relic/agent/transaction/datastore_segment.rb +49 -0
  26. data/lib/new_relic/agent/transaction/segment.rb +30 -0
  27. data/lib/new_relic/agent/transaction/tracing.rb +53 -0
  28. data/lib/new_relic/agent/transaction_sampler.rb +8 -1
  29. data/lib/new_relic/noticed_error.rb +3 -1
  30. data/lib/new_relic/version.rb +1 -1
  31. data/lib/sequel/extensions/newrelic_instrumentation.rb +22 -15
  32. data/lib/sequel/plugins/newrelic_instrumentation.rb +4 -3
  33. data/newrelic_rpm.gemspec +1 -9
  34. data/test/environments/lib/environments/runner.rb +6 -4
  35. data/test/environments/norails/Gemfile +9 -3
  36. data/test/environments/rails21/Gemfile +6 -3
  37. data/test/environments/rails22/Gemfile +5 -2
  38. data/test/environments/rails23/Gemfile +1 -1
  39. data/test/environments/rails30/Gemfile +1 -1
  40. data/test/environments/rails31/Gemfile +1 -1
  41. data/test/environments/rails32/Gemfile +1 -1
  42. data/test/environments/rails40/Gemfile +2 -2
  43. data/test/environments/rails41/Gemfile +2 -2
  44. data/test/environments/rails42/Gemfile +2 -2
  45. data/test/environments/rails50/Gemfile +2 -2
  46. data/test/helpers/mongo_metric_builder.rb +3 -4
  47. data/test/multiverse/lib/multiverse/shell_utils.rb +27 -0
  48. data/test/multiverse/lib/multiverse/suite.rb +47 -2
  49. data/test/multiverse/suites/active_record/Envfile +1 -1
  50. data/test/multiverse/suites/delayed_job/Envfile +2 -0
  51. data/test/multiverse/suites/grape/grape_versioning_test.rb +55 -1
  52. data/test/multiverse/suites/grape/grape_versioning_test_api.rb +61 -3
  53. data/test/multiverse/suites/mongo/mongo_instrumentation_test.rb +18 -0
  54. data/test/multiverse/suites/rails/Envfile +3 -3
  55. data/test/multiverse/suites/rails/error_tracing_test.rb +2 -2
  56. data/test/multiverse/suites/sequel/Envfile +7 -0
  57. data/test/multiverse/suites/sequel/sequel_extension_test.rb +1 -1
  58. data/test/new_relic/agent/database_test.rb +9 -0
  59. data/test/new_relic/agent/datastores/metric_helper_test.rb +76 -43
  60. data/test/new_relic/agent/datastores/mongo/metric_translator_test.rb +67 -117
  61. data/test/new_relic/agent/datastores_test.rb +17 -0
  62. data/test/new_relic/agent/error_collector_test.rb +21 -5
  63. data/test/new_relic/agent/instrumentation/active_record_helper_test.rb +40 -45
  64. data/test/new_relic/agent/instrumentation/active_record_subscriber_test.rb +2 -3
  65. data/test/new_relic/agent/instrumentation/mongodb_command_subscriber_test.rb +2 -0
  66. data/test/new_relic/agent/method_tracer_test.rb +54 -52
  67. data/test/new_relic/agent/mock_scope_listener.rb +4 -1
  68. data/test/new_relic/agent/sql_sampler_test.rb +15 -0
  69. data/test/new_relic/agent/transaction/abstract_segment_test.rb +94 -0
  70. data/test/new_relic/agent/transaction/datastore_segment_test.rb +99 -0
  71. data/test/new_relic/agent/transaction/segment_test.rb +53 -0
  72. data/test/new_relic/agent/transaction/tracing_test.rb +121 -0
  73. data/test/new_relic/agent/transaction_sampler_test.rb +13 -0
  74. data/test/new_relic/noticed_error_test.rb +7 -0
  75. data/test/performance/suites/datastores.rb +59 -0
  76. data/test/performance/suites/trace_execution_scoped.rb +8 -9
  77. metadata +13 -46
@@ -0,0 +1,73 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under New Relic's license terms.
3
+ # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
4
+
5
+ module NewRelic
6
+ module Agent
7
+ class Transaction
8
+ class AbstractSegment
9
+ attr_reader :start_time, :end_time, :duration, :exclusive_duration
10
+ attr_accessor :name, :children_time, :transaction
11
+
12
+ def initialize name
13
+ @name = name
14
+ @children_time = 0.0
15
+ @record_metrics = true
16
+ @transaction = nil
17
+ end
18
+
19
+ def start
20
+ @start_time = Time.now
21
+ end
22
+
23
+ def finish
24
+ @end_time = Time.now
25
+ @duration = end_time.to_f - start_time.to_f
26
+ @exclusive_duration = duration - children_time
27
+ record_metrics if record_metrics?
28
+ segment_complete
29
+ @transaction.segment_complete self if transaction
30
+ rescue => e
31
+ # This rescue block was added for the benefit of this test:
32
+ # test/multiverse/suites/bare/standalone_instrumentation_test.rb
33
+ # See the top of the test for details.
34
+ NewRelic::Agent.logger.error "Exception finishing segment: #{name}", e
35
+ end
36
+
37
+ def record_metrics?
38
+ @record_metrics
39
+ end
40
+
41
+ def record_metrics= value
42
+ @record_metrics = value
43
+ end
44
+
45
+ def record_metrics
46
+ raise NotImplementedError, "Subclasses must implement record_metrics"
47
+ end
48
+
49
+ private
50
+
51
+ # callback for subclasses to override
52
+ def segment_complete
53
+ end
54
+
55
+ def metric_cache
56
+ if transaction
57
+ transaction.metrics
58
+ else
59
+ NewRelic::Agent.instance.stats_engine
60
+ end
61
+ end
62
+
63
+ def transaction_state
64
+ @transaction_state ||= if @transaction
65
+ transaction.state
66
+ else
67
+ TransactionState.tl_get
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,49 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under New Relic's license terms.
3
+ # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
4
+
5
+ require 'new_relic/agent/transaction/segment'
6
+ require 'new_relic/agent/datastores/metric_helper'
7
+ require 'new_relic/agent/database'
8
+
9
+ module NewRelic
10
+ module Agent
11
+ class Transaction
12
+ class DatastoreSegment < Segment
13
+ attr_reader :product, :operation, :collection, :sql_statement
14
+
15
+ def initialize product, operation, collection = nil
16
+ @product = product
17
+ @operation = operation
18
+ @collection = collection
19
+ @sql_statement = nil
20
+ super Datastores::MetricHelper.scoped_metric_for(product, operation, collection),
21
+ Datastores::MetricHelper.unscoped_metrics_for(product, operation, collection)
22
+ end
23
+
24
+ def notice_sql sql
25
+ _notice_sql sql
26
+ end
27
+
28
+ # @api private
29
+ def _notice_sql sql, config=nil, explainer=nil, binds=nil, name=nil
30
+ return unless record_sql?
31
+ @sql_statement = Database::Statement.new sql, config, explainer, binds, name
32
+ end
33
+
34
+ private
35
+
36
+ def segment_complete
37
+ return unless sql_statement
38
+
39
+ NewRelic::Agent.instance.transaction_sampler.notice_sql_statement(sql_statement, duration)
40
+ NewRelic::Agent.instance.sql_sampler.notice_sql_statement(sql_statement.dup, name, duration)
41
+ end
42
+
43
+ def record_sql?
44
+ transaction_state.is_sql_recorded?
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,30 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under New Relic's license terms.
3
+ # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
4
+
5
+ require 'new_relic/agent/transaction/abstract_segment'
6
+
7
+ module NewRelic
8
+ module Agent
9
+ class Transaction
10
+ class Segment < AbstractSegment
11
+ # unscoped_metrics can be nil, a string, or array. we do this to save
12
+ # object allocations. if allocations weren't important then we would
13
+ # initialize it as an array that would be empty, have one item, or many items.
14
+ attr_reader :unscoped_metrics
15
+
16
+ def initialize name, unscoped_metrics=nil
17
+ @unscoped_metrics = unscoped_metrics
18
+ super name
19
+ end
20
+
21
+ def record_metrics
22
+ metric_cache.record_scoped_and_unscoped name, duration, exclusive_duration
23
+ if unscoped_metrics
24
+ metric_cache.record_unscoped unscoped_metrics, duration, exclusive_duration
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,53 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under New Relic's license terms.
3
+ # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
4
+
5
+ require 'new_relic/agent/transaction/segment'
6
+ require 'new_relic/agent/transaction/datastore_segment'
7
+
8
+ module NewRelic
9
+ module Agent
10
+ class Transaction
11
+ module Tracing
12
+ module ClassMethods
13
+ def start_segment name, unscoped_metrics=nil
14
+ segment = Segment.new name, unscoped_metrics
15
+ segment.start
16
+ add_segment segment
17
+ segment
18
+ end
19
+
20
+ def start_datastore_segment product, operation, collection=nil
21
+ segment = DatastoreSegment.new product, operation, collection
22
+ segment.start
23
+ add_segment segment
24
+ segment
25
+ end
26
+
27
+ private
28
+
29
+ def add_segment segment
30
+ state = NewRelic::Agent::TransactionState.tl_get
31
+ segment.record_metrics = state.is_execution_traced?
32
+ if (txn = state.current_transaction) && state.is_execution_traced?
33
+ txn.add_segment segment
34
+ end
35
+ end
36
+ end
37
+
38
+ def self.included base
39
+ base.extend ClassMethods
40
+ end
41
+
42
+ def add_segment segment
43
+ segment.transaction = self
44
+ state.traced_method_stack.push_segment state, segment
45
+ end
46
+
47
+ def segment_complete segment
48
+ state.traced_method_stack.pop_frame(state, segment, segment.name, segment.end_time, segment.record_metrics?)
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -183,7 +183,7 @@ module NewRelic
183
183
  # @api public
184
184
  # @deprecated Use {Datastores.notice_sql} instead.
185
185
  #
186
- def notice_sql(sql, config, duration, state=nil, explainer=nil, binds=[], name="SQL") #THREAD_LOCAL_ACCESS sometimes
186
+ def notice_sql(sql, config, duration, state=nil, explainer=nil, binds=nil, name=nil) #THREAD_LOCAL_ACCESS sometimes
187
187
  # some statements (particularly INSERTS with large BLOBS
188
188
  # may be very large; we should trim them to a maximum usable length
189
189
  state ||= TransactionState.tl_get
@@ -194,6 +194,13 @@ module NewRelic
194
194
  end
195
195
  end
196
196
 
197
+
198
+ def notice_sql_statement(statement, duration) #THREAD_LOCAL_ACCESS sometimes
199
+ state ||= TransactionState.tl_get
200
+ builder = state.transaction_sample_builder
201
+ notice_extra_data(builder, statement, duration, :sql)
202
+ end
203
+
197
204
  # Attaches an additional non-SQL query parameter to the current
198
205
  # transaction trace node.
199
206
  #
@@ -30,7 +30,9 @@ class NewRelic::NoticedError
30
30
 
31
31
  if exception.nil?
32
32
  @message = '<no message>'
33
- elsif exception.respond_to?('original_exception')
33
+ elsif exception.respond_to?(:cause)
34
+ @message = (exception.cause || exception).to_s
35
+ elsif exception.respond_to?(:original_exception)
34
36
  @message = (exception.original_exception || exception).to_s
35
37
  else # exception is not nil, but does not respond to original_exception
36
38
  @message = exception.to_s
@@ -12,7 +12,7 @@ module NewRelic
12
12
 
13
13
  MAJOR = 3
14
14
  MINOR = 16
15
- TINY = 0
15
+ TINY = 1
16
16
 
17
17
  begin
18
18
  require File.join(File.dirname(__FILE__), 'build')
@@ -32,30 +32,37 @@ module Sequel
32
32
  #
33
33
  module NewRelicInstrumentation
34
34
 
35
- # Instrument all queries that go through #execute_query.
36
- def log_yield(sql, args=nil) #THREAD_LOCAL_ACCESS
37
- rval = nil
38
- product = NewRelic::Agent::Instrumentation::SequelHelper.product_name_from_adapter(self.class.adapter_scheme)
39
- metrics = NewRelic::Agent::Datastores::MetricHelper.metrics_from_sql(product, sql)
40
- scoped_metric = metrics.first
41
-
42
- NewRelic::Agent::MethodTracer.trace_execution_scoped(metrics) do
43
- t0 = Time.now
44
- begin
45
- rval = super
46
- ensure
47
- notice_sql(sql, scoped_metric, args, t0, Time.now)
35
+ module Naming
36
+ def self.query_method_name
37
+ if Sequel::VERSION >= "4.35.0"
38
+ :log_connection_yield
39
+ else
40
+ :log_yield
48
41
  end
49
42
  end
43
+ end
44
+
45
+ define_method Naming.query_method_name do |*args, &blk| #THREAD_LOCAL_ACCESS
46
+ sql = args.first
50
47
 
51
- return rval
48
+ product = NewRelic::Agent::Instrumentation::SequelHelper.product_name_from_adapter(self.class.adapter_scheme)
49
+ operation = NewRelic::Agent::Datastores::MetricHelper.operation_from_sql(sql)
50
+ segment = NewRelic::Agent::Transaction.start_datastore_segment product, operation
51
+
52
+ begin
53
+ super(*args, &blk)
54
+ ensure
55
+ notice_sql(sql, segment.name, segment.start_time, Time.now)
56
+ segment.finish
57
+ end
52
58
  end
53
59
 
60
+
54
61
  THREAD_SAFE_CONNECTION_POOL_CLASSES = [
55
62
  (defined?(::Sequel::ThreadedConnectionPool) && ::Sequel::ThreadedConnectionPool)
56
63
  ].freeze
57
64
 
58
- def notice_sql(sql, metric_name, args, start, finish)
65
+ def notice_sql(sql, metric_name, start, finish)
59
66
  state = NewRelic::Agent::TransactionState.tl_get
60
67
  duration = finish - start
61
68
 
@@ -22,12 +22,13 @@ module Sequel
22
22
  def wrap_sequel_method(method_name, operation_name=method_name)
23
23
  define_method(method_name) do |*args, &block|
24
24
  klass = self.is_a?(Class) ? self : self.class
25
-
26
25
  product = NewRelic::Agent::Instrumentation::SequelHelper.product_name_from_adapter(db.adapter_scheme)
27
- metrics = ::NewRelic::Agent::Datastores::MetricHelper.metrics_for(product, operation_name, klass.name)
26
+ segment = NewRelic::Agent::Transaction.start_datastore_segment(product, operation_name, klass.name)
28
27
 
29
- NewRelic::Agent::MethodTracer.trace_execution_scoped(metrics) do
28
+ begin
30
29
  NewRelic::Agent.disable_all_tracing { super(*args, &block) }
30
+ ensure
31
+ segment.finish
31
32
  end
32
33
  end
33
34
  end
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
10
10
  s.version = NewRelic::VERSION::STRING
11
11
  s.required_ruby_version = '>= 1.8.7'
12
12
  s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
13
- s.authors = [ "Tim Krajcar", "Matthew Wear", "Katherine Wu", "Karl Sandwich", "Caito Scherr" ]
13
+ s.authors = [ "Tim Krajcar", "Matthew Wear", "Katherine Wu", "Caito Scherr", "Kenichi Nakamura" ]
14
14
  s.date = Time.now.strftime('%Y-%m-%d')
15
15
  s.licenses = ['New Relic', 'MIT', 'Ruby']
16
16
  s.description = <<-EOS
@@ -49,14 +49,6 @@ EOS
49
49
  s.add_development_dependency 'pry', '~> 0.9.12'
50
50
  s.add_development_dependency 'hometown', '~> 0.2.5'
51
51
 
52
- # Only let Guard run on newer Rubies
53
- if RUBY_VERSION >= "1.9.3"
54
- s.add_development_dependency 'guard'
55
- s.add_development_dependency 'listen', '< 3.1' if RUBY_VERSION < "2.2.3"
56
- s.add_development_dependency 'guard-minitest'
57
- s.add_development_dependency 'rb-fsevent'
58
- end
59
-
60
52
  # rack-cache ~> 1.2 is specified by actionpack 3.2, but rack-cache 1.3.1 only works on Ruby 1.9.3 & newer. :(
61
53
  # https://github.com/rtomayko/rack-cache/issues/124
62
54
  if RUBY_VERSION < "1.9.3"
@@ -5,6 +5,7 @@
5
5
  require 'bundler'
6
6
 
7
7
  require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'multiverse', 'lib', 'multiverse', 'color'))
8
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'multiverse', 'lib', 'multiverse', 'shell_utils'))
8
9
 
9
10
  module Environments
10
11
  class Runner
@@ -94,14 +95,15 @@ module Environments
94
95
 
95
96
  def bundle(dir)
96
97
  puts "Bundling in #{dir}..."
97
- bundling = `cd #{dir} && bundle install --local`
98
+ result = `cd #{dir} && bundle install --local`
98
99
  unless $?.success?
99
100
  puts "Failed local bundle, trying again with full bundle..."
100
- bundling = `cd #{dir} && bundle install --retry 3`
101
+ command = "cd #{dir} && bundle install --retry 3"
102
+ result = Multiverse::ShellUtils.try_command_n_times(command, 3)
101
103
  end
102
104
 
103
- bundling = red(bundling) unless $?.success?
104
- puts bundling
105
+ result = red(result) unless $?.success?
106
+ puts result
105
107
  $?
106
108
  end
107
109
 
@@ -4,14 +4,20 @@ gem 'rake', '~>10.1.1'
4
4
 
5
5
  gem 'minitest', '~>4.7.5'
6
6
  gem 'mocha', :require => false
7
- gem 'rack'
7
+
8
+ if RUBY_VERSION < '2.2.2'
9
+ gem 'rack', '< 2.0.0'
10
+ else
11
+ gem 'rack'
12
+ end
13
+
8
14
  gem 'rack-test'
9
- gem 'json' if RUBY_VERSION == "1.8.7"
15
+ gem 'json', '< 2.0.0' if RUBY_VERSION == "1.8.7"
10
16
 
11
17
  platforms :rbx do
12
18
  gem "rubysl"
13
19
  gem "rubysl-test-unit"
14
- gem "json"
20
+ gem "json", '< 2.0.0'
15
21
  gem "psych"
16
22
  gem "racc" # https://github.com/rubinius/rubinius/issues/2632
17
23
  end
@@ -7,8 +7,7 @@ gem 'minitest', '~>4.7.5'
7
7
  gem "mocha", :require => false
8
8
  gem "jeweler", "1.4.0"
9
9
  gem "rdoc"
10
-
11
- gem 'rack'
10
+ gem 'rack', '< 2.0.0'
12
11
  gem 'rack-test'
13
12
  gem 'newrelic_rpm', :path => "../../.."
14
13
 
@@ -24,4 +23,8 @@ end
24
23
  gem 'pry', '~> 0.9.12'
25
24
  gem 'hometown', '~> 0.2.5'
26
25
 
27
- gem 'git', '< 1.3' if RUBY_VERSION < '1.9' # git 1.3.0 requires Ruby version >= 1.9
26
+ if RUBY_VERSION < '1.9'
27
+ gem 'git', '< 1.3' # git 1.3.0 requires Ruby version >= 1.9
28
+ gem 'json_pure', '< 2.0'
29
+ end
30
+
@@ -8,7 +8,7 @@ gem "mocha", :require => false
8
8
  gem "jeweler", "1.4.0"
9
9
  gem "rdoc"
10
10
 
11
- gem 'rack'
11
+ gem 'rack', '< 2.0.0'
12
12
  gem 'rack-test'
13
13
  gem 'newrelic_rpm', :path => '../../..'
14
14
 
@@ -24,4 +24,7 @@ end
24
24
  gem 'pry', '~> 0.9.12'
25
25
  gem 'hometown', '~> 0.2.5'
26
26
 
27
- gem 'git', '< 1.3' if RUBY_VERSION < '1.9' # git 1.3.0 requires Ruby version >= 1.9
27
+ if RUBY_VERSION < '1.9'
28
+ gem 'git', '< 1.3' # git 1.3.0 requires Ruby version >= 1.9
29
+ gem 'json_pure', '< 2.0'
30
+ end
@@ -5,7 +5,7 @@ gem "rails", "~> 2.3.18"
5
5
  gem 'rake', '~>10.1.1'
6
6
  gem 'minitest', '~>4.7.5'
7
7
  gem 'mocha', :require => false
8
- gem 'rack'
8
+ gem 'rack', '< 2.0.0'
9
9
  gem 'rack-test'
10
10
  gem 'rdoc'
11
11