newrelic_rpm 3.10.0.279 → 3.11.0.283

Sign up to get free protection for your applications and to get access to all the features.
Files changed (180) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG +61 -0
  3. data/lib/new_relic/agent.rb +14 -8
  4. data/lib/new_relic/agent/agent.rb +43 -28
  5. data/lib/new_relic/agent/agent_logger.rb +21 -20
  6. data/lib/new_relic/agent/configuration/default_source.rb +31 -1
  7. data/lib/new_relic/agent/database.rb +2 -1
  8. data/lib/new_relic/agent/datastores.rb +177 -0
  9. data/lib/new_relic/agent/datastores/metric_helper.rb +85 -0
  10. data/lib/new_relic/agent/datastores/mongo/metric_translator.rb +11 -20
  11. data/lib/new_relic/agent/deprecator.rb +18 -0
  12. data/lib/new_relic/agent/instrumentation/active_record.rb +20 -35
  13. data/lib/new_relic/agent/instrumentation/active_record_helper.rb +116 -57
  14. data/lib/new_relic/agent/instrumentation/active_record_subscriber.rb +11 -20
  15. data/lib/new_relic/agent/instrumentation/data_mapper.rb +104 -172
  16. data/lib/new_relic/agent/instrumentation/memcache.rb +104 -52
  17. data/lib/new_relic/agent/instrumentation/metric_frame.rb +9 -0
  18. data/lib/new_relic/agent/instrumentation/middleware_proxy.rb +15 -2
  19. data/lib/new_relic/agent/instrumentation/mongo.rb +5 -18
  20. data/lib/new_relic/agent/instrumentation/sequel_helper.rb +36 -0
  21. data/lib/new_relic/agent/new_relic_service.rb +4 -0
  22. data/lib/new_relic/agent/stats_engine/metric_stats.rb +2 -17
  23. data/lib/new_relic/agent/threading/backtrace_service.rb +28 -5
  24. data/lib/new_relic/agent/transaction.rb +63 -34
  25. data/lib/new_relic/agent/transaction_event_aggregator.rb +0 -4
  26. data/lib/new_relic/agent/transaction_sampler.rb +11 -5
  27. data/lib/new_relic/rack/error_collector.rb +0 -1
  28. data/lib/new_relic/version.rb +1 -1
  29. data/lib/sequel/extensions/newrelic_instrumentation.rb +28 -56
  30. data/lib/sequel/plugins/newrelic_instrumentation.rb +28 -45
  31. data/newrelic_rpm.gemspec +0 -7
  32. data/test/agent_helper.rb +35 -16
  33. data/test/environments/rails31/Gemfile +1 -0
  34. data/test/environments/rails32/Gemfile +1 -0
  35. data/test/helpers/mongo_metric_builder.rb +2 -3
  36. data/test/multiverse/lib/multiverse/output_collector.rb +24 -9
  37. data/test/multiverse/lib/multiverse/suite.rb +5 -0
  38. data/test/multiverse/suites/active_record/Envfile +6 -4
  39. data/test/multiverse/suites/active_record/active_record_test.rb +32 -73
  40. data/test/multiverse/suites/active_record/ar_method_aliasing.rb +0 -1
  41. data/test/multiverse/suites/activemerchant/activemerchant_test.rb +0 -3
  42. data/test/multiverse/suites/agent_only/agent_run_id_handling_test.rb +0 -1
  43. data/test/multiverse/suites/agent_only/audit_log_test.rb +0 -1
  44. data/test/multiverse/suites/agent_only/collector_exception_handling_test.rb +0 -2
  45. data/test/multiverse/suites/agent_only/cross_application_tracing_test.rb +0 -1
  46. data/test/multiverse/suites/agent_only/custom_analytics_events_test.rb +0 -2
  47. data/test/multiverse/suites/agent_only/custom_queue_time_test.rb +0 -1
  48. data/test/multiverse/suites/agent_only/encoding_handling_test.rb +0 -2
  49. data/test/multiverse/suites/agent_only/exclusive_time_test.rb +0 -2
  50. data/test/multiverse/suites/agent_only/harvest_timestamps_test.rb +0 -1
  51. data/test/multiverse/suites/agent_only/http_response_code_test.rb +0 -1
  52. data/test/multiverse/suites/agent_only/keepalive_test.rb +0 -1
  53. data/test/multiverse/suites/agent_only/key_transactions_test.rb +54 -9
  54. data/test/multiverse/suites/agent_only/labels_test.rb +0 -2
  55. data/test/multiverse/suites/agent_only/logging_test.rb +0 -1
  56. data/test/multiverse/suites/agent_only/marshaling_test.rb +0 -1
  57. data/test/multiverse/suites/agent_only/pipe_manager_test.rb +0 -2
  58. data/test/multiverse/suites/agent_only/rename_rule_test.rb +5 -7
  59. data/test/multiverse/suites/agent_only/rum_instrumentation_test.rb +0 -1
  60. data/test/multiverse/suites/agent_only/set_transaction_name_test.rb +0 -2
  61. data/test/multiverse/suites/agent_only/ssl_test.rb +0 -2
  62. data/test/multiverse/suites/agent_only/synthetics_test.rb +0 -1
  63. data/test/multiverse/suites/agent_only/testing_app.rb +21 -0
  64. data/test/multiverse/suites/agent_only/thread_profiling_test.rb +1 -2
  65. data/test/multiverse/suites/agent_only/transaction_ignoring_test.rb +0 -2
  66. data/test/multiverse/suites/agent_only/utilization_data_collection_test.rb +0 -1
  67. data/test/multiverse/suites/agent_only/xray_sessions_test.rb +69 -34
  68. data/test/multiverse/suites/capistrano/deployment_test.rb +0 -1
  69. data/test/multiverse/suites/capistrano2/deployment_test.rb +0 -1
  70. data/test/multiverse/suites/config_file_loading/config_file_loading_test.rb +0 -2
  71. data/test/multiverse/suites/curb/curb_test.rb +0 -2
  72. data/test/multiverse/suites/datamapper/Envfile +26 -3
  73. data/test/multiverse/suites/datamapper/config/newrelic.yml +1 -0
  74. data/test/multiverse/suites/datamapper/datamapper_test.rb +271 -37
  75. data/test/multiverse/suites/deferred_instrumentation/sinatra_test.rb +0 -1
  76. data/test/multiverse/suites/delayed_job/Envfile +31 -8
  77. data/test/multiverse/suites/delayed_job/delayed_job_sampler_test.rb +0 -3
  78. data/test/multiverse/suites/delayed_job/unsupported_backend_test.rb +0 -3
  79. data/test/multiverse/suites/excon/excon_test.rb +0 -2
  80. data/test/multiverse/suites/grape/grape_test.rb +0 -3
  81. data/test/multiverse/suites/grape/grape_versioning_test.rb +0 -3
  82. data/test/multiverse/suites/grape/unsupported_version_test.rb +0 -3
  83. data/test/multiverse/suites/high_security/high_security_test.rb +0 -1
  84. data/test/multiverse/suites/httpclient/httpclient_test.rb +0 -2
  85. data/test/multiverse/suites/json/json_test.rb +0 -1
  86. data/test/multiverse/suites/marshalling/marshalling_test.rb +0 -1
  87. data/test/multiverse/suites/memcached/Envfile +52 -0
  88. data/test/multiverse/suites/memcached/dalli_test.rb +89 -0
  89. data/test/multiverse/suites/memcached/memcache_client_test.rb +25 -0
  90. data/test/multiverse/suites/memcached/memcache_test_cases.rb +302 -0
  91. data/test/multiverse/suites/memcached/memcached_test.rb +159 -0
  92. data/test/multiverse/suites/mongo/helpers/mongo_operation_tests.rb +26 -17
  93. data/test/multiverse/suites/mongo/mongo_connection_test.rb +0 -1
  94. data/test/multiverse/suites/mongo/mongo_instrumentation_test.rb +0 -1
  95. data/test/multiverse/suites/mongo/mongo_unsupported_version_test.rb +0 -1
  96. data/test/multiverse/suites/net_http/net_http_test.rb +0 -2
  97. data/test/multiverse/suites/padrino/padrino_test.rb +0 -3
  98. data/test/multiverse/suites/rack/http_response_code_test.rb +0 -1
  99. data/test/multiverse/suites/rack/nested_non_rack_app_test.rb +1 -1
  100. data/test/multiverse/suites/rack/rack_auto_instrumentation_test.rb +12 -12
  101. data/test/multiverse/suites/rack/rack_cascade_test.rb +0 -1
  102. data/test/multiverse/suites/rack/rack_env_mutation_test.rb +0 -1
  103. data/test/multiverse/suites/rack/rack_parameter_filtering_test.rb +0 -1
  104. data/test/multiverse/suites/rack/rack_unsupported_version_test.rb +0 -2
  105. data/test/multiverse/suites/rack/url_map_test.rb +3 -2
  106. data/test/multiverse/suites/rails/Envfile +3 -0
  107. data/test/multiverse/suites/rails/activejob_test.rb +0 -1
  108. data/test/multiverse/suites/rails/app.rb +0 -1
  109. data/test/multiverse/suites/rails/parameter_capture_test.rb +13 -0
  110. data/test/multiverse/suites/rails/rails3_app/app_rails3_plus.rb +5 -0
  111. data/test/multiverse/suites/rails/transaction_ignoring_test.rb +0 -2
  112. data/test/multiverse/suites/resque/instrumentation_test.rb +0 -2
  113. data/test/multiverse/suites/resque/resque_marshalling_test.rb +0 -1
  114. data/test/multiverse/suites/sequel/sequel_extension_test.rb +135 -0
  115. data/test/multiverse/suites/sequel/sequel_helpers.rb +62 -0
  116. data/test/multiverse/suites/sequel/sequel_plugin_test.rb +230 -0
  117. data/test/multiverse/suites/sidekiq/sidekiq_instrumentation_test.rb +0 -2
  118. data/test/multiverse/suites/sinatra/ignoring_test.rb +0 -2
  119. data/test/multiverse/suites/sinatra/nested_middleware_test.rb +0 -2
  120. data/test/multiverse/suites/sinatra/sinatra_classic_test.rb +0 -1
  121. data/test/multiverse/suites/sinatra/sinatra_error_tracing_test.rb +0 -2
  122. data/test/multiverse/suites/sinatra/sinatra_metric_explosion_test.rb +14 -12
  123. data/test/multiverse/suites/sinatra/sinatra_modular_test.rb +0 -1
  124. data/test/multiverse/suites/sinatra/sinatra_routes_test.rb +0 -2
  125. data/test/multiverse/suites/sinatra/sinatra_test_cases.rb +0 -2
  126. data/test/multiverse/suites/typhoeus/typhoeus_test.rb +0 -2
  127. data/test/multiverse/suites/yajl/yajl_test.rb +0 -1
  128. data/test/new_relic/agent/agent/start_test.rb +2 -2
  129. data/test/new_relic/agent/agent_logger_test.rb +6 -3
  130. data/test/new_relic/agent/datastores/metric_helper_test.rb +61 -0
  131. data/test/new_relic/agent/datastores/mongo/metric_translator_test.rb +20 -21
  132. data/test/new_relic/agent/datastores_test.rb +195 -0
  133. data/test/new_relic/agent/deprecator_test.rb +52 -0
  134. data/test/new_relic/agent/instrumentation/action_view_subscriber_test.rb +20 -26
  135. data/test/new_relic/agent/instrumentation/active_record_helper_test.rb +58 -53
  136. data/test/new_relic/agent/instrumentation/active_record_subscriber_test.rb +7 -20
  137. data/test/new_relic/agent/instrumentation/middleware_proxy_test.rb +19 -0
  138. data/test/new_relic/agent/instrumentation/sequel_helper_test.rb +36 -0
  139. data/test/new_relic/agent/instrumentation/task_instrumentation_test.rb +1 -0
  140. data/test/new_relic/agent/method_tracer_test.rb +3 -4
  141. data/test/new_relic/agent/pipe_channel_manager_test.rb +1 -1
  142. data/test/new_relic/agent/threading/backtrace_service_test.rb +29 -4
  143. data/test/new_relic/agent/transaction_event_aggregator_test.rb +0 -4
  144. data/test/new_relic/agent/transaction_test.rb +100 -2
  145. data/test/new_relic/agent_test.rb +3 -3
  146. data/test/new_relic/http_client_test_cases.rb +0 -1
  147. data/test/new_relic/multiverse_helpers.rb +7 -0
  148. data/test/new_relic/transaction_ignoring_test_cases.rb +0 -2
  149. data/test/new_relic/transaction_sample_test.rb +11 -2
  150. data/test/performance/README.md +37 -17
  151. data/test/performance/lib/performance.rb +1 -0
  152. data/test/performance/lib/performance/baseline_compare_reporter.rb +11 -7
  153. data/test/performance/lib/performance/console_reporter.rb +29 -5
  154. data/test/performance/lib/performance/formatting_helpers.rb +22 -0
  155. data/test/performance/lib/performance/instrumentation/stackprof.rb +11 -1
  156. data/test/performance/lib/performance/result.rb +17 -6
  157. data/test/performance/lib/performance/runner.rb +7 -3
  158. data/test/performance/lib/performance/test_case.rb +89 -21
  159. data/test/performance/script/runner +13 -1
  160. data/test/performance/suites/active_record.rb +47 -0
  161. data/test/performance/suites/config.rb +4 -48
  162. data/test/performance/suites/marshalling.rb +20 -30
  163. data/test/performance/suites/queue_time.rb +1 -1
  164. data/test/performance/suites/rack_middleware.rb +1 -1
  165. data/test/performance/suites/rum_autoinsertion.rb +1 -1
  166. data/test/performance/suites/sql_obfuscation.rb +2 -2
  167. data/test/performance/suites/startup.rb +1 -1
  168. data/test/performance/suites/stats_hash.rb +7 -11
  169. data/test/performance/suites/thread_profiling.rb +20 -25
  170. data/test/performance/suites/trace_execution_scoped.rb +2 -2
  171. data/test/performance/suites/transaction_tracing.rb +4 -2
  172. data/test/test_helper.rb +5 -1
  173. metadata +53 -100
  174. data.tar.gz.sig +0 -0
  175. data/gem-public_cert.pem +0 -20
  176. data/lib/new_relic/agent/datastores/mongo/metric_generator.rb +0 -33
  177. data/test/multiverse/suites/sequel/sequel_instrumentation_test.rb +0 -289
  178. data/test/new_relic/agent/datastores/mongo/metric_generator_test.rb +0 -69
  179. data/test/new_relic/agent/memcache_instrumentation_test.rb +0 -155
  180. metadata.gz.sig +0 -2
@@ -2,6 +2,8 @@
2
2
  # This file is distributed under New Relic's license terms.
3
3
  # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
4
4
 
5
+ require 'new_relic/agent/deprecator'
6
+
5
7
  module NewRelic
6
8
  module Agent
7
9
  module Instrumentation
@@ -17,11 +19,18 @@ module NewRelic
17
19
 
18
20
  # @deprecated
19
21
  def self.recording_web_transaction?
22
+ NewRelic::Agent::Deprecator.deprecate(
23
+ "NewRelic::Agent::Instrumentation::MetricFrame.recording_web_transaction?",
24
+ "NewRelic::Agent::Transaction.recording_web_transaction?")
25
+
20
26
  Transaction.recording_web_transaction?
21
27
  end
22
28
 
23
29
  # @deprecated
24
30
  def self.abort_transaction!
31
+ NewRelic::Agent::Deprecator.deprecate(
32
+ "NewRelic::Agent::Instrumentation::MetricFrame.abort_transaction!",
33
+ "NewRelic::Agent::Transaction.abort_transaction!")
25
34
  Transaction.abort_transaction!
26
35
  end
27
36
  end
@@ -15,6 +15,9 @@ module NewRelic
15
15
  class MiddlewareProxy
16
16
  include MiddlewareTracing
17
17
 
18
+ ANONYMOUS_CLASS = "AnonymousClass".freeze unless defined?(ANONYMOUS_CLASS)
19
+ OBJECT_CLASS_NAME = "Object".freeze unless defined?(OBJECT_CLASS_NAME)
20
+
18
21
  # This class is used to wrap classes that are passed to
19
22
  # Rack::Builder#use without synchronously instantiating those classes.
20
23
  # A MiddlewareProxy::Generator responds to new, like a Class would, and
@@ -84,12 +87,22 @@ module NewRelic
84
87
  # to a singleton instance of the the subclass. We need to ensure that we
85
88
  # capture the correct name in both cases.
86
89
  def determine_class_name
90
+ clazz = class_for_target
91
+
92
+ name = clazz.name
93
+ name = clazz.superclass.name if name.nil? || name == ""
94
+ name = ANONYMOUS_CLASS if name.nil? || name == OBJECT_CLASS_NAME
95
+ name
96
+ end
97
+
98
+ def class_for_target
87
99
  if @target.is_a?(Class)
88
- @target.name
100
+ @target
89
101
  else
90
- @target.class.name
102
+ @target.class
91
103
  end
92
104
  end
105
+
93
106
  end
94
107
  end
95
108
  end
@@ -20,7 +20,7 @@ DependencyDetection.defer do
20
20
  end
21
21
 
22
22
  def install_mongo_instrumentation
23
- require 'new_relic/agent/datastores/mongo/metric_generator'
23
+ require 'new_relic/agent/datastores/mongo/metric_translator'
24
24
  require 'new_relic/agent/datastores/mongo/statement_formatter'
25
25
 
26
26
  hook_instrument_methods
@@ -39,19 +39,6 @@ DependencyDetection.defer do
39
39
  target_class.class_eval do
40
40
  include NewRelic::Agent::MethodTracer
41
41
 
42
- def new_relic_instance_metric_builder
43
- Proc.new do
44
- if @pool
45
- host, port = @pool.host, @pool.port
46
- elsif @connection && (primary = @connection.primary)
47
- host, port = primary[0], primary[1]
48
- end
49
-
50
- database_name = @db.name if @db
51
- NewRelic::Agent::Datastores::Mongo::MetricGenerator.generate_instance_metric_for(host, port, database_name)
52
- end
53
- end
54
-
55
42
  # It's key that this method eats all exceptions, as it rests between the
56
43
  # Mongo operation the user called and us returning them the data. Be safe!
57
44
  def new_relic_notice_statement(t0, payload, name)
@@ -65,13 +52,13 @@ DependencyDetection.defer do
65
52
 
66
53
  def new_relic_generate_metrics(operation, payload = nil)
67
54
  payload ||= { :collection => self.name, :database => self.db.name }
68
- NewRelic::Agent::Datastores::Mongo::MetricGenerator.generate_metrics_for(operation, payload)
55
+ NewRelic::Agent::Datastores::Mongo::MetricTranslator.metrics_for(operation, payload)
69
56
  end
70
57
 
71
58
  def instrument_with_new_relic_trace(name, payload = {}, &block)
72
59
  metrics = new_relic_generate_metrics(name, payload)
73
60
 
74
- trace_execution_scoped(metrics, :additional_metrics_callback => new_relic_instance_metric_builder) do
61
+ trace_execution_scoped(metrics) do
75
62
  t0 = Time.now
76
63
 
77
64
  result = NewRelic::Agent.disable_all_tracing do
@@ -92,7 +79,7 @@ DependencyDetection.defer do
92
79
  ::Mongo::Collection.class_eval do
93
80
  def save_with_new_relic_trace(doc, opts = {}, &block)
94
81
  metrics = new_relic_generate_metrics(:save)
95
- trace_execution_scoped(metrics, :additional_metrics_callback => new_relic_instance_metric_builder) do
82
+ trace_execution_scoped(metrics) do
96
83
  t0 = Time.now
97
84
 
98
85
  result = NewRelic::Agent.disable_all_tracing do
@@ -113,7 +100,7 @@ DependencyDetection.defer do
113
100
  ::Mongo::Collection.class_eval do
114
101
  def ensure_index_with_new_relic_trace(spec, opts = {}, &block)
115
102
  metrics = new_relic_generate_metrics(:ensureIndex)
116
- trace_execution_scoped(metrics, :additional_metrics_callback => new_relic_instance_metric_builder) do
103
+ trace_execution_scoped(metrics) do
117
104
  t0 = Time.now
118
105
 
119
106
  result = NewRelic::Agent.disable_all_tracing do
@@ -0,0 +1,36 @@
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
+ module Instrumentation
8
+ module SequelHelper
9
+ extend self
10
+
11
+ # Fallback if the product cannot be determined
12
+ DEFAULT_PRODUCT_NAME = "Sequel".freeze
13
+
14
+ # A Sequel adapter is called an "adapter_scheme" and can be accessed from
15
+ # the database:
16
+ #
17
+ # DB.adapter_scheme
18
+ PRODUCT_NAMES = {
19
+ :ibmdb => "IBMDB2",
20
+ :firebird => "Firebird",
21
+ :informix => "Informix",
22
+ :jdbc => "JDBC",
23
+ :mysql => "MySQL",
24
+ :mysql2 => "MySQL",
25
+ :oracle => "Oracle",
26
+ :postgres => "Postgres",
27
+ :sqlite => "SQLite"
28
+ }.freeze
29
+
30
+ def product_name_from_adapter(adapter)
31
+ PRODUCT_NAMES.fetch(adapter, DEFAULT_PRODUCT_NAME)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -301,6 +301,10 @@ module NewRelic
301
301
  http_class = Net::HTTP::Proxy(proxy_server.name, proxy_server.port,
302
302
  proxy_server.user, proxy_server.password)
303
303
 
304
+ if proxy_server.name
305
+ ::NewRelic::Agent.logger.debug("Using proxy server #{proxy_server.name}:#{proxy_server.port}")
306
+ end
307
+
304
308
  conn = http_class.new((@collector.ip || @collector.name), @collector.port)
305
309
  setup_connection_for_ssl(conn) if Agent.config[:ssl]
306
310
  setup_connection_timeouts(conn)
@@ -150,14 +150,6 @@ module NewRelic
150
150
  stats
151
151
  end
152
152
 
153
- # Returns a stat if one exists, otherwise returns nil.
154
- def lookup_stats(metric_name, scope_name = '')
155
- spec = NewRelic::MetricSpec.new(metric_name, scope_name)
156
- with_stats_lock do
157
- @stats_hash.has_key?(spec) ? @stats_hash[spec] : nil
158
- end
159
- end
160
-
161
153
  # Helper for recording a straight value into the count
162
154
  def tl_record_supportability_metric_count(metric, value)
163
155
  real_name = "Supportability/#{metric}"
@@ -233,16 +225,9 @@ module NewRelic
233
225
  NewRelic::Agent::BusyCalculator.reset
234
226
  end
235
227
 
236
- # Returns all of the metric names of all the stats in the engine.
237
228
  # For use by test code only.
238
- def metrics
239
- with_stats_lock do
240
- @stats_hash.keys.map { |spec| spec.to_s }
241
- end
242
- end
243
-
244
- def metric_specs
245
- with_stats_lock { @stats_hash.keys }
229
+ def to_h
230
+ with_stats_lock { Hash[@stats_hash] }
246
231
  end
247
232
  end
248
233
  end
@@ -9,7 +9,14 @@ module NewRelic
9
9
  ALL_TRANSACTIONS = "**ALL**".freeze
10
10
 
11
11
  def self.is_supported?
12
- RUBY_VERSION >= "1.9.2"
12
+ RUBY_VERSION >= "1.9.2" && !is_resque?
13
+ end
14
+
15
+ # Because of Resque's forking, we don't poll thread backtraces for it.
16
+ # To accomplish that would require starting a new backtracing thread in
17
+ # each forked worker, and merging profiles across the pipe channel.
18
+ def self.is_resque?
19
+ NewRelic::Agent.config[:dispatcher] == :resque
13
20
  end
14
21
 
15
22
  attr_reader :worker_loop, :buffer, :effective_polling_period,
@@ -45,6 +52,11 @@ module NewRelic
45
52
  end
46
53
 
47
54
  def subscribe(transaction_name, command_arguments={})
55
+ if self.class.is_resque?
56
+ NewRelic::Agent.logger.info("Backtracing threads on Resque is not supported, so not subscribing transaction '#{transaction_name}'")
57
+ return
58
+ end
59
+
48
60
  if !self.class.is_supported?
49
61
  NewRelic::Agent.logger.debug("Backtracing not supported, so not subscribing transaction '#{transaction_name}'")
50
62
  return
@@ -104,10 +116,11 @@ module NewRelic
104
116
  start = payload[:start_timestamp]
105
117
  duration = payload[:duration]
106
118
  thread = payload[:thread] || Thread.current
119
+ bucket = payload[:bucket]
107
120
  @lock.synchronize do
108
121
  backtraces = @buffer.delete(thread)
109
122
  if backtraces && @profiles.has_key?(name)
110
- aggregate_backtraces(backtraces, name, start, duration, thread)
123
+ aggregate_backtraces(backtraces, name, start, duration, bucket, thread)
111
124
  end
112
125
  end
113
126
  end
@@ -115,11 +128,11 @@ module NewRelic
115
128
  # Internals
116
129
 
117
130
  # This method is expected to be called with @lock held.
118
- def aggregate_backtraces(backtraces, name, start, duration, thread)
131
+ def aggregate_backtraces(backtraces, name, start, duration, bucket, thread)
119
132
  end_time = start + duration
120
133
  backtraces.each do |(timestamp, backtrace)|
121
134
  if timestamp >= start && timestamp < end_time
122
- @profiles[name].aggregate(backtrace, :request, thread)
135
+ @profiles[name].aggregate(backtrace, bucket, thread)
123
136
  end
124
137
  end
125
138
  end
@@ -169,7 +182,7 @@ module NewRelic
169
182
 
170
183
  # This method is expected to be called with @lock held.
171
184
  def should_buffer?(bucket)
172
- bucket == :request && @profiles.keys.any? { |k| k != ALL_TRANSACTIONS }
185
+ allowed_bucket?(bucket) && watching_for_transaction?
173
186
  end
174
187
 
175
188
  # This method is expected to be called with @lock held.
@@ -180,6 +193,16 @@ module NewRelic
180
193
  )
181
194
  end
182
195
 
196
+ # This method is expected to be called with @lock held
197
+ def watching_for_transaction?
198
+ @profiles.size > 1 ||
199
+ (@profiles.size == 1 && @profiles[ALL_TRANSACTIONS].nil?)
200
+ end
201
+
202
+ def allowed_bucket?(bucket)
203
+ bucket == :request || bucket == :background
204
+ end
205
+
183
206
  MAX_BUFFER_LENGTH = 500
184
207
 
185
208
  # This method is expected to be called with @lock held.
@@ -56,10 +56,6 @@ module NewRelic
56
56
  # as a Rack::Request or an ActionController::AbstractRequest.
57
57
  attr_accessor :request
58
58
 
59
- # This is the name of the model currently assigned to database
60
- # measurements, overriding the default.
61
- attr_reader :database_metric_name
62
-
63
59
  attr_reader :guid,
64
60
  :metrics,
65
61
  :gc_start_snapshot,
@@ -302,6 +298,24 @@ module NewRelic
302
298
  @ignore_enduser = false
303
299
  end
304
300
 
301
+ # This transaction-local hash may be used as temprory storage by
302
+ # instrumentation that needs to pass data from one instrumentation point
303
+ # to another.
304
+ #
305
+ # For example, if both A and B are instrumented, and A calls B
306
+ # but some piece of state needed by the instrumentation at B is only
307
+ # available at A, the instrumentation at A may write into the hash, call
308
+ # through, and then remove the key afterwards, allowing the
309
+ # instrumentation at B to read the value in between.
310
+ #
311
+ # Keys should be symbols, and care should be taken to not generate key
312
+ # names dynamically, and to ensure that keys are removed upon return from
313
+ # the method that creates them.
314
+ #
315
+ def instrumentation_state
316
+ @instrumentation_state ||= {}
317
+ end
318
+
305
319
  def noticed_error_ids
306
320
  @noticed_error_ids ||= []
307
321
  end
@@ -534,6 +548,7 @@ module NewRelic
534
548
  duration = end_time.to_f - start_time.to_f
535
549
  payload = {
536
550
  :name => @frozen_name,
551
+ :bucket => recording_web_transaction? ? :request : :background,
537
552
  :start_timestamp => start_time.to_f,
538
553
  :duration => duration,
539
554
  :metrics => @metrics,
@@ -613,9 +628,14 @@ module NewRelic
613
628
  APDEX_F = 'F'.freeze
614
629
 
615
630
  def append_apdex_perf_zone(duration, payload)
616
- return unless recording_web_transaction?
631
+ if recording_web_transaction?
632
+ bucket = apdex_bucket(duration, apdex_t)
633
+ elsif background_apdex_t = transaction_specific_apdex_t
634
+ bucket = apdex_bucket(duration, background_apdex_t)
635
+ end
636
+
637
+ return unless bucket
617
638
 
618
- bucket = apdex_bucket(duration)
619
639
  bucket_str = case bucket
620
640
  when :apdex_s then APDEX_S
621
641
  when :apdex_t then APDEX_T
@@ -708,32 +728,54 @@ module NewRelic
708
728
  end
709
729
  end
710
730
 
711
- APDEX_METRIC = 'Apdex'.freeze
731
+ APDEX_ALL_METRIC = 'ApdexAll'.freeze
732
+
733
+ APDEX_METRIC = 'Apdex'.freeze
734
+ APDEX_OTHER_METRIC = 'ApdexOther'.freeze
735
+
736
+ APDEX_TXN_METRIC_PREFIX = 'Apdex/'.freeze
737
+ APDEX_OTHER_TXN_METRIC_PREFIX = 'ApdexOther/Transaction/'.freeze
712
738
 
713
739
  def had_error?
714
- !notable_exceptions.empty?
740
+ @exceptions.each do |exception, _|
741
+ return true unless NewRelic::Agent.instance.error_collector.error_is_ignored?(exception)
742
+ end
743
+ false
715
744
  end
716
745
 
717
- def apdex_bucket(duration)
718
- self.class.apdex_bucket(duration, had_error?, apdex_t)
746
+ def apdex_bucket(duration, current_apdex_t)
747
+ self.class.apdex_bucket(duration, had_error?, current_apdex_t)
719
748
  end
720
749
 
721
750
  def record_apdex(state, end_time=Time.now)
722
- return unless recording_web_transaction? && state.is_execution_traced?
751
+ return unless state.is_execution_traced?
723
752
 
724
753
  freeze_name_and_execute_if_not_ignored do
725
- action_duration = end_time - start_time
726
754
  total_duration = end_time - apdex_start
755
+ action_duration = end_time - start_time
727
756
 
728
- apdex_bucket_global = apdex_bucket(total_duration)
729
- apdex_bucket_txn = apdex_bucket(action_duration)
730
-
731
- @metrics.record_unscoped(APDEX_METRIC, apdex_bucket_global, apdex_t)
732
- txn_apdex_metric = @frozen_name.gsub(/^[^\/]+\//, 'Apdex/')
733
- @metrics.record_unscoped(txn_apdex_metric, apdex_bucket_txn, apdex_t)
757
+ if recording_web_transaction?
758
+ record_apdex_metrics(APDEX_METRIC, APDEX_TXN_METRIC_PREFIX,
759
+ total_duration, action_duration, apdex_t)
760
+ else
761
+ record_apdex_metrics(APDEX_OTHER_METRIC, APDEX_OTHER_TXN_METRIC_PREFIX,
762
+ total_duration, action_duration, transaction_specific_apdex_t)
763
+ end
734
764
  end
735
765
  end
736
766
 
767
+ def record_apdex_metrics(rollup_metric, transaction_prefix, total_duration, action_duration, current_apdex_t)
768
+ return unless current_apdex_t
769
+
770
+ apdex_bucket_global = apdex_bucket(total_duration, current_apdex_t)
771
+ apdex_bucket_txn = apdex_bucket(action_duration, current_apdex_t)
772
+
773
+ @metrics.record_unscoped(rollup_metric, apdex_bucket_global, current_apdex_t)
774
+ @metrics.record_unscoped(APDEX_ALL_METRIC, apdex_bucket_global, current_apdex_t)
775
+ txn_apdex_metric = @frozen_name.gsub(/^[^\/]+\//, transaction_prefix)
776
+ @metrics.record_unscoped(txn_apdex_metric, apdex_bucket_txn, current_apdex_t)
777
+ end
778
+
737
779
  def apdex_t
738
780
  transaction_specific_apdex_t || Agent.config[:apdex_t]
739
781
  end
@@ -743,15 +785,8 @@ module NewRelic
743
785
  Agent.config[key] && Agent.config[key][best_name]
744
786
  end
745
787
 
746
- # Yield to a block that is run with a database metric name context. This means
747
- # the Database instrumentation will use this for the metric name if it does not
748
- # otherwise know about a model. This is re-entrant.
749
- #
750
- # * <tt>model</tt> is the DB model class
751
- # * <tt>method</tt> is the name of the finder method or other method to identify the operation with.
752
- #
753
788
  def with_database_metric_name(model, method)
754
- previous = @database_metric_name
789
+ previous = self.instrumentation_state[:datastore_override]
755
790
  model_name = case model
756
791
  when Class
757
792
  model.name
@@ -760,10 +795,10 @@ module NewRelic
760
795
  else
761
796
  model.to_s
762
797
  end
763
- @database_metric_name = "ActiveRecord/#{model_name}/#{method}"
798
+ self.instrumentation_state[:datastore_override] = [method, model_name]
764
799
  yield
765
800
  ensure
766
- @database_metric_name=previous
801
+ self.instrumentation_state[:datastore_override] = previous
767
802
  end
768
803
 
769
804
  def custom_parameters
@@ -839,12 +874,6 @@ module NewRelic
839
874
  @ignore_enduser
840
875
  end
841
876
 
842
- def notable_exceptions
843
- @exceptions.keys.select do |exception|
844
- !NewRelic::Agent.instance.error_collector.error_is_ignored?(exception)
845
- end
846
- end
847
-
848
877
  private
849
878
 
850
879
  def process_cpu