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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 65e448cfa30a9ec08c2cafdeef4b85d91a4ab36b
4
- data.tar.gz: 6ce77fbb0850fdd68d403672df4544c81c1c1937
3
+ metadata.gz: ec626b83799ad14fe3e3534083621d692bfbd138
4
+ data.tar.gz: 0593104dbbfb3f5faa967043e7025e42991ce168
5
5
  SHA512:
6
- metadata.gz: e5b765cb31305ef2f4e1faffe2f715a8a89c39320d21baa7d375f8c4c88d7fabd8d104b8933727ca4750fd51080d92d9c0ee361486fe40ba5e3900602137efc4
7
- data.tar.gz: 6722c3012daab68738f96f5237bdbb72a18f972ba799b5e8046179d9a42f9dfbfed8e67c8382cf22e4a923748cc547de15134bef2f1c93984ad7c2569fef081c
6
+ metadata.gz: 3caec728f33c30b9149c5c01e27d9c573562268f19cc69a06416af69634e622c25e11cb2a9267082615b063b8f3963cb62de03ab97b9d6ddfb6aa721b18d7d66
7
+ data.tar.gz: 688803e2468ece921d1c4b18dd3f81bb3d7c5ddc41d6ecf0ebb24fef10db0fcfe8ca85d8f329f71a8126769e7bd6c036a9fe2234bee373eed29852dfbf71245f
@@ -45,7 +45,8 @@ rvm:
45
45
  # Run slowest builds first to try and optimize overall cycle time.
46
46
  - jruby-1.7.23
47
47
  - jruby-9.0.4.0
48
- - 2.2.4
48
+ - 2.3.1
49
+ - 2.2.5
49
50
  - 2.1.8
50
51
  - 2.0.0-p648
51
52
  - 1.9.3
@@ -97,12 +98,20 @@ matrix:
97
98
  env: TYPE=FUNCTIONAL GROUP=agent
98
99
 
99
100
  # Unsupported Rails/Ruby combinations
101
+ # 2.3
102
+ - rvm: 2.3.1
103
+ env: TYPE=UNIT ENVIRONMENT=rails21
104
+ - rvm: 2.3.1
105
+ env: TYPE=UNIT ENVIRONMENT=rails22
106
+ - rvm: 2.3.1
107
+ env: TYPE=UNIT ENVIRONMENT=rails23
108
+
100
109
  # 2.2
101
- - rvm: 2.2.4
110
+ - rvm: 2.2.5
102
111
  env: TYPE=UNIT ENVIRONMENT=rails21
103
- - rvm: 2.2.4
112
+ - rvm: 2.2.5
104
113
  env: TYPE=UNIT ENVIRONMENT=rails22
105
- - rvm: 2.2.4
114
+ - rvm: 2.2.5
106
115
  env: TYPE=UNIT ENVIRONMENT=rails23
107
116
 
108
117
  # 2.1
data/CHANGELOG CHANGED
@@ -1,11 +1,50 @@
1
1
  # New Relic Ruby Agent Release Notes #
2
2
 
3
+ ## v3.16.1
4
+
5
+ * Internal datastore instrumentation rewrites
6
+
7
+ The agent's internal tracing of datastore segments has been rewritten, and
8
+ instrumentation updated to utilize the new classes.
9
+
10
+ * Fix Grape endpoint versions in transaction names
11
+
12
+ Grape 0.16 changed Route#version (formerly #route_version) to possibly return
13
+ an Array of versions for the current endpoint. The agent has been updated to
14
+ use rack.env['api.version'] set by Grape, and fall back to joining the version
15
+ Array with '|' before inclusion in the transaction name when api.version is
16
+ not available. Thanks Geoff Massanek for the contribution!
17
+
18
+ * Fix deprecation warnings from various Rails error subclasses
19
+
20
+ Rails 5 deprecates #original_exception on a few internal subclasses of
21
+ StandardError in favor of Exception#cause from Ruby stdlib. The agent has
22
+ been updated to try Exception#cause first, thus avoiding deprecation
23
+ warnings. Thanks Alexander Stuart-Kregor for the contribution!
24
+
25
+ * Fix instrumentation for Sequel 4.35.0
26
+
27
+ The latest version of Sequel changes the name and signature of the method
28
+ that the Ruby Agent wraps for instrumentation. The agent has been updated
29
+ to handle these changes. Users using Sequel 4.35.0 or newer should upgrade
30
+ their agent.
31
+
32
+ * Fix DataMapper instrumentation for additional versions
33
+
34
+ Different versions of DataMapper have different methods for retrieving the
35
+ adapter name, and Postmodern expanded our coverage. Thanks for the
36
+ contribution!
37
+
3
38
  ## v3.16.0
4
39
 
5
- * Experimental Action Cable instrumentation
40
+ * Official Rails 5.0 support
41
+
42
+ This version of the agent has been verified against the Rails 5.0.0 release.
43
+
44
+ * Early access Action Cable instrumentation
6
45
 
7
46
  The Ruby agent instruments Action Cable channel actions and calls to
8
- ActionCable::Channel#Transmit in Rails 5 RC1. Feedback is welcome!
47
+ ActionCable::Channel#Transmit in Rails 5. Feedback is welcome!
9
48
 
10
49
  * Obfuscate queries from `oracle_enhanced` adapter correctly
11
50
 
@@ -27,8 +27,17 @@ module NewRelic
27
27
 
28
28
  extend self
29
29
 
30
+ # Properly encode, truncate, and dup the incoming query.
31
+ # Take care not to the dup the query more than once as
32
+ # correctly encoded may also dup the query.
30
33
  def capture_query(query)
31
- Helper.correctly_encoded(truncate_query(query))
34
+ id = query.object_id
35
+ query = Helper.correctly_encoded(truncate_query(query))
36
+ if query.object_id == id
37
+ query.dup
38
+ else
39
+ query
40
+ end
32
41
  end
33
42
 
34
43
  def truncate_query(query)
@@ -176,7 +185,7 @@ module NewRelic
176
185
 
177
186
  DEFAULT_QUERY_NAME = "SQL".freeze
178
187
 
179
- def initialize(sql, config={}, explainer=nil, binds=[], name=DEFAULT_QUERY_NAME)
188
+ def initialize(sql, config={}, explainer=nil, binds=nil, name=DEFAULT_QUERY_NAME)
180
189
  @sql = Database.capture_query(sql)
181
190
  @config = config
182
191
  @explainer = explainer
@@ -232,15 +241,17 @@ module NewRelic
232
241
  end
233
242
  end
234
243
 
244
+ ELLIPSIS = "...".freeze
245
+
235
246
  def explainable?
236
247
  return false unless @explainer && is_select?(@sql)
237
248
 
238
- if @sql[-3,3] == '...'
249
+ if @sql.end_with?(ELLIPSIS)
239
250
  NewRelic::Agent.logger.debug('Unable to collect explain plan for truncated query.')
240
251
  return false
241
252
  end
242
253
 
243
- if parameterized?(@sql) && @binds.empty?
254
+ if parameterized?(@sql) && (!@binds || @binds.empty?)
244
255
  NewRelic::Agent.logger.debug('Unable to collect explain plan for parameter-less parameterized query.')
245
256
  return false
246
257
  end
@@ -11,9 +11,10 @@ module NewRelic
11
11
  module ExplainPlanHelpers
12
12
 
13
13
  SUPPORTED_ADAPTERS_FOR_EXPLAIN = [:postgres, :mysql2, :mysql, :sqlite]
14
+ SELECT = 'select'.freeze
14
15
 
15
16
  def is_select?(sql)
16
- NewRelic::Agent::Database.parse_operation_from_query(sql) == 'select'
17
+ NewRelic::Agent::Database.parse_operation_from_query(sql) == SELECT
17
18
  end
18
19
 
19
20
  def parameterized?(sql)
@@ -45,9 +45,11 @@ module NewRelic
45
45
  alias_method method_name_without_newrelic, method_name
46
46
 
47
47
  define_method(method_name) do |*args, &blk|
48
- metrics = MetricHelper.metrics_for(product, operation)
49
- NewRelic::Agent::MethodTracer.trace_execution_scoped(metrics) do
48
+ segment = NewRelic::Agent::Transaction.start_datastore_segment(product, operation)
49
+ begin
50
50
  send(method_name_without_newrelic, *args, &blk)
51
+ ensure
52
+ segment.finish
51
53
  end
52
54
  end
53
55
 
@@ -103,18 +105,16 @@ module NewRelic
103
105
  def self.wrap(product, operation, collection = nil, callback = nil)
104
106
  return yield unless operation
105
107
 
106
- metrics = MetricHelper.metrics_for(product, operation, collection)
107
- scoped_metric = metrics.first
108
- NewRelic::Agent::MethodTracer.trace_execution_scoped(metrics) do
109
- t0 = Time.now if callback
110
- begin
111
- result = yield
112
- ensure
113
- if callback
114
- elapsed_time = (Time.now - t0).to_f
115
- callback.call(result, scoped_metric, elapsed_time)
116
- end
108
+ segment = NewRelic::Agent::Transaction.start_datastore_segment(product, operation, collection)
109
+
110
+ begin
111
+ result = yield
112
+ ensure
113
+ if callback
114
+ elapsed_time = (Time.now - segment.start_time).to_f
115
+ callback.call(result, segment.name, elapsed_time)
117
116
  end
117
+ segment.finish
118
118
  end
119
119
  end
120
120
 
@@ -44,14 +44,41 @@ module NewRelic
44
44
  end
45
45
  end
46
46
 
47
- def self.metrics_for(product, operation, collection = nil, generic_product = nil)
47
+ def self.scoped_metric_for product, operation, collection=nil
48
+ if collection
49
+ statement_metric_for product, collection, operation
50
+ else
51
+ operation_metric_for product, operation
52
+ end
53
+ end
54
+
55
+ def self.unscoped_metrics_for product, operation, collection=nil
56
+ suffix = all_suffix
57
+
58
+ metrics = [
59
+ product_suffixed_rollup(product, suffix),
60
+ product_rollup(product),
61
+ suffixed_rollup(suffix),
62
+ ROLLUP_METRIC
63
+ ]
64
+
65
+ metrics.unshift operation_metric_for(product, operation) if collection
66
+
67
+ metrics
68
+ end
69
+
70
+ def self.product_operation_collection_for product, operation, collection=nil, generic_product = nil
48
71
  if overrides = overridden_operation_and_collection
49
72
  if should_override?(overrides, product, generic_product)
50
73
  operation = overrides[0] || operation
51
74
  collection = overrides[1] || collection
52
75
  end
53
76
  end
77
+ [product, operation, collection]
78
+ end
54
79
 
80
+ def self.metrics_for(product, operation, collection = nil, generic_product = nil)
81
+ product, operation, collection = product_operation_collection_for(product, operation, collection, generic_product)
55
82
  suffix = all_suffix
56
83
 
57
84
  # Order of these metrics matters--the first metric in the list will
@@ -70,10 +97,14 @@ module NewRelic
70
97
  end
71
98
 
72
99
  def self.metrics_from_sql(product, sql)
73
- operation = NewRelic::Agent::Database.parse_operation_from_query(sql) || OTHER
100
+ operation = operation_from_sql(sql)
74
101
  metrics_for(product, operation)
75
102
  end
76
103
 
104
+ def self.operation_from_sql(sql)
105
+ NewRelic::Agent::Database.parse_operation_from_query(sql) || OTHER
106
+ end
107
+
77
108
  # Allow Transaction#with_database_metric_name to override our
78
109
  # collection and operation
79
110
  def self.overridden_operation_and_collection #THREAD_LOCAL_ACCESS
@@ -10,7 +10,7 @@ module NewRelic
10
10
  module Datastores
11
11
  module Mongo
12
12
  module MetricTranslator
13
- def self.metrics_for(name, payload)
13
+ def self.operation_and_collection_for(name, payload)
14
14
  payload ||= {}
15
15
 
16
16
  if collection_in_selector?(payload)
@@ -51,20 +51,14 @@ module NewRelic
51
51
  collection = collection_name_from_rename_selector(payload)
52
52
  end
53
53
 
54
- build_metrics(name, collection)
54
+ [name.to_s, collection]
55
55
  rescue => e
56
56
  NewRelic::Agent.logger.debug("Failure during Mongo metric generation", e)
57
- []
57
+ nil
58
58
  end
59
59
 
60
60
  MONGO_PRODUCT_NAME = "MongoDB".freeze
61
61
 
62
- def self.build_metrics(name, collection)
63
- NewRelic::Agent::Datastores::MetricHelper.metrics_for(MONGO_PRODUCT_NAME,
64
- name,
65
- collection)
66
- end
67
-
68
62
  def self.collection_in_selector?(payload)
69
63
  payload[:collection] == '$cmd' && payload[:selector]
70
64
  end
@@ -185,8 +185,8 @@ module NewRelic
185
185
 
186
186
  # extracts a stack trace from the exception for debugging purposes
187
187
  def extract_stack_trace(exception)
188
- actual_exception = sense_method(exception, 'original_exception') || exception
189
- sense_method(actual_exception, 'backtrace') || '<no stack trace>'
188
+ actual_exception = sense_method(exception, :cause) || sense_method(exception, :original_exception) || exception
189
+ sense_method(actual_exception, :backtrace) || '<no stack trace>'
190
190
  end
191
191
 
192
192
  # See NewRelic::Agent.notice_error for options and commentary
@@ -44,29 +44,19 @@ module NewRelic
44
44
  end
45
45
 
46
46
  sql, name, _ = args
47
- metrics = ActiveRecordHelper.metrics_for(
47
+
48
+ product, operation, collection = ActiveRecordHelper.product_operation_collection_for(
48
49
  NewRelic::Helper.correctly_encoded(name),
49
50
  NewRelic::Helper.correctly_encoded(sql),
50
51
  @config && @config[:adapter])
51
52
 
52
- # It is critical that we grab this name before trace_execution_scoped
53
- # because that method mutates the metrics list passed in.
54
- scoped_metric = metrics.first
55
-
56
- NewRelic::Agent::MethodTracer.trace_execution_scoped(metrics) do
57
- t0 = Time.now
58
- begin
59
- log_without_newrelic_instrumentation(*args, &block)
60
- ensure
61
- elapsed_time = (Time.now - t0).to_f
62
-
63
- NewRelic::Agent.instance.transaction_sampler.notice_sql(sql,
64
- @config, elapsed_time,
65
- state, EXPLAINER)
66
- NewRelic::Agent.instance.sql_sampler.notice_sql(sql, scoped_metric,
67
- @config, elapsed_time,
68
- state, EXPLAINER)
69
- end
53
+ segment = NewRelic::Agent::Transaction.start_datastore_segment(product, operation, collection)
54
+ segment._notice_sql(sql, @config, EXPLAINER)
55
+
56
+ begin
57
+ log_without_newrelic_instrumentation(*args, &block)
58
+ ensure
59
+ segment.finish
70
60
  end
71
61
  end
72
62
  end
@@ -86,16 +86,12 @@ module NewRelic
86
86
  ACTIVE_RECORD = "ActiveRecord".freeze unless defined?(ACTIVE_RECORD)
87
87
  OTHER = "other".freeze unless defined?(OTHER)
88
88
 
89
- def metrics_for(name, sql, adapter_name)
89
+ def product_operation_collection_for name, sql, adapter_name
90
90
  product = map_product(adapter_name)
91
91
  splits = split_name(name)
92
92
  model = model_from_splits(splits)
93
93
  operation = operation_from_splits(splits, sql)
94
-
95
- NewRelic::Agent::Datastores::MetricHelper.metrics_for(product,
96
- operation,
97
- model,
98
- ACTIVE_RECORD)
94
+ NewRelic::Agent::Datastores::MetricHelper.product_operation_collection_for product, operation, model, ACTIVE_RECORD
99
95
  end
100
96
 
101
97
  # @deprecated
@@ -23,7 +23,9 @@ module NewRelic
23
23
  def start(name, id, payload) #THREAD_LOCAL_ACCESS
24
24
  return if payload[:name] == CACHED_QUERY_NAME
25
25
  return unless NewRelic::Agent.tl_is_execution_traced?
26
- super
26
+ config = active_record_config(payload)
27
+ event = ActiveRecordEvent.new(name, Time.now, nil, id, payload, @explainer, config)
28
+ push_event(event)
27
29
  rescue => e
28
30
  log_notification_error(e, name, 'start')
29
31
  end
@@ -32,10 +34,8 @@ module NewRelic
32
34
  return if payload[:name] == CACHED_QUERY_NAME
33
35
  state = NewRelic::Agent::TransactionState.tl_get
34
36
  return unless state.is_execution_traced?
35
- event = pop_event(id)
36
- config = active_record_config_for_event(event)
37
- base_metric = record_metrics(event, config)
38
- notice_sql(state, event, config, base_metric)
37
+ event = pop_event(id)
38
+ event.finish
39
39
  rescue => e
40
40
  log_notification_error(e, name, 'finish')
41
41
  end
@@ -52,43 +52,11 @@ module NewRelic
52
52
  end
53
53
  end
54
54
 
55
- def notice_sql(state, event, config, metric)
56
- stack = state.traced_method_stack
57
-
58
- # enter transaction trace node
59
- frame = stack.push_frame(state, :active_record, event.time)
60
-
61
- NewRelic::Agent.instance.transaction_sampler \
62
- .notice_sql(event.payload[:sql], config,
63
- Helper.milliseconds_to_seconds(event.duration),
64
- state, @explainer, event.payload[:binds], event.payload[:name])
65
-
66
- NewRelic::Agent.instance.sql_sampler \
67
- .notice_sql(event.payload[:sql], metric, config,
68
- Helper.milliseconds_to_seconds(event.duration),
69
- state, @explainer, event.payload[:binds], event.payload[:name])
70
-
71
- # exit transaction trace node
72
- stack.pop_frame(state, frame, metric, event.end)
73
- end
74
-
75
- def record_metrics(event, config) #THREAD_LOCAL_ACCESS
76
- base, *other_metrics = ActiveRecordHelper.metrics_for(event.payload[:name],
77
- NewRelic::Helper.correctly_encoded(event.payload[:sql]),
78
- config && config[:adapter])
79
-
80
- NewRelic::Agent.instance.stats_engine.tl_record_scoped_and_unscoped_metrics(
81
- base, other_metrics,
82
- Helper.milliseconds_to_seconds(event.duration))
83
-
84
- base
85
- end
86
-
87
- def active_record_config_for_event(event)
88
- return unless event.payload[:connection_id]
55
+ def active_record_config(payload)
56
+ return unless payload[:connection_id]
89
57
 
90
58
  connection = nil
91
- connection_id = event.payload[:connection_id]
59
+ connection_id = payload[:connection_id]
92
60
 
93
61
  ::ActiveRecord::Base.connection_handler.connection_pool_list.each do |handler|
94
62
  connection = handler.connections.detect do |conn|
@@ -100,6 +68,47 @@ module NewRelic
100
68
 
101
69
  connection.instance_variable_get(:@config) if connection
102
70
  end
71
+
72
+ class ActiveRecordEvent < Event
73
+ def initialize(name, start, ending, transaction_id, payload, explainer, config)
74
+ super(name, start, ending, transaction_id, payload)
75
+ @explainer = explainer
76
+ @config = config
77
+ @segment = start_segment
78
+ end
79
+
80
+ # Events do not always finish in the order they are started for this subscriber.
81
+ # The traced_method_stack expects that frames are popped off in the order that they
82
+ # are pushed, otherwise it will continue to pop up the stack until it finds the frame
83
+ # it expects. This will be fixed when we replace the tracer internals, but for now
84
+ # we need to work around this limitation.
85
+ def start_segment
86
+ product, operation, collection = ActiveRecordHelper.product_operation_collection_for(payload[:name],
87
+ sql, @config && @config[:adapter])
88
+ segment = NewRelic::Agent::Transaction::DatastoreSegment.new product, operation, collection
89
+ if txn = state.current_transaction
90
+ segment.transaction = txn
91
+ end
92
+ segment._notice_sql sql, @config, @explainer, payload[:binds], payload[:name]
93
+ segment.start
94
+ segment
95
+ end
96
+
97
+ # See comment for start_segment as we continue to work around limitations of the
98
+ # current tracer in this method.
99
+ def finish
100
+ state.traced_method_stack.push_segment state, @segment
101
+ @segment.finish
102
+ end
103
+
104
+ def state
105
+ @state ||= NewRelic::Agent::TransactionState.tl_get
106
+ end
107
+
108
+ def sql
109
+ @sql ||= Helper.correctly_encoded payload[:sql]
110
+ end
111
+ end
103
112
  end
104
113
  end
105
114
  end