newrelic_rpm 2.8.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of newrelic_rpm might be problematic. Click here for more details.

Files changed (107) hide show
  1. data/LICENSE +37 -0
  2. data/README +93 -0
  3. data/Rakefile +38 -0
  4. data/install.rb +37 -0
  5. data/lib/new_relic/agent.rb +26 -0
  6. data/lib/new_relic/agent/agent.rb +762 -0
  7. data/lib/new_relic/agent/chained_call.rb +13 -0
  8. data/lib/new_relic/agent/collection_helper.rb +81 -0
  9. data/lib/new_relic/agent/error_collector.rb +105 -0
  10. data/lib/new_relic/agent/instrumentation/active_record_instrumentation.rb +95 -0
  11. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +151 -0
  12. data/lib/new_relic/agent/instrumentation/data_mapper.rb +90 -0
  13. data/lib/new_relic/agent/instrumentation/dispatcher_instrumentation.rb +105 -0
  14. data/lib/new_relic/agent/instrumentation/memcache.rb +18 -0
  15. data/lib/new_relic/agent/instrumentation/merb/controller.rb +17 -0
  16. data/lib/new_relic/agent/instrumentation/merb/dispatcher.rb +15 -0
  17. data/lib/new_relic/agent/instrumentation/merb/errors.rb +6 -0
  18. data/lib/new_relic/agent/instrumentation/rails/action_controller.rb +35 -0
  19. data/lib/new_relic/agent/instrumentation/rails/action_web_service.rb +27 -0
  20. data/lib/new_relic/agent/instrumentation/rails/dispatcher.rb +30 -0
  21. data/lib/new_relic/agent/instrumentation/rails/errors.rb +23 -0
  22. data/lib/new_relic/agent/instrumentation/rails/rails.rb +6 -0
  23. data/lib/new_relic/agent/method_tracer.rb +171 -0
  24. data/lib/new_relic/agent/patch_const_missing.rb +31 -0
  25. data/lib/new_relic/agent/samplers/cpu.rb +29 -0
  26. data/lib/new_relic/agent/samplers/memory.rb +55 -0
  27. data/lib/new_relic/agent/samplers/mongrel.rb +26 -0
  28. data/lib/new_relic/agent/stats_engine.rb +241 -0
  29. data/lib/new_relic/agent/synchronize.rb +40 -0
  30. data/lib/new_relic/agent/transaction_sampler.rb +281 -0
  31. data/lib/new_relic/agent/worker_loop.rb +128 -0
  32. data/lib/new_relic/api/deployments.rb +92 -0
  33. data/lib/new_relic/config.rb +194 -0
  34. data/lib/new_relic/config/merb.rb +35 -0
  35. data/lib/new_relic/config/rails.rb +113 -0
  36. data/lib/new_relic/config/ruby.rb +9 -0
  37. data/lib/new_relic/local_environment.rb +108 -0
  38. data/lib/new_relic/merbtasks.rb +6 -0
  39. data/lib/new_relic/metric_data.rb +26 -0
  40. data/lib/new_relic/metric_spec.rb +39 -0
  41. data/lib/new_relic/metrics.rb +7 -0
  42. data/lib/new_relic/noticed_error.rb +21 -0
  43. data/lib/new_relic/shim_agent.rb +95 -0
  44. data/lib/new_relic/stats.rb +359 -0
  45. data/lib/new_relic/transaction_analysis.rb +122 -0
  46. data/lib/new_relic/transaction_sample.rb +499 -0
  47. data/lib/new_relic/version.rb +111 -0
  48. data/lib/new_relic_api.rb +275 -0
  49. data/lib/newrelic_rpm.rb +27 -0
  50. data/lib/tasks/agent_tests.rake +14 -0
  51. data/lib/tasks/all.rb +4 -0
  52. data/lib/tasks/install.rake +7 -0
  53. data/newrelic.yml +137 -0
  54. data/recipes/newrelic.rb +46 -0
  55. data/test/config/newrelic.yml +26 -0
  56. data/test/config/test_config.rb +9 -0
  57. data/test/new_relic/agent/mock_ar_connection.rb +40 -0
  58. data/test/new_relic/agent/mock_scope_listener.rb +23 -0
  59. data/test/new_relic/agent/model_fixture.rb +17 -0
  60. data/test/new_relic/agent/tc_active_record.rb +91 -0
  61. data/test/new_relic/agent/tc_agent.rb +112 -0
  62. data/test/new_relic/agent/tc_collection_helper.rb +104 -0
  63. data/test/new_relic/agent/tc_controller.rb +98 -0
  64. data/test/new_relic/agent/tc_dispatcher_instrumentation.rb +52 -0
  65. data/test/new_relic/agent/tc_error_collector.rb +127 -0
  66. data/test/new_relic/agent/tc_method_tracer.rb +306 -0
  67. data/test/new_relic/agent/tc_stats_engine.rb +218 -0
  68. data/test/new_relic/agent/tc_synchronize.rb +37 -0
  69. data/test/new_relic/agent/tc_transaction_sample.rb +175 -0
  70. data/test/new_relic/agent/tc_transaction_sample_builder.rb +200 -0
  71. data/test/new_relic/agent/tc_transaction_sampler.rb +305 -0
  72. data/test/new_relic/agent/tc_worker_loop.rb +101 -0
  73. data/test/new_relic/agent/testable_agent.rb +13 -0
  74. data/test/new_relic/tc_config.rb +36 -0
  75. data/test/new_relic/tc_deployments_api.rb +37 -0
  76. data/test/new_relic/tc_environment.rb +94 -0
  77. data/test/new_relic/tc_metric_spec.rb +150 -0
  78. data/test/new_relic/tc_shim_agent.rb +9 -0
  79. data/test/new_relic/tc_stats.rb +141 -0
  80. data/test/test_helper.rb +39 -0
  81. data/test/ui/tc_newrelic_helper.rb +44 -0
  82. data/ui/controllers/newrelic_controller.rb +200 -0
  83. data/ui/helpers/google_pie_chart.rb +55 -0
  84. data/ui/helpers/newrelic_helper.rb +286 -0
  85. data/ui/views/layouts/newrelic_default.rhtml +49 -0
  86. data/ui/views/newrelic/_explain_plans.rhtml +27 -0
  87. data/ui/views/newrelic/_sample.rhtml +12 -0
  88. data/ui/views/newrelic/_segment.rhtml +28 -0
  89. data/ui/views/newrelic/_segment_row.rhtml +14 -0
  90. data/ui/views/newrelic/_show_sample_detail.rhtml +22 -0
  91. data/ui/views/newrelic/_show_sample_sql.rhtml +19 -0
  92. data/ui/views/newrelic/_show_sample_summary.rhtml +3 -0
  93. data/ui/views/newrelic/_sql_row.rhtml +11 -0
  94. data/ui/views/newrelic/_stack_trace.rhtml +30 -0
  95. data/ui/views/newrelic/_table.rhtml +12 -0
  96. data/ui/views/newrelic/explain_sql.rhtml +45 -0
  97. data/ui/views/newrelic/images/arrow-close.png +0 -0
  98. data/ui/views/newrelic/images/arrow-open.png +0 -0
  99. data/ui/views/newrelic/images/blue_bar.gif +0 -0
  100. data/ui/views/newrelic/images/gray_bar.gif +0 -0
  101. data/ui/views/newrelic/index.rhtml +37 -0
  102. data/ui/views/newrelic/javascript/transaction_sample.js +107 -0
  103. data/ui/views/newrelic/sample_not_found.rhtml +2 -0
  104. data/ui/views/newrelic/show_sample.rhtml +62 -0
  105. data/ui/views/newrelic/show_source.rhtml +3 -0
  106. data/ui/views/newrelic/stylesheets/style.css +394 -0
  107. metadata +180 -0
@@ -0,0 +1,13 @@
1
+ # This is used to allow obfuscators to be chained.
2
+
3
+ class NewRelic::ChainedCall
4
+ def initialize(block1, block2)
5
+ @block1 = block1
6
+ @block2 = block2
7
+ end
8
+
9
+ def call(sql)
10
+ sql = @block1.call(sql)
11
+ @block2.call(sql)
12
+ end
13
+ end
@@ -0,0 +1,81 @@
1
+ module NewRelic::Agent::CollectionHelper
2
+ # Transform parameter hash into a hash whose values are strictly
3
+ # strings
4
+ def normalize_params(params)
5
+ case params
6
+ when Symbol, FalseClass, TrueClass, nil:
7
+ params
8
+ when Numeric
9
+ truncate(params.to_s)
10
+ when String
11
+ truncate(params)
12
+ when Hash:
13
+ new_params = {}
14
+ params.each do | key, value |
15
+ new_params[truncate(normalize_params(key),32)] = normalize_params(value)
16
+ end
17
+ new_params
18
+ when Enumerable:
19
+ # We only want the first 20 values of any enumerable. Invoking to_a.first(20) works but
20
+ # the to_a call might be expensive, so we'll just build it manually, even though it's
21
+ # more verbose.
22
+ new_values = []
23
+ count = 1
24
+ params.each do | item |
25
+ new_values << normalize_params(item)
26
+ break if (count += 1) > 20
27
+ end
28
+ new_values
29
+ else
30
+ truncate(flatten(params))
31
+ end
32
+ end
33
+
34
+ # Return an array of strings (backtrace), cleaned up for readability
35
+ # Return nil if there is no backtrace
36
+
37
+ def strip_nr_from_backtrace(backtrace)
38
+ if backtrace
39
+ # strip newrelic from the trace
40
+ backtrace = backtrace.reject {|line| line =~ /new_relic\/agent\// }
41
+ # rename methods back to their original state
42
+ backtrace = backtrace.collect {|line| line.gsub /_without_(newrelic|trace)/, ""}
43
+ end
44
+ backtrace
45
+ end
46
+
47
+ private
48
+
49
+ # Convert any kind of object to a descriptive string
50
+ # Only call this on unknown objects. Otherwise call to_s.
51
+ def flatten(object)
52
+ s =
53
+ if object.respond_to? :inspect
54
+ object.inspect
55
+ elsif object.respond_to? :to_s
56
+ object.to_s
57
+ elsif object.nil?
58
+ "nil"
59
+ else
60
+ "#<#{object.class.to_s}>"
61
+ end
62
+
63
+ if !(s.instance_of? String)
64
+ s = "#<#{object.class.to_s}>"
65
+ end
66
+
67
+ s
68
+ end
69
+
70
+ def truncate(string, len=256)
71
+ if string.instance_of? Symbol
72
+ string
73
+ elsif string.nil?
74
+ ""
75
+ elsif string.instance_of? String
76
+ string.to_s.gsub(/^(.{#{len}})(.*)/) {$2.blank? ? $1 : $1 + "..."}
77
+ else
78
+ truncate(flatten(string), len)
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,105 @@
1
+
2
+ module NewRelic::Agent
3
+ class ErrorCollector
4
+ include Synchronize
5
+ include CollectionHelper
6
+
7
+ MAX_ERROR_QUEUE_LENGTH = 20 unless defined? MAX_ERROR_QUEUE_LENGTH
8
+
9
+ attr_accessor :capture_params
10
+ attr_accessor :capture_source
11
+ attr_accessor :enabled
12
+
13
+ def initialize(agent = nil)
14
+ @agent = agent
15
+ @errors = []
16
+ # lookup of exception class names to ignore. Hash for fast access
17
+ @ignore = {}
18
+ @ignore_filter = nil
19
+ @capture_params = true
20
+ @capture_source = false
21
+ @enabled = true
22
+ end
23
+
24
+ def ignore_error_filter(&block)
25
+ @ignore_filter = block
26
+ end
27
+
28
+
29
+ # errors is an array of Exception Class Names
30
+ #
31
+ def ignore(errors)
32
+ errors.each { |error| @ignore[error] = true; log.debug("Ignoring error: '#{error}'") }
33
+ end
34
+
35
+
36
+ def notice_error(path, request_uri, params, exception)
37
+
38
+ return unless @enabled
39
+ return if @ignore[exception.class.name]
40
+
41
+ if @ignore_filter
42
+ exception = @ignore_filter.call(exception)
43
+
44
+ return if exception.nil?
45
+ end
46
+
47
+ error_stat.increment_count
48
+
49
+ data = {}
50
+
51
+ data[:request_params] = normalize_params(params) if @capture_params
52
+ data[:custom_params] = normalize_params(@agent.custom_params) if @agent
53
+
54
+ data[:request_uri] = request_uri
55
+
56
+ data[:rails_root] = NewRelic::Config.instance.root
57
+
58
+ data[:file_name] = exception.file_name if exception.respond_to?('file_name')
59
+ data[:line_number] = exception.line_number if exception.respond_to?('line_number')
60
+
61
+ if @capture_source && exception.respond_to?('source_extract')
62
+ data[:source] = exception.source_extract
63
+ end
64
+
65
+ if exception.respond_to? 'original_exception'
66
+ inside_exception = exception.original_exception
67
+ else
68
+ inside_exception = exception
69
+ end
70
+ data[:stack_trace] = strip_nr_from_backtrace(inside_exception.backtrace)
71
+ noticed_error = NewRelic::NoticedError.new(path, data, exception)
72
+
73
+ synchronize do
74
+ if @errors.length >= MAX_ERROR_QUEUE_LENGTH
75
+ log.info("The error reporting queue has reached #{MAX_ERROR_QUEUE_LENGTH}. This error will not be reported to RPM: #{exception.message}")
76
+ else
77
+ @errors << noticed_error
78
+ end
79
+ end
80
+ end
81
+
82
+ # Get the errors currently queued up. Unsent errors are left
83
+ # over from a previous unsuccessful attempt to send them to the server.
84
+ # We first clear out all unsent errors before sending the newly queued errors.
85
+ def harvest_errors(unsent_errors)
86
+ if unsent_errors && !unsent_errors.empty?
87
+ return unsent_errors
88
+ else
89
+ synchronize do
90
+ errors = @errors
91
+ @errors = []
92
+ return errors
93
+ end
94
+ end
95
+ end
96
+
97
+ private
98
+ def error_stat
99
+ @error_stat ||= NewRelic::Agent.get_stats("Errors/all")
100
+ end
101
+ def log
102
+ NewRelic::Config.instance.log
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,95 @@
1
+
2
+ # NewRelic instrumentation for ActiveRecord
3
+ if defined? ActiveRecord
4
+
5
+ ActiveRecord::Base.class_eval do
6
+ class << self
7
+ [:find_by_sql, :count].each do |find_method|
8
+ add_method_tracer find_method, 'ActiveRecord/#{self.name}/find'
9
+ add_method_tracer find_method, 'ActiveRecord/find', :push_scope => false
10
+ add_method_tracer find_method, 'ActiveRecord/all', :push_scope => false
11
+ end
12
+ end
13
+ [:save, :save!].each do |save_method|
14
+ add_method_tracer save_method, 'ActiveRecord/#{self.class.name}/save'
15
+ add_method_tracer save_method, 'ActiveRecord/save', :push_scope => false
16
+ add_method_tracer save_method, 'ActiveRecord/all', :push_scope => false
17
+ end
18
+
19
+ add_method_tracer :destroy, 'ActiveRecord/#{self.class.name}/destroy'
20
+ add_method_tracer :destroy, 'ActiveRecord/destroy', :push_scope => false
21
+ add_method_tracer :destroy, 'ActiveRecord/all', :push_scope => false
22
+ end
23
+
24
+ # instrumentation to catch logged SQL statements in sampled transactions
25
+
26
+ ActiveRecord::ConnectionAdapters::AbstractAdapter.class_eval do
27
+ @@my_sql_defined = defined? ActiveRecord::ConnectionAdapters::MysqlAdapter
28
+ @@postgres_defined = defined? ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
29
+
30
+ def log_with_newrelic_instrumentation(sql, name, &block)
31
+ # if we aren't in a blamed context, then add one so that we can see that
32
+ # controllers are calling SQL directly
33
+ # we check scope_depth vs 2 since the controller is 1, and the
34
+ #
35
+ if NewRelic::Agent.instance.transaction_sampler.scope_depth < 2
36
+ self.class.trace_method_execution_with_scope "Database/DirectSQL", true, true do
37
+ log_with_capture_sql(sql, name, &block)
38
+ end
39
+ else
40
+ log_with_capture_sql(sql, name, &block)
41
+ end
42
+ end
43
+
44
+ def log_with_capture_sql(sql, name, &block)
45
+ if @@my_sql_defined && self.is_a?(ActiveRecord::ConnectionAdapters::MysqlAdapter)
46
+ config = @config
47
+ elsif @@postgres_defined && self.is_a?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
48
+ config = @config
49
+ else
50
+ config = nil
51
+ end
52
+
53
+ t0 = Time.now
54
+ result = log_without_newrelic_instrumentation(sql, name, &block)
55
+
56
+ NewRelic::Agent.instance.transaction_sampler.notice_sql(sql, config, Time.now - t0)
57
+
58
+ result
59
+ end
60
+
61
+ # Compare with #alias_method_chain, which is not available in
62
+ # Rails 1.1:
63
+ alias_method :log_without_newrelic_instrumentation, :log
64
+ alias_method :log, :log_with_newrelic_instrumentation
65
+ protected :log
66
+
67
+ add_method_tracer :log, 'Database/#{adapter_name}/#{args[1]}', :metric => false
68
+ add_method_tracer :log, 'Database/all', :push_scope => false
69
+
70
+ end
71
+ ActiveRecord::Associations::ClassMethods.class_eval do
72
+ add_method_tracer :find_with_associations, 'ActiveRecord/#{self.name}/find'
73
+ add_method_tracer :find_with_associations, 'ActiveRecord/find', :push_scope => false
74
+ add_method_tracer :find_with_associations, 'ActiveRecord/all', :push_scope => false
75
+ end
76
+
77
+ # instrumentation for associations
78
+ ActiveRecord::Associations::AssociationCollection.class_eval do
79
+ add_method_tracer :delete, 'ActiveRecord/#{@owner.class.name}/association delete'
80
+ end
81
+ =begin
82
+ # Consider enabling these in the future
83
+ class HasAndBelongsToManyAssociation
84
+ add_method_tracer :find, 'ActiveRecord/#{@owner.class.name}/association find'
85
+ add_method_tracer :create_record, 'ActiveRecord/#{@owner.class.name}/association create'
86
+ add_method_tracer :insert_record, 'ActiveRecord/#{@owner.class.name}/association insert'
87
+ end
88
+
89
+ class HasManyAssociation
90
+ add_method_tracer :find, 'ActiveRecord/#{@owner.class.name}/association find'
91
+ add_method_tracer :insert_record, 'ActiveRecord/#{@owner.class.name}/association insert'
92
+ add_method_tracer :create_record, 'ActiveRecord/#{@owner.class.name}/association create'
93
+ end
94
+ =end
95
+ end
@@ -0,0 +1,151 @@
1
+ # NewRelic instrumentation for controllers
2
+ #
3
+ # This instrumentation is applied to the action controller by default if the agent
4
+ # is actively collecting statistics. It will collect statistics for the
5
+ # given action.
6
+ #
7
+ # In cases where you don't want to instrument the top level action, but instead
8
+ # have other methods which are dispatched to by your action, and you want to treat
9
+ # these as distinct actions, then what you need to do is call newrelic_ignore
10
+ # on the top level action, and manually instrument the called 'actions'.
11
+ #
12
+ # Here's an example of a controller with a send_message action which dispatches
13
+ # to more specific send_servicename methods. This results in the controller
14
+ # action stats showing up for send_servicename.
15
+ #
16
+ # MyController < ActionController::Base
17
+ # newrelic_ignore :only => 'send_message'
18
+ # # dispatch this action to the method given by the service parameter.
19
+ # def send_message
20
+ # service = params['service']
21
+ # dispatch_to_method = "send_messge_to_#{service}"
22
+ # perform_action_with_newrelic_trace(dispatch_to_method) do
23
+ # send dispatch_to_method, params['message']
24
+ # end
25
+ # end
26
+ # end
27
+
28
+ module NewRelic::Agent::Instrumentation
29
+ module ControllerInstrumentation
30
+
31
+ @@newrelic_apdex_t = NewRelic::Agent.instance.apdex_t
32
+ @@newrelic_apdex_overall = NewRelic::Agent.instance.stats_engine.get_stats_no_scope("Apdex")
33
+ def self.included(clazz)
34
+ clazz.extend(ClassMethods)
35
+ end
36
+
37
+ module ClassMethods
38
+ # Have NewRelic ignore actions in this controller. Specify the actions as hash options
39
+ # using :except and :only. If no actions are specified, all actions are ignored.
40
+ def newrelic_ignore(specifiers={})
41
+ if specifiers.empty?
42
+ self.newrelic_ignore_attr = true
43
+ elsif ! (Hash === specifiers)
44
+ logger.error "newrelic_ignore takes an optional hash with :only and :except lists of actions (illegal argument type '#{specifiers.class}')"
45
+ else
46
+ self.newrelic_ignore_attr = specifiers
47
+ end
48
+ end
49
+ # Should be implemented in the controller class via the inheritable attribute mechanism.
50
+ def newrelic_ignore_attr=(value); end
51
+ def newrelic_ignore_attr; end
52
+ end
53
+
54
+ # Must be implemented in the controller class:
55
+ # Determine the path that is used in the metric name for
56
+ # the called controller action. Of the form controller_path/action_name
57
+ #
58
+ def newrelic_metric_path(action_name_override = nil)
59
+ raise "Not implemented!"
60
+ end
61
+
62
+ @@newrelic_apdex_t = NewRelic::Agent.instance.apdex_t
63
+ # Perform the current action with NewRelic tracing. Used in a method
64
+ # chain via aliasing. Call directly if you want to instrument a specifc
65
+ # block as if it were an action. Pass the block along with the path.
66
+ # The metric is named according to the action name, or the given path if called
67
+ # directly.
68
+ def perform_action_with_newrelic_trace(*args)
69
+ agent = NewRelic::Agent.instance
70
+ stats_engine = agent.stats_engine
71
+
72
+ ignore_actions = self.class.newrelic_ignore_attr
73
+ # Skip instrumentation based on the value of 'do_not_trace' and if
74
+ # we aren't calling directly with a block.
75
+ should_skip = !block_given? && case ignore_actions
76
+ when nil: false
77
+ when Hash
78
+ only_actions = Array(ignore_actions[:only])
79
+ except_actions = Array(ignore_actions[:except])
80
+ only_actions.include?(action_name.to_sym) || (except_actions.any? && !except_actions.include?(action_name.to_sym))
81
+ else
82
+ true
83
+ end
84
+ if should_skip
85
+ begin
86
+ return perform_action_without_newrelic_trace(*args)
87
+ ensure
88
+ # Tell the dispatcher instrumentation that we ignored this action and it shouldn't
89
+ # be counted for the overall HTTP operations measurement. The if.. appears here
90
+ # because we might be ignoring the top level action instrumenting but instrumenting
91
+ # a direct invocation that already happened, so we need to make sure if this var
92
+ # has already been set to false we don't reset it.
93
+ Thread.current[:controller_ignored] = true if Thread.current[:controller_ignored].nil?
94
+ end
95
+ end
96
+
97
+ Thread.current[:controller_ignored] = false
98
+
99
+ start = Time.now.to_f
100
+ agent.ensure_worker_thread_started
101
+
102
+ # generate metrics for all all controllers (no scope)
103
+ self.class.trace_method_execution_no_scope "Controller" do
104
+ # generate metrics for this specific action
105
+ # assuming the first argument, if present, is the action name
106
+ path = newrelic_metric_path(args.size > 0 ? args[0] : nil)
107
+ stats_engine.transaction_name ||= "Controller/#{path}" if stats_engine
108
+
109
+ self.class.trace_method_execution_with_scope "Controller/#{path}", true, true do
110
+ # send request and parameter info to the transaction sampler
111
+
112
+ local_params = (respond_to? :filter_parameters) ? filter_parameters(params) : params
113
+
114
+ agent.transaction_sampler.notice_transaction(path, request, local_params)
115
+
116
+ t = Process.times.utime + Process.times.stime
117
+
118
+ begin
119
+ # run the action
120
+ if block_given?
121
+ yield
122
+ else
123
+ perform_action_without_newrelic_trace(*args)
124
+ end
125
+ ensure
126
+ cpu_burn = (Process.times.utime + Process.times.stime) - t
127
+ agent.transaction_sampler.notice_transaction_cpu_time(cpu_burn)
128
+
129
+ duration = Time.now.to_f - start
130
+ # do the apdex bucketing
131
+ if duration <= @@newrelic_apdex_t
132
+ @@newrelic_apdex_overall.record_apdex_s cpu_burn # satisfied
133
+ stats_engine.get_stats_no_scope("Apdex/#{path}").record_apdex_s cpu_burn
134
+ elsif duration <= (4 * @@newrelic_apdex_t)
135
+ @@newrelic_apdex_overall.record_apdex_t cpu_burn # tolerating
136
+ stats_engine.get_stats_no_scope("Apdex/#{path}").record_apdex_t cpu_burn
137
+ else
138
+ @@newrelic_apdex_overall.record_apdex_f cpu_burn # frustrated
139
+ stats_engine.get_stats_no_scope("Apdex/#{path}").record_apdex_f cpu_burn
140
+ end
141
+
142
+ end
143
+ end
144
+ end
145
+
146
+ ensure
147
+ # clear out the name of the traced transaction under all circumstances
148
+ stats_engine.transaction_name = nil
149
+ end
150
+ end
151
+ end