Class: NewRelic::Agent::Instrumentation::MetricFrame
- Inherits:
-
Object
- Object
- NewRelic::Agent::Instrumentation::MetricFrame
- Defined in:
- lib/new_relic/agent/instrumentation/metric_frame.rb
Constant Summary collapse
- @@check_server_connection =
false
- @@java_classes_loaded =
false
Instance Attribute Summary collapse
-
#apdex_start ⇒ Object
A Time instance used for calculating the apdex score, which.
-
#database_metric_name ⇒ Object
might end up being @start, or it might be further upstream if we can find a request header for the queue entry time.
-
#depth ⇒ Object
readonly
Returns the value of attribute depth.
-
#exception ⇒ Object
might end up being @start, or it might be further upstream if we can find a request header for the queue entry time.
-
#filtered_params ⇒ Object
might end up being @start, or it might be further upstream if we can find a request header for the queue entry time.
-
#force_flag ⇒ Object
might end up being @start, or it might be further upstream if we can find a request header for the queue entry time.
-
#jruby_cpu_start ⇒ Object
might end up being @start, or it might be further upstream if we can find a request header for the queue entry time.
-
#process_cpu_start ⇒ Object
might end up being @start, or it might be further upstream if we can find a request header for the queue entry time.
-
#request ⇒ Object
Give the current metric frame a request context.
-
#start ⇒ Object
A Time instance for the start time, never nil.
Class Method Summary collapse
-
.abort_transaction! ⇒ Object
Indicate that you don’t want to keep the currently saved transaction information.
-
.add_custom_parameters(p) ⇒ Object
Add context parameters to the metric frame.
- .check_server_connection=(value) ⇒ Object
-
.current(create_if_empty = nil) ⇒ Object
Return the currently active metric frame, or nil.
- .custom_parameters ⇒ Object
-
.database_metric_name ⇒ Object
This is the name of the model currently assigned to database measurements, overriding the default.
-
.notice_error(e, options = {}) ⇒ Object
If we have an active metric frame, notice the error and increment the error metric.
- .record_apdex(current_metric, action_duration, total_duration, is_error) ⇒ Object
- .recording_web_transaction? ⇒ Boolean
- .referer ⇒ Object
-
.referer_from_request(request) ⇒ Object
Make a safe attempt to get the referer from a request object, generally successful when it’s a Rack request.
-
.update_apdex(stat, duration, failed) ⇒ Object
Record an apdex value for the given stat.
-
.uri_from_request(request) ⇒ Object
Make a safe attempt to get the URI, without the host and query string.
Instance Method Summary collapse
-
#abort_transaction! ⇒ Object
Call this to ensure that the current transaction is not saved.
- #add_custom_parameters(p) ⇒ Object
- #current_metric ⇒ Object
- #custom_parameters ⇒ Object
-
#initialize ⇒ MetricFrame
constructor
A new instance of MetricFrame.
- #is_web_transaction?(metric) ⇒ Boolean
- #metric_name ⇒ Object
-
#notice_error(e, options = {}) ⇒ Object
Do not call this.
-
#path ⇒ Object
Return the path, the part of the metric after the category.
-
#pop ⇒ Object
Unwind one stack level.
-
#push(m) ⇒ Object
Indicate that we are entering a measured controller action or task.
- #record_apdex ⇒ Object
-
#recorded_metrics ⇒ Object
Return the array of metrics to record for the current metric frame.
- #recording_web_transaction? ⇒ Boolean
-
#referer ⇒ Object
For the current web transaction, return the full referer, minus the host string, or nil.
-
#start_transaction ⇒ Object
This needs to be called after entering the call to trace the controller action, otherwise the controller action blames itself.
-
#uri ⇒ Object
For the current web transaction, return the path of the URI minus the host part and query string, or nil.
-
#with_database_metric_name(model, method) ⇒ Object
Yield to a block that is run with a database metric name context.
Constructor Details
#initialize ⇒ MetricFrame
Returns a new instance of MetricFrame.
67 68 69 70 71 72 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 67 def initialize @start = Time.now @path_stack = [] # stack of [controller, path] elements @jruby_cpu_start = jruby_cpu_time @process_cpu_start = process_cpu end |
Instance Attribute Details
#apdex_start ⇒ Object
A Time instance used for calculating the apdex score, which
12 13 14 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 12 def apdex_start @apdex_start end |
#database_metric_name ⇒ Object
might end up being @start, or it might be further upstream if we can find a request header for the queue entry time
15 16 17 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 15 def database_metric_name @database_metric_name end |
#depth ⇒ Object (readonly)
Returns the value of attribute depth.
65 66 67 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 65 def depth @depth end |
#exception ⇒ Object
might end up being @start, or it might be further upstream if we can find a request header for the queue entry time
15 16 17 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 15 def exception @exception end |
#filtered_params ⇒ Object
might end up being @start, or it might be further upstream if we can find a request header for the queue entry time
15 16 17 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 15 def filtered_params @filtered_params end |
#force_flag ⇒ Object
might end up being @start, or it might be further upstream if we can find a request header for the queue entry time
15 16 17 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 15 def force_flag @force_flag end |
#jruby_cpu_start ⇒ Object
might end up being @start, or it might be further upstream if we can find a request header for the queue entry time
15 16 17 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 15 def jruby_cpu_start @jruby_cpu_start end |
#process_cpu_start ⇒ Object
might end up being @start, or it might be further upstream if we can find a request header for the queue entry time
15 16 17 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 15 def process_cpu_start @process_cpu_start end |
#request ⇒ Object
Give the current metric frame a request context. Use this to get the URI and referer. The request is interpreted loosely as a Rack::Request or an ActionController::AbstractRequest.
22 23 24 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 22 def request @request end |
#start ⇒ Object
A Time instance for the start time, never nil
11 12 13 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 11 def start @start end |
Class Method Details
.abort_transaction! ⇒ Object
Indicate that you don’t want to keep the currently saved transaction information
83 84 85 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 83 def self.abort_transaction! current.abort_transaction! if current end |
.add_custom_parameters(p) ⇒ Object
Add context parameters to the metric frame. This information will be passed in to errors and transaction traces. Keys and Values should be strings, numbers or date/times.
186 187 188 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 186 def self.add_custom_parameters(p) current.add_custom_parameters(p) if current end |
.check_server_connection=(value) ⇒ Object
26 27 28 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 26 def self.check_server_connection=(value) @@check_server_connection = value end |
.current(create_if_empty = nil) ⇒ Object
Return the currently active metric frame, or nil. Call with true
to create a new metric frame if one is not already on the thread.
31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 31 def self.current(create_if_empty=nil) f = Thread.current[:newrelic_metric_frame] return f if f || !create_if_empty # Reconnect to the server if necessary. This is only done # for old versions of passenger that don't implement an explicit after_fork # event. NewRelic::Agent.instance.after_fork(:keep_retrying => false) if @@check_server_connection Thread.current[:newrelic_metric_frame] = new end |
.custom_parameters ⇒ Object
190 191 192 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 190 def self.custom_parameters (current && current.custom_parameters) ? current.custom_parameters : {} end |
.database_metric_name ⇒ Object
This is the name of the model currently assigned to database measurements, overriding the default.
45 46 47 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 45 def self.database_metric_name current && current.database_metric_name end |
.notice_error(e, options = {}) ⇒ Object
If we have an active metric frame, notice the error and increment the error metric. Options:
-
:request
=> Request object to get the uri and referer -
:uri
=> The request path, minus any request params or query string. -
:referer
=> The URI of the referer -
:metric
=> The metric name associated with the transaction -
:request_params
=> Request parameters, already filtered if necessary -
:custom_params
=> Custom parameters
Anything left over is treated as custom params
158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 158 def self.notice_error(e, ={}) if request = .delete(:request) [:referer] = referer_from_request(request) [:uri] = uri_from_request(request) end if current current.notice_error(e, ) else NewRelic::Agent.instance.error_collector.notice_error(e, ) end end |
.record_apdex(current_metric, action_duration, total_duration, is_error) ⇒ Object
277 278 279 280 281 282 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 277 def self.record_apdex(current_metric, action_duration, total_duration, is_error) summary_stat = NewRelic::Agent.instance.stats_engine.get_custom_stats("Apdex", NewRelic::ApdexStats) controller_stat = NewRelic::Agent.instance.stats_engine.get_custom_stats(current_metric.apdex_metric_path, NewRelic::ApdexStats) update_apdex(summary_stat, total_duration, is_error) update_apdex(controller_stat, action_duration, is_error) end |
.recording_web_transaction? ⇒ Boolean
243 244 245 246 247 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 243 def self.recording_web_transaction? if c = Thread.current[:newrelic_metric_frame] c.recording_web_transaction? end end |
.referer ⇒ Object
49 50 51 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 49 def self.referer current && current.referer end |
.referer_from_request(request) ⇒ Object
Make a safe attempt to get the referer from a request object, generally successful when it’s a Rack request.
259 260 261 262 263 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 259 def self.referer_from_request(request) if request && request.respond_to?(:referer) request.referer.to_s.split('?').first end end |
.update_apdex(stat, duration, failed) ⇒ Object
Record an apdex value for the given stat. when ‘failed` the apdex should be recorded as a failure regardless of duration.
286 287 288 289 290 291 292 293 294 295 296 297 298 299 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 286 def self.update_apdex(stat, duration, failed) duration = duration.to_f apdex_t = NewRelic::Control.instance.apdex_t case when failed stat.record_apdex_f when duration <= apdex_t stat.record_apdex_s when duration <= 4 * apdex_t stat.record_apdex_t else stat.record_apdex_f end end |
.uri_from_request(request) ⇒ Object
Make a safe attempt to get the URI, without the host and query string.
266 267 268 269 270 271 272 273 274 275 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 266 def self.uri_from_request(request) approximate_uri = case when request.respond_to?(:fullpath) then request.fullpath when request.respond_to?(:path) then request.path when request.respond_to?(:request_uri) then request.request_uri when request.respond_to?(:uri) then request.uri when request.respond_to?(:url) then request.url end return approximate_uri[%r{^(https?://.*?)?(/[^?]*)}, 2] || '/' if approximate_uri # ' end |
Instance Method Details
#abort_transaction! ⇒ Object
Call this to ensure that the current transaction is not saved
98 99 100 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 98 def abort_transaction! NewRelic::Agent.instance.transaction_sampler.ignore_transaction end |
#add_custom_parameters(p) ⇒ Object
239 240 241 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 239 def add_custom_parameters(p) custom_parameters.merge!(p) end |
#current_metric ⇒ Object
111 112 113 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 111 def current_metric @path_stack.last end |
#custom_parameters ⇒ Object
235 236 237 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 235 def custom_parameters @custom_parameters ||= {} end |
#is_web_transaction?(metric) ⇒ Boolean
253 254 255 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 253 def is_web_transaction?(metric) 0 == metric.index("Controller") end |
#metric_name ⇒ Object
200 201 202 203 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 200 def metric_name return nil if @path_stack.empty? current_metric.name end |
#notice_error(e, options = {}) ⇒ Object
Do not call this. Invoke the class method instead.
171 172 173 174 175 176 177 178 179 180 181 182 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 171 def notice_error(e, ={}) # :nodoc: params = custom_parameters [:referer] = referer if referer [:request_params] = filtered_params if filtered_params [:uri] = uri if uri [:metric] = metric_name .merge!(custom_parameters) if exception != e result = NewRelic::Agent.instance.error_collector.notice_error(e, ) self.exception = result if result end end |
#path ⇒ Object
Return the path, the part of the metric after the category
116 117 118 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 116 def path @path_stack.last.last end |
#pop ⇒ Object
Unwind one stack level. It knows if it’s back at the outermost caller and does the appropriate wrapup of the context.
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 122 def pop metric = @path_stack.pop if metric.nil? NewRelic::Agent.logger.error "Underflow in metric frames: #{caller.join("\n ")}" end if @path_stack.empty? if NewRelic::Agent.is_execution_traced? cpu_burn = nil if @process_cpu_start cpu_burn = process_cpu - @process_cpu_start elsif @jruby_cpu_start cpu_burn = jruby_cpu_time - @jruby_cpu_start NewRelic::Agent.get_stats_no_scope(NewRelic::Metrics::USER_TIME).record_data_point(cpu_burn) end NewRelic::Agent.instance.transaction_sampler.notice_transaction_cpu_time(cpu_burn) if cpu_burn NewRelic::Agent.instance.histogram.process((Time.now - start).to_f) if metric.is_web_transaction? NewRelic::Agent.instance.transaction_sampler.notice_scope_empty end NewRelic::Agent.instance.stats_engine.end_transaction Thread.current[:newrelic_metric_frame] = nil else # path stack not empty # change the transaction name back to whatever was on the stack. NewRelic::Agent.instance.stats_engine.scope_name = metric_name end end |
#push(m) ⇒ Object
Indicate that we are entering a measured controller action or task. Make sure you unwind every push with a pop call.
76 77 78 79 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 76 def push(m) NewRelic::Agent.instance.transaction_sampler.notice_first_scope_push(start) @path_stack.push NewRelic::MetricParser.for_metric_named(m) end |
#record_apdex ⇒ Object
194 195 196 197 198 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 194 def record_apdex() return unless recording_web_transaction? && NewRelic::Agent.is_execution_traced? t = Time.now self.class.record_apdex(current_metric, t - start, t - apdex_start, !exception.nil?) end |
#recorded_metrics ⇒ Object
Return the array of metrics to record for the current metric frame.
206 207 208 209 210 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 206 def recorded_metrics metrics = [ metric_name ] metrics += current_metric.summary_metrics if @path_stack.size == 1 metrics end |
#recording_web_transaction? ⇒ Boolean
249 250 251 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 249 def recording_web_transaction? current_metric && current_metric.is_web_transaction? end |
#referer ⇒ Object
For the current web transaction, return the full referer, minus the host string, or nil.
93 94 95 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 93 def referer @referer ||= self.class.referer_from_request(@request) end |
#start_transaction ⇒ Object
This needs to be called after entering the call to trace the controller action, otherwise the controller action blames itself. It gets reset in the normal #pop call.
103 104 105 106 107 108 109 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 103 def start_transaction NewRelic::Agent.instance.stats_engine.start_transaction metric_name # Only push the transaction context info once, on entry: if @path_stack.size == 1 NewRelic::Agent.instance.transaction_sampler.notice_transaction(metric_name, uri, filtered_params) end end |
#uri ⇒ Object
For the current web transaction, return the path of the URI minus the host part and query string, or nil.
88 89 90 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 88 def uri @uri ||= self.class.uri_from_request(@request) unless @request.nil? end |
#with_database_metric_name(model, method) ⇒ Object
Yield to a block that is run with a database metric name context. This means the Database instrumentation will use this for the metric name if it does not otherwise know about a model. This is re-entrant.
-
model
is the DB model class -
method
is the name of the finder method or other method to identify the operation with.
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 219 def with_database_metric_name(model, method) previous = @database_metric_name model_name = case model when Class model.name when String model else model.to_s end @database_metric_name = "ActiveRecord/#{model_name}/#{method}" yield ensure @database_metric_name=previous end |