newrelic_rpm 3.6.0.83 → 3.6.1.85.beta

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. data/CHANGELOG +27 -0
  2. data/Gemfile +2 -7
  3. data/README.md +1 -1
  4. data/lib/new_relic/agent/agent.rb +3 -2
  5. data/lib/new_relic/agent/autostart.rb +56 -0
  6. data/lib/new_relic/agent/browser_monitoring.rb +19 -14
  7. data/lib/new_relic/agent/configuration/defaults.rb +12 -2
  8. data/lib/new_relic/agent/configuration/environment_source.rb +4 -1
  9. data/lib/new_relic/agent/cross_app_monitor.rb +2 -1
  10. data/lib/new_relic/agent/cross_app_tracing.rb +19 -10
  11. data/lib/new_relic/agent/error_collector.rb +5 -4
  12. data/lib/new_relic/agent/instrumentation/action_controller_subscriber.rb +204 -0
  13. data/lib/new_relic/agent/instrumentation/action_view_subscriber.rb +88 -0
  14. data/lib/new_relic/agent/instrumentation/active_record.rb +1 -1
  15. data/lib/new_relic/agent/instrumentation/active_record_helper.rb +1 -1
  16. data/lib/new_relic/agent/instrumentation/active_record_subscriber.rb +84 -0
  17. data/lib/new_relic/agent/instrumentation/browser_monitoring_timings.rb +3 -2
  18. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +104 -87
  19. data/lib/new_relic/agent/instrumentation/evented_subscriber.rb +91 -0
  20. data/lib/new_relic/agent/instrumentation/memcache.rb +4 -4
  21. data/lib/new_relic/agent/instrumentation/merb/errors.rb +4 -4
  22. data/lib/new_relic/agent/instrumentation/rack.rb +1 -1
  23. data/lib/new_relic/agent/instrumentation/rails/action_controller.rb +20 -20
  24. data/lib/new_relic/agent/instrumentation/rails/errors.rb +5 -5
  25. data/lib/new_relic/agent/instrumentation/rails3/errors.rb +3 -3
  26. data/lib/new_relic/agent/instrumentation/rails4/action_controller.rb +3 -25
  27. data/lib/new_relic/agent/instrumentation/rails4/action_view.rb +2 -115
  28. data/lib/new_relic/agent/instrumentation/rails4/active_record.rb +2 -82
  29. data/lib/new_relic/agent/instrumentation/rails4/errors.rb +3 -4
  30. data/lib/new_relic/agent/method_tracer.rb +93 -56
  31. data/lib/new_relic/agent/null_logger.rb +6 -0
  32. data/lib/new_relic/agent/samplers/cpu_sampler.rb +9 -4
  33. data/lib/new_relic/agent/sql_sampler.rb +10 -6
  34. data/lib/new_relic/agent/stats_engine/metric_stats.rb +19 -3
  35. data/lib/new_relic/agent/stats_engine/transactions.rb +53 -34
  36. data/lib/new_relic/agent/system_info.rb +54 -0
  37. data/lib/new_relic/agent/thread.rb +2 -2
  38. data/lib/new_relic/agent/transaction/pop.rb +52 -0
  39. data/lib/new_relic/agent/transaction.rb +388 -0
  40. data/lib/new_relic/agent/transaction_info.rb +5 -13
  41. data/lib/new_relic/agent/transaction_sample_builder.rb +13 -20
  42. data/lib/new_relic/agent/transaction_sampler.rb +13 -15
  43. data/lib/new_relic/agent/uri_util.rb +35 -0
  44. data/lib/new_relic/agent.rb +54 -11
  45. data/lib/new_relic/build.rb +2 -2
  46. data/lib/new_relic/control/frameworks/rails.rb +0 -1
  47. data/lib/new_relic/control/frameworks/rails3.rb +2 -0
  48. data/lib/new_relic/control/frameworks/rails4.rb +0 -4
  49. data/lib/new_relic/control/instance_methods.rb +5 -19
  50. data/lib/new_relic/control/server_methods.rb +2 -0
  51. data/lib/new_relic/environment_report.rb +4 -34
  52. data/lib/new_relic/latest_changes.rb +1 -1
  53. data/lib/new_relic/local_environment.rb +0 -6
  54. data/lib/new_relic/metric_spec.rb +2 -2
  55. data/lib/new_relic/rack/error_collector.rb +6 -4
  56. data/lib/new_relic/transaction_sample.rb +7 -1
  57. data/lib/new_relic/version.rb +1 -1
  58. data/lib/newrelic_rpm.rb +2 -2
  59. data/newrelic.yml +20 -20
  60. data/test/config/test_control.rb +2 -2
  61. data/test/multiverse/suites/agent_only/audit_log_test.rb +1 -1
  62. data/test/multiverse/suites/agent_only/cross_application_tracing_test.rb +0 -2
  63. data/test/multiverse/suites/agent_only/logging_test.rb +1 -1
  64. data/test/multiverse/suites/agent_only/marshaling_test.rb +5 -3
  65. data/test/multiverse/suites/agent_only/rename_rule_test.rb +2 -0
  66. data/test/multiverse/suites/agent_only/set_transaction_name_test.rb +96 -0
  67. data/test/multiverse/suites/agent_only/testing_app.rb +1 -0
  68. data/test/multiverse/suites/rails/error_tracing_test.rb +17 -29
  69. data/test/multiverse/suites/rails/queue_time_test.rb +8 -2
  70. data/test/multiverse/suites/rails/view_instrumentation_test.rb +6 -3
  71. data/test/multiverse/suites/resque/instrumentation_test.rb +1 -1
  72. data/test/multiverse/suites/sinatra/sinatra_error_tracing_test.rb +8 -0
  73. data/test/new_relic/agent/agent/connect_test.rb +2 -1
  74. data/test/new_relic/agent/agent/start_test.rb +0 -10
  75. data/test/new_relic/agent/agent_logger_test.rb +15 -0
  76. data/test/new_relic/agent/agent_test_controller.rb +6 -2
  77. data/test/new_relic/agent/agent_test_controller_test.rb +20 -69
  78. data/test/new_relic/agent/autostart_test.rb +67 -0
  79. data/test/new_relic/agent/browser_monitoring_test.rb +60 -38
  80. data/test/new_relic/agent/configuration/environment_source_test.rb +19 -17
  81. data/test/new_relic/agent/cross_app_monitor_test.rb +8 -0
  82. data/test/new_relic/agent/error_collector/notice_error_test.rb +0 -5
  83. data/test/new_relic/agent/error_collector_test.rb +8 -9
  84. data/test/new_relic/agent/instrumentation/action_controller_subscriber_test.rb +228 -0
  85. data/test/new_relic/agent/instrumentation/action_view_subscriber_test.rb +18 -34
  86. data/test/new_relic/agent/instrumentation/active_record_instrumentation_test.rb +5 -5
  87. data/test/new_relic/agent/instrumentation/active_record_subscriber_test.rb +8 -9
  88. data/test/new_relic/agent/instrumentation/browser_monitoring_timings_test.rb +1 -1
  89. data/test/new_relic/agent/instrumentation/controller_instrumentation_test.rb +24 -38
  90. data/test/new_relic/agent/instrumentation/net_instrumentation_test.rb +126 -178
  91. data/test/new_relic/agent/instrumentation/rack_test.rb +1 -1
  92. data/test/new_relic/agent/instrumentation/task_instrumentation_test.rb +135 -151
  93. data/test/new_relic/agent/method_tracer/instance_methods/trace_execution_scoped_test.rb +153 -81
  94. data/test/new_relic/agent/method_tracer_test.rb +42 -33
  95. data/test/new_relic/agent/mock_scope_listener.rb +4 -4
  96. data/test/new_relic/agent/pipe_channel_manager_test.rb +4 -2
  97. data/test/new_relic/agent/rpm_agent_test.rb +86 -89
  98. data/test/new_relic/agent/sql_sampler_test.rb +18 -19
  99. data/test/new_relic/agent/stats_engine/gc_profiler_test.rb +5 -8
  100. data/test/new_relic/agent/stats_engine/metric_stats_test.rb +20 -8
  101. data/test/new_relic/agent/stats_engine/samplers_test.rb +31 -14
  102. data/test/new_relic/agent/stats_engine_test.rb +53 -60
  103. data/test/new_relic/agent/thread_test.rb +7 -7
  104. data/test/new_relic/agent/transaction/pop_test.rb +96 -0
  105. data/test/new_relic/agent/transaction_info_test.rb +6 -17
  106. data/test/new_relic/agent/transaction_sample_builder_test.rb +10 -18
  107. data/test/new_relic/agent/transaction_sampler_test.rb +80 -75
  108. data/test/new_relic/agent/{instrumentation/metric_frame_test.rb → transaction_test.rb} +76 -42
  109. data/test/new_relic/agent/uri_util_test.rb +75 -0
  110. data/test/new_relic/agent_test.rb +115 -9
  111. data/test/test_helper.rb +138 -9
  112. data.tar.gz.sig +0 -0
  113. metadata +37 -74
  114. metadata.gz.sig +0 -0
  115. data/lib/new_relic/agent/instrumentation/metric_frame/pop.rb +0 -84
  116. data/lib/new_relic/agent/instrumentation/metric_frame.rb +0 -353
  117. data/test/new_relic/agent/instrumentation/metric_frame/pop_test.rb +0 -175
  118. data/test/test_contexts.rb +0 -34
@@ -0,0 +1,54 @@
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
+ # This module is intended to provide access to information about the host OS and
6
+ # [virtual] machine. It intentionally does no caching and maintains no state -
7
+ # caching should be handled by clients if needed. Methods should return nil if
8
+ # the requested information is unavailable.
9
+
10
+ require 'rbconfig'
11
+
12
+ module NewRelic
13
+ module Agent
14
+ module SystemInfo
15
+ def self.ruby_os_identifier
16
+ RbConfig::CONFIG['target_os']
17
+ end
18
+
19
+ def self.processor_count
20
+ case ruby_os_identifier
21
+ when /darwin/, /freebsd/
22
+ `sysctl -n hw.ncpu`.to_i
23
+ when /linux/
24
+ cpuinfo = ''
25
+ proc_file = '/proc/cpuinfo'
26
+ File.open(proc_file) do |f|
27
+ loop do
28
+ begin
29
+ cpuinfo << f.read_nonblock(4096).strip
30
+ rescue EOFError
31
+ break
32
+ rescue Errno::EWOULDBLOCK, Errno::EAGAIN
33
+ cpuinfo = ''
34
+ break # don't select file handle, just give up
35
+ end
36
+ end
37
+ end
38
+ processors = cpuinfo.split("\n").select {|line| line =~ /^processor\s*:/ }.size
39
+ processors == 0 ? nil : processors
40
+ end
41
+ rescue
42
+ nil
43
+ end
44
+
45
+ def self.processor_arch
46
+ RbConfig::CONFIG['target_cpu']
47
+ end
48
+
49
+ def self.os_version
50
+ `uname -v` rescue nil
51
+ end
52
+ end
53
+ end
54
+ end
@@ -15,8 +15,8 @@ module NewRelic
15
15
  def self.bucket_thread(thread, profile_agent_code)
16
16
  if thread.key?(:newrelic_label)
17
17
  return profile_agent_code ? :agent : :ignore
18
- elsif !thread[:newrelic_metric_frame].nil?
19
- thread[:newrelic_metric_frame].request.nil? ? :background : :request
18
+ elsif !thread[:newrelic_transaction].nil?
19
+ thread[:newrelic_transaction].request.nil? ? :background : :request
20
20
  else
21
21
  :other
22
22
  end
@@ -0,0 +1,52 @@
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/instrumentation'
6
+ module NewRelic
7
+ module Agent
8
+ class Transaction
9
+ module Pop
10
+ def log_underflow
11
+ ::NewRelic::Agent.logger.error "Underflow in transaction: #{caller.join("\n ")}"
12
+ end
13
+
14
+ def record_transaction_cpu
15
+ burn = cpu_burn
16
+ transaction_sampler.notice_transaction_cpu_time(burn) if burn
17
+ end
18
+
19
+ def normal_cpu_burn
20
+ return unless @process_cpu_start
21
+ process_cpu - @process_cpu_start
22
+ end
23
+
24
+ def jruby_cpu_burn
25
+ return unless @jruby_cpu_start
26
+ burn = (jruby_cpu_time - @jruby_cpu_start)
27
+ # record_jruby_cpu_burn(burn)
28
+ burn
29
+ end
30
+
31
+ # we need to do this here because the normal cpu sampler
32
+ # process doesn't work on JRuby. See the cpu_sampler.rb file
33
+ # to understand where cpu is recorded for non-jruby processes
34
+ def record_jruby_cpu_burn(burn)
35
+ NewRelic::Agent.record_metric(NewRelic::Metrics::USER_TIME, burn)
36
+ end
37
+
38
+ def cpu_burn
39
+ normal_cpu_burn || jruby_cpu_burn
40
+ end
41
+
42
+ def traced?
43
+ NewRelic::Agent.is_execution_traced?
44
+ end
45
+
46
+ def current_stack_metric
47
+ metric_name
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,388 @@
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/pop'
6
+
7
+ # A struct holding the information required to measure a controller
8
+ # action. This is put on the thread local. Handles the issue of
9
+ # re-entrancy, or nested action calls.
10
+ #
11
+ # This class is not part of the public API. Avoid making calls on it directly.
12
+ #
13
+ module NewRelic
14
+ module Agent
15
+ class Transaction
16
+ # helper module refactored out of the `pop` method
17
+ include Pop
18
+
19
+ attr_accessor :start_time # A Time instance for the start time, never nil
20
+ attr_accessor :apdex_start # A Time instance used for calculating the apdex score, which
21
+ # might end up being @start, or it might be further upstream if
22
+ # we can find a request header for the queue entry time
23
+ attr_accessor(:type, :exceptions, :filtered_params, :force_flag,
24
+ :jruby_cpu_start, :process_cpu_start, :database_metric_name)
25
+ attr_reader :name
26
+
27
+ # Give the current transaction a request context. Use this to
28
+ # get the URI and referer. The request is interpreted loosely
29
+ # as a Rack::Request or an ActionController::AbstractRequest.
30
+ attr_accessor :request
31
+
32
+
33
+ # Return the currently active transaction, or nil. Call with +true+
34
+ # to create a new transaction if one is not already on the thread.
35
+ def self.current
36
+ self.stack.last
37
+ end
38
+
39
+ def self.start(transaction_type, options={})
40
+ txn = Transaction.new(transaction_type, options)
41
+ txn.start(transaction_type)
42
+ self.stack.push(txn)
43
+ return txn
44
+ end
45
+
46
+ def self.stop(metric_name=nil)
47
+ txn = self.stack.pop
48
+ txn.stop(metric_name) if txn
49
+ return txn
50
+ end
51
+
52
+ def self.stack
53
+ Thread.current[:newrelic_transaction] ||= []
54
+ end
55
+
56
+ def self.in_transaction?
57
+ !self.stack.empty?
58
+ end
59
+
60
+ # This is the name of the model currently assigned to database
61
+ # measurements, overriding the default.
62
+ def self.database_metric_name
63
+ current && current.database_metric_name
64
+ end
65
+
66
+ def self.referer
67
+ current && current.referer
68
+ end
69
+
70
+ def self.agent
71
+ NewRelic::Agent.instance
72
+ end
73
+
74
+ def self.freeze_name
75
+ self.current && self.current.freeze_name
76
+ end
77
+
78
+ @@java_classes_loaded = false
79
+
80
+ if defined? JRuby
81
+ begin
82
+ require 'java'
83
+ java_import 'java.lang.management.ManagementFactory'
84
+ java_import 'com.sun.management.OperatingSystemMXBean'
85
+ @@java_classes_loaded = true
86
+ rescue => e
87
+ end
88
+ end
89
+
90
+ attr_reader :depth
91
+
92
+ def initialize(type=:controller, options={})
93
+ @type = type
94
+ @start_time = Time.now
95
+ @jruby_cpu_start = jruby_cpu_time
96
+ @process_cpu_start = process_cpu
97
+ @filtered_params = options[:filtered_params] || {}
98
+ @force_flag = options[:force]
99
+ @request = options[:request]
100
+ @exceptions = {}
101
+ TransactionInfo.get.transaction = self
102
+ end
103
+
104
+ def name=(name)
105
+ if !@name_frozen
106
+ @name = name
107
+ else
108
+ NewRelic::Agent.logger.warn("Attempted to rename transaction to #{name} after transaction name was already frozen.")
109
+ end
110
+ end
111
+
112
+ def freeze_name
113
+ return if name_frozen?
114
+ @name = NewRelic::Agent.instance.transaction_rules.rename(@name)
115
+ @name_frozen = true
116
+ end
117
+
118
+ def name_frozen?
119
+ @name_frozen
120
+ end
121
+
122
+ def has_parent?
123
+ self.class.stack.size > 1
124
+ end
125
+
126
+ # Indicate that we are entering a measured controller action or task.
127
+ # Make sure you unwind every push with a pop call.
128
+ def start(transaction_type)
129
+ transaction_sampler.notice_first_scope_push(start_time)
130
+ sql_sampler.notice_first_scope_push(start_time)
131
+
132
+ NewRelic::Agent::StatsEngine::GCProfiler.init
133
+ agent.stats_engine.start_transaction
134
+ agent.stats_engine.push_transaction_stats
135
+ transaction_sampler.notice_transaction(uri, filtered_params)
136
+ sql_sampler.notice_transaction(uri, filtered_params)
137
+ end
138
+
139
+ # Indicate that you don't want to keep the currently saved transaction
140
+ # information
141
+ def self.abort_transaction!
142
+ current.abort_transaction! if current
143
+ end
144
+
145
+ # For the current web transaction, return the path of the URI minus the host part and query string, or nil.
146
+ def uri
147
+ @uri ||= self.class.uri_from_request(@request) unless @request.nil?
148
+ end
149
+
150
+ # For the current web transaction, return the full referer, minus the host string, or nil.
151
+ def referer
152
+ @referer ||= self.class.referer_from_request(@request)
153
+ end
154
+
155
+ # Call this to ensure that the current transaction is not saved
156
+ def abort_transaction!
157
+ transaction_sampler.ignore_transaction
158
+ end
159
+
160
+ # Unwind one stack level. It knows if it's back at the outermost caller and
161
+ # does the appropriate wrapup of the context.
162
+ def stop(metric='(unknown)')
163
+ @name ||= metric unless name_frozen?
164
+ freeze_name
165
+ log_underflow if @type.nil?
166
+
167
+ # these record metrics so need to be done before
168
+ # the pop
169
+ if self.class.stack.empty?
170
+ # this one records metrics and wants to happen
171
+ # before the transaction sampler is finished
172
+ if traced?
173
+ record_transaction_cpu
174
+ gc_time = NewRelic::Agent::StatsEngine::GCProfiler.capture
175
+ end
176
+ @transaction_trace = transaction_sampler.notice_scope_empty(self, Time.now, gc_time)
177
+ sql_sampler.notice_scope_empty(@name)
178
+ end
179
+
180
+ record_exceptions
181
+ agent.stats_engine.pop_transaction_stats(@name)
182
+
183
+ # these tear everything down so need to be done
184
+ # after the pop
185
+ if self.class.stack.empty?
186
+ agent.stats_engine.end_transaction
187
+ end
188
+ end
189
+
190
+ def record_exceptions
191
+ @exceptions.each do |exception, options|
192
+ options[:metric] = @name
193
+ agent.error_collector.notice_error(exception, options)
194
+ end
195
+ end
196
+
197
+ # If we have an active transaction, notice the error and increment the error metric.
198
+ # Options:
199
+ # * <tt>:request</tt> => Request object to get the uri and referer
200
+ # * <tt>:uri</tt> => The request path, minus any request params or query string.
201
+ # * <tt>:referer</tt> => The URI of the referer
202
+ # * <tt>:metric</tt> => The metric name associated with the transaction
203
+ # * <tt>:request_params</tt> => Request parameters, already filtered if necessary
204
+ # * <tt>:custom_params</tt> => Custom parameters
205
+ # Anything left over is treated as custom params
206
+
207
+ def self.notice_error(e, options={})
208
+ request = options.delete(:request)
209
+ if request
210
+ options[:referer] = referer_from_request(request)
211
+ options[:uri] = uri_from_request(request)
212
+ end
213
+ if current
214
+ current.notice_error(e, options)
215
+ else
216
+ agent.error_collector.notice_error(e, options)
217
+ end
218
+ end
219
+
220
+ # Do not call this. Invoke the class method instead.
221
+ def notice_error(e, options={}) # :nodoc:
222
+ params = custom_parameters
223
+ options[:referer] = referer if referer
224
+ options[:request_params] = filtered_params if filtered_params
225
+ options[:uri] = uri if uri
226
+ options.merge!(custom_parameters)
227
+ if !@exceptions.keys.include?(e)
228
+ @exceptions[e] = options
229
+ end
230
+ end
231
+
232
+ # Add context parameters to the transaction. This information will be passed in to errors
233
+ # and transaction traces. Keys and Values should be strings, numbers or date/times.
234
+ def self.add_custom_parameters(p)
235
+ current.add_custom_parameters(p) if current
236
+ end
237
+
238
+ def self.custom_parameters
239
+ (current && current.custom_parameters) ? current.custom_parameters : {}
240
+ end
241
+
242
+ def self.set_user_attributes(attributes)
243
+ current.set_user_attributes(attributes) if current
244
+ end
245
+
246
+ def self.user_attributes
247
+ (current) ? current.user_attributes : {}
248
+ end
249
+
250
+ def record_apdex(metric_name)
251
+ return unless recording_web_transaction? && NewRelic::Agent.is_execution_traced?
252
+ metric_parser = NewRelic::MetricParser::MetricParser \
253
+ .for_metric_named(metric_name)
254
+
255
+ t = Time.now
256
+ self.class.record_apdex(metric_parser, t - start_time, t - apdex_start, exceptions.any?)
257
+ end
258
+
259
+ # Yield to a block that is run with a database metric name context. This means
260
+ # the Database instrumentation will use this for the metric name if it does not
261
+ # otherwise know about a model. This is re-entrant.
262
+ #
263
+ # * <tt>model</tt> is the DB model class
264
+ # * <tt>method</tt> is the name of the finder method or other method to identify the operation with.
265
+ #
266
+ def with_database_metric_name(model, method)
267
+ previous = @database_metric_name
268
+ model_name = case model
269
+ when Class
270
+ model.name
271
+ when String
272
+ model
273
+ else
274
+ model.to_s
275
+ end
276
+ @database_metric_name = "ActiveRecord/#{model_name}/#{method}"
277
+ yield
278
+ ensure
279
+ @database_metric_name=previous
280
+ end
281
+
282
+ def custom_parameters
283
+ @custom_parameters ||= {}
284
+ end
285
+
286
+ def user_attributes
287
+ @user_atrributes ||= {}
288
+ end
289
+
290
+ def queue_time
291
+ @apdex_start ? @start_time - @apdex_start : 0
292
+ end
293
+
294
+ def add_custom_parameters(p)
295
+ custom_parameters.merge!(p)
296
+ end
297
+
298
+ def set_user_attributes(attributes)
299
+ user_attributes.merge!(attributes)
300
+ end
301
+
302
+ def self.recording_web_transaction?
303
+ self.current && self.current.recording_web_transaction?
304
+ end
305
+
306
+ def recording_web_transaction?
307
+ [:controller, :uri, :rack, :sinatra].include?(@type)
308
+ end
309
+
310
+ # Make a safe attempt to get the referer from a request object, generally successful when
311
+ # it's a Rack request.
312
+ def self.referer_from_request(request)
313
+ if request && request.respond_to?(:referer)
314
+ request.referer.to_s.split('?').first
315
+ end
316
+ end
317
+
318
+ # Make a safe attempt to get the URI, without the host and query string.
319
+ def self.uri_from_request(request)
320
+ approximate_uri = case
321
+ when request.respond_to?(:fullpath) then request.fullpath
322
+ when request.respond_to?(:path) then request.path
323
+ when request.respond_to?(:request_uri) then request.request_uri
324
+ when request.respond_to?(:uri) then request.uri
325
+ when request.respond_to?(:url) then request.url
326
+ end
327
+ return approximate_uri[%r{^(https?://.*?)?(/[^?]*)}, 2] || '/' if approximate_uri # '
328
+ end
329
+
330
+ def self.record_apdex(current_metric, action_duration, total_duration, is_error)
331
+ agent.stats_engine.record_metrics('Apdex') do |stat|
332
+ update_apdex(stat, total_duration, is_error)
333
+ end
334
+ agent.stats_engine.record_metrics(current_metric.apdex_metric_path) do |stat|
335
+ update_apdex(stat, action_duration, is_error)
336
+ end
337
+ end
338
+
339
+ # Record an apdex value for the given stat. when `failed`
340
+ # the apdex should be recorded as a failure regardless of duration.
341
+ def self.update_apdex(stat, duration, failed)
342
+ apdex_t = TransactionInfo.get.apdex_t
343
+ duration = duration.to_f
344
+ case
345
+ when failed
346
+ stat.record_apdex_f
347
+ when duration <= apdex_t
348
+ stat.record_apdex_s
349
+ when duration <= 4 * apdex_t
350
+ stat.record_apdex_t
351
+ else
352
+ stat.record_apdex_f
353
+ end
354
+ # Apdex min and max values should be initialized to the
355
+ # current apdex_t
356
+ stat.min_call_time = apdex_t
357
+ stat.max_call_time = apdex_t
358
+ end
359
+
360
+ private
361
+
362
+ def process_cpu
363
+ return nil if defined? JRuby
364
+ p = Process.times
365
+ p.stime + p.utime
366
+ end
367
+
368
+ def jruby_cpu_time # :nodoc:
369
+ return nil unless @@java_classes_loaded
370
+ threadMBean = ManagementFactory.getThreadMXBean()
371
+ java_utime = threadMBean.getCurrentThreadUserTime() # ns
372
+ -1 == java_utime ? 0.0 : java_utime/1e9
373
+ end
374
+
375
+ def agent
376
+ NewRelic::Agent.instance
377
+ end
378
+
379
+ def transaction_sampler
380
+ agent.transaction_sampler
381
+ end
382
+
383
+ def sql_sampler
384
+ agent.sql_sampler
385
+ end
386
+ end
387
+ end
388
+ end
@@ -7,25 +7,15 @@ require 'erb'
7
7
  module NewRelic
8
8
  module Agent
9
9
  class TransactionInfo
10
- DEFAULT_TRANSACTION_NAME = '(unknown)'
11
10
 
12
- attr_accessor :token, :capture_deep_tt
13
- attr_writer :transaction_name
11
+ attr_accessor :token, :capture_deep_tt, :request, :transaction
14
12
  attr_reader :start_time
15
13
 
16
14
  def initialize
17
15
  @guid = ""
18
- @transaction_name = nil
19
16
  @start_time = Time.now
20
17
  @ignore_end_user = false
21
- end
22
-
23
- def transaction_name_set?
24
- !@transaction_name.nil?
25
- end
26
-
27
- def transaction_name
28
- @transaction_name || DEFAULT_TRANSACTION_NAME
18
+ @transaction = Transaction.current
29
19
  end
30
20
 
31
21
  def force_persist_sample?(sample)
@@ -58,7 +48,7 @@ module NewRelic
58
48
 
59
49
  def apdex_t
60
50
  (Agent.config[:web_transactions_apdex] &&
61
- Agent.config[:web_transactions_apdex][@transaction_name]) ||
51
+ Agent.config[:web_transactions_apdex][@transaction.name]) ||
62
52
  Agent.config[:apdex_t]
63
53
  end
64
54
 
@@ -89,6 +79,8 @@ module NewRelic
89
79
  clear
90
80
  instance = get
91
81
  instance.token = get_token(request)
82
+ instance.request = request
83
+ instance.transaction = Transaction.current
92
84
  end
93
85
 
94
86
  def self.get_token(request)
@@ -5,7 +5,7 @@
5
5
  require 'new_relic/collection_helper'
6
6
  require 'new_relic/transaction_sample'
7
7
  require 'new_relic/control'
8
- require 'new_relic/agent/instrumentation/metric_frame'
8
+ require 'new_relic/agent/transaction'
9
9
  module NewRelic
10
10
  module Agent
11
11
  # a builder is created with every sampled transaction, to dynamically
@@ -27,20 +27,20 @@ module NewRelic
27
27
  end
28
28
 
29
29
  def ignored?
30
- @ignore || @sample.params[:path].nil?
30
+ @ignore
31
31
  end
32
32
 
33
33
  def ignore_transaction
34
34
  @ignore = true
35
35
  end
36
-
36
+
37
37
  def segment_limit
38
38
  Agent.config[:'transaction_tracer.limit_segments']
39
39
  end
40
40
 
41
- def trace_entry(metric_name, time)
41
+ def trace_entry(time)
42
42
  if @sample.count_segments < segment_limit()
43
- segment = @sample.create_segment(time.to_f - @sample_start, metric_name)
43
+ segment = @sample.create_segment(time.to_f - @sample_start)
44
44
  @current_segment.add_called_segment(segment)
45
45
  @current_segment = segment
46
46
  if @sample.count_segments == segment_limit()
@@ -52,14 +52,12 @@ module NewRelic
52
52
 
53
53
  def trace_exit(metric_name, time)
54
54
  return unless @sample.count_segments < segment_limit()
55
- if metric_name != @current_segment.metric_name
56
- fail "unbalanced entry/exit: #{metric_name} != #{@current_segment.metric_name}"
57
- end
55
+ @current_segment.metric_name = metric_name
58
56
  @current_segment.end_trace(time.to_f - @sample_start)
59
57
  @current_segment = @current_segment.parent_segment
60
58
  end
61
59
 
62
- def finish_trace(time=Time.now.to_f)
60
+ def finish_trace(time=Time.now.to_f, custom_params={})
63
61
  # This should never get called twice, but in a rare case that we can't reproduce in house it does.
64
62
  # log forensics and return gracefully
65
63
  if @sample.frozen?
@@ -68,7 +66,7 @@ module NewRelic
68
66
  end
69
67
  @sample.root_segment.end_trace(time.to_f - @sample_start)
70
68
  @sample.params[:custom_params] ||= {}
71
- @sample.params[:custom_params].merge!(normalize_params(NewRelic::Agent::Instrumentation::MetricFrame.custom_parameters))
69
+ @sample.params[:custom_params].merge!(normalize_params(custom_params))
72
70
 
73
71
  txn_info = NewRelic::Agent::TransactionInfo.get
74
72
  @sample.force_persist = txn_info.force_persist_sample?(sample)
@@ -97,9 +95,7 @@ module NewRelic
97
95
  @sample.profile = profile
98
96
  end
99
97
 
100
- def set_transaction_info(path, uri, params)
101
- @sample.params[:path] = path
102
-
98
+ def set_transaction_info(uri, params)
103
99
  if Agent.config[:capture_params]
104
100
  params = normalize_params params
105
101
 
@@ -110,15 +106,12 @@ module NewRelic
110
106
  @sample.params[:uri] ||= uri || params[:uri]
111
107
  end
112
108
 
113
- def set_transaction_cpu_time(cpu_time)
114
- @sample.params[:custom_params] ||= {}
115
- @sample.params[:custom_params][:cpu_time] = cpu_time
109
+ def set_transaction_name(name)
110
+ @sample.params[:path] = name
116
111
  end
117
112
 
118
- # Set the metric name of the current segment to +new_name+ if
119
- def rename_current_segment( new_name )
120
- return unless @sample.count_segments < segment_limit()
121
- @current_segment.metric_name = new_name
113
+ def set_transaction_cpu_time(cpu_time)
114
+ @sample.set_custom_param(:cpu_time, cpu_time)
122
115
  end
123
116
 
124
117
  def sample