Class: NewRelic::Agent::Transaction
- Inherits:
-
Object
- Object
- NewRelic::Agent::Transaction
- Includes:
- Pop
- Defined in:
- lib/new_relic/agent/transaction.rb,
lib/new_relic/agent/transaction/pop.rb
Defined Under Namespace
Modules: Pop
Constant Summary collapse
- OVERVIEW_SPECS =
[ [:webDuration, MetricSpec.new('HttpDispatcher')], [:queueDuration, MetricSpec.new('WebFrontend/QueueTime')], [:externalDuration, MetricSpec.new('External/allWeb')], [:databaseDuration, MetricSpec.new('ActiveRecord/all')], [:gcCumulative, MetricSpec.new("GC/cumulative")], [:memcacheDuration, MetricSpec.new('Memcache/allWeb')] ]
- APDEX_METRIC_SPEC =
NewRelic::MetricSpec.new('Apdex').freeze
- @@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.
-
#exceptions ⇒ 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.
-
#name ⇒ Object
Returns the value of attribute name.
-
#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 transaction a request context.
-
#start_time ⇒ Object
A Time instance for the start time, never nil.
-
#stats_hash ⇒ Object
readonly
Returns the value of attribute stats_hash.
-
#type ⇒ Object
might end up being @start, or it might be further upstream if we can find a request header for the queue entry time.
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 transaction.
- .agent ⇒ Object
- .apdex_bucket(duration, failed, apdex_t) ⇒ Object
-
.current ⇒ Object
Return the currently active transaction, or nil.
- .custom_parameters ⇒ Object
-
.database_metric_name ⇒ Object
This is the name of the model currently assigned to database measurements, overriding the default.
- .freeze_name ⇒ Object
- .in_transaction? ⇒ Boolean
-
.notice_error(e, options = {}) ⇒ Object
If we have an active transaction, notice the error and increment the error metric.
- .parent ⇒ Object
- .record_apdex(end_time, is_error) ⇒ Object
-
.recording_web_transaction? ⇒ Boolean
Returns truthy if the current in-progress transaction is considered a a web transaction (as opposed to, e.g., a background transaction).
- .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.
- .set_user_attributes(attributes) ⇒ Object
- .stack ⇒ Object
- .start(transaction_type, options = {}) ⇒ Object
- .stop(metric_name = nil, end_time = Time.now) ⇒ Object
-
.uri_from_request(request) ⇒ Object
Make a safe attempt to get the URI, without the host and query string.
- .user_attributes ⇒ Object
Instance Method Summary collapse
-
#abort_transaction! ⇒ Object
Call this to ensure that the current transaction is not saved.
- #add_custom_parameters(p) ⇒ Object
- #apdex_t ⇒ Object
- #custom_parameters ⇒ Object
- #freeze_name ⇒ Object
- #has_parent? ⇒ Boolean
-
#initialize(type = :controller, options = {}) ⇒ Transaction
constructor
A new instance of Transaction.
- #merge_stats_hash ⇒ Object
- #name_frozen? ⇒ Boolean
-
#notice_error(e, options = {}) ⇒ Object
Do not call this.
- #noticed_error_ids ⇒ Object
- #parent ⇒ Object
- #queue_time ⇒ Object
- #record_apdex(end_time = Time.now, is_error = nil) ⇒ Object
- #record_exceptions ⇒ Object
- #recording_web_transaction? ⇒ Boolean
-
#referer ⇒ Object
For the current web transaction, return the full referer, minus the host string, or nil.
- #root? ⇒ Boolean
- #set_user_attributes(attributes) ⇒ Object
-
#start(transaction_type) ⇒ Object
Indicate that we are entering a measured controller action or task.
-
#stop(metric = ::NewRelic::Agent::UNKNOWN_METRIC, end_time = Time.now) ⇒ Object
Unwind one stack level.
- #transaction_overview_metrics ⇒ Object
- #transaction_specific_apdex_t ⇒ Object
-
#uri ⇒ Object
For the current web transaction, return the path of the URI minus the host part and query string, or nil.
- #user_attributes ⇒ Object
-
#with_database_metric_name(model, method) ⇒ Object
Yield to a block that is run with a database metric name context.
Methods included from Pop
#cpu_burn, #current_stack_metric, #jruby_cpu_burn, #log_underflow, #normal_cpu_burn, #record_jruby_cpu_burn, #record_transaction_cpu, #traced?
Constructor Details
#initialize(type = :controller, options = {}) ⇒ Transaction
Returns a new instance of Transaction.
96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/new_relic/agent/transaction.rb', line 96 def initialize(type=:controller, ={}) @type = type @start_time = Time.now @apdex_start = @start_time @jruby_cpu_start = jruby_cpu_time @process_cpu_start = process_cpu @filtered_params = [:filtered_params] || {} @force_flag = [:force] @request = [:request] @exceptions = {} @stats_hash = StatsHash.new TransactionState.get.transaction = self end |
Instance Attribute Details
#apdex_start ⇒ Object
A Time instance used for calculating the apdex score, which
21 22 23 |
# File 'lib/new_relic/agent/transaction.rb', line 21 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
24 25 26 |
# File 'lib/new_relic/agent/transaction.rb', line 24 def database_metric_name @database_metric_name end |
#depth ⇒ Object (readonly)
Returns the value of attribute depth.
94 95 96 |
# File 'lib/new_relic/agent/transaction.rb', line 94 def depth @depth end |
#exceptions ⇒ Object
might end up being @start, or it might be further upstream if we can find a request header for the queue entry time
24 25 26 |
# File 'lib/new_relic/agent/transaction.rb', line 24 def exceptions @exceptions 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
24 25 26 |
# File 'lib/new_relic/agent/transaction.rb', line 24 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
24 25 26 |
# File 'lib/new_relic/agent/transaction.rb', line 24 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
24 25 26 |
# File 'lib/new_relic/agent/transaction.rb', line 24 def jruby_cpu_start @jruby_cpu_start end |
#name ⇒ Object
Returns the value of attribute name.
26 27 28 |
# File 'lib/new_relic/agent/transaction.rb', line 26 def name @name 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
24 25 26 |
# File 'lib/new_relic/agent/transaction.rb', line 24 def process_cpu_start @process_cpu_start end |
#request ⇒ Object
Give the current transaction a request context. Use this to get the URI and referer. The request is interpreted loosely as a Rack::Request or an ActionController::AbstractRequest.
32 33 34 |
# File 'lib/new_relic/agent/transaction.rb', line 32 def request @request end |
#start_time ⇒ Object
A Time instance for the start time, never nil
20 21 22 |
# File 'lib/new_relic/agent/transaction.rb', line 20 def start_time @start_time end |
#stats_hash ⇒ Object (readonly)
Returns the value of attribute stats_hash.
27 28 29 |
# File 'lib/new_relic/agent/transaction.rb', line 27 def stats_hash @stats_hash end |
#type ⇒ Object
might end up being @start, or it might be further upstream if we can find a request header for the queue entry time
24 25 26 |
# File 'lib/new_relic/agent/transaction.rb', line 24 def type @type end |
Class Method Details
.abort_transaction! ⇒ Object
Indicate that you don’t want to keep the currently saved transaction information
158 159 160 |
# File 'lib/new_relic/agent/transaction.rb', line 158 def self.abort_transaction! current.abort_transaction! if current end |
.add_custom_parameters(p) ⇒ Object
Add context parameters to the transaction. This information will be passed in to errors and transaction traces. Keys and Values should be strings, numbers or date/times.
275 276 277 |
# File 'lib/new_relic/agent/transaction.rb', line 275 def self.add_custom_parameters(p) current.add_custom_parameters(p) if current end |
.agent ⇒ Object
74 75 76 |
# File 'lib/new_relic/agent/transaction.rb', line 74 def self.agent NewRelic::Agent.instance end |
.apdex_bucket(duration, failed, apdex_t) ⇒ Object
397 398 399 400 401 402 403 404 405 406 407 408 |
# File 'lib/new_relic/agent/transaction.rb', line 397 def self.apdex_bucket(duration, failed, apdex_t) case when failed :apdex_f when duration <= apdex_t :apdex_s when duration <= 4 * apdex_t :apdex_t else :apdex_f end end |
.current ⇒ Object
Return the currently active transaction, or nil.
35 36 37 |
# File 'lib/new_relic/agent/transaction.rb', line 35 def self.current self.stack.last end |
.custom_parameters ⇒ Object
279 280 281 |
# File 'lib/new_relic/agent/transaction.rb', line 279 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.
66 67 68 |
# File 'lib/new_relic/agent/transaction.rb', line 66 def self.database_metric_name current && current.database_metric_name end |
.freeze_name ⇒ Object
78 79 80 |
# File 'lib/new_relic/agent/transaction.rb', line 78 def self.freeze_name self.current && self.current.freeze_name end |
.in_transaction? ⇒ Boolean
60 61 62 |
# File 'lib/new_relic/agent/transaction.rb', line 60 def self.in_transaction? !self.stack.empty? end |
.notice_error(e, options = {}) ⇒ Object
If we have an active transaction, 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
248 249 250 251 252 253 254 255 256 257 258 259 |
# File 'lib/new_relic/agent/transaction.rb', line 248 def self.notice_error(e, ={}) request = .delete(:request) if request [:referer] = referer_from_request(request) [:uri] = uri_from_request(request) end if current current.notice_error(e, ) else agent.error_collector.notice_error(e, ) end end |
.parent ⇒ Object
39 40 41 |
# File 'lib/new_relic/agent/transaction.rb', line 39 def self.parent self.stack[-2] end |
.record_apdex(end_time, is_error) ⇒ Object
393 394 395 |
# File 'lib/new_relic/agent/transaction.rb', line 393 def self.record_apdex(end_time, is_error) current && current.record_apdex(end_time, is_error) end |
.recording_web_transaction? ⇒ Boolean
Returns truthy if the current in-progress transaction is considered a a web transaction (as opposed to, e.g., a background transaction).
363 364 365 |
# File 'lib/new_relic/agent/transaction.rb', line 363 def self.recording_web_transaction? self.current && self.current.recording_web_transaction? end |
.referer ⇒ Object
70 71 72 |
# File 'lib/new_relic/agent/transaction.rb', line 70 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.
373 374 375 376 377 |
# File 'lib/new_relic/agent/transaction.rb', line 373 def self.referer_from_request(request) if request && request.respond_to?(:referer) request.referer.to_s.split('?').first end end |
.set_user_attributes(attributes) ⇒ Object
283 284 285 |
# File 'lib/new_relic/agent/transaction.rb', line 283 def self.set_user_attributes(attributes) current.set_user_attributes(attributes) if current end |
.stack ⇒ Object
56 57 58 |
# File 'lib/new_relic/agent/transaction.rb', line 56 def self.stack TransactionState.get.current_transaction_stack end |
.start(transaction_type, options = {}) ⇒ Object
43 44 45 46 47 48 |
# File 'lib/new_relic/agent/transaction.rb', line 43 def self.start(transaction_type, ={}) txn = Transaction.new(transaction_type, ) txn.start(transaction_type) self.stack.push(txn) return txn end |
.stop(metric_name = nil, end_time = Time.now) ⇒ Object
50 51 52 53 54 |
# File 'lib/new_relic/agent/transaction.rb', line 50 def self.stop(metric_name=nil, end_time=Time.now) txn = self.stack.last txn.stop(metric_name, end_time) if txn return self.stack.pop end |
.uri_from_request(request) ⇒ Object
Make a safe attempt to get the URI, without the host and query string.
380 381 382 383 384 385 386 387 388 389 |
# File 'lib/new_relic/agent/transaction.rb', line 380 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 |
.user_attributes ⇒ Object
287 288 289 |
# File 'lib/new_relic/agent/transaction.rb', line 287 def self.user_attributes (current) ? current.user_attributes : {} end |
Instance Method Details
#abort_transaction! ⇒ Object
Call this to ensure that the current transaction is not saved
173 174 175 |
# File 'lib/new_relic/agent/transaction.rb', line 173 def abort_transaction! transaction_sampler.ignore_transaction end |
#add_custom_parameters(p) ⇒ Object
353 354 355 |
# File 'lib/new_relic/agent/transaction.rb', line 353 def add_custom_parameters(p) custom_parameters.merge!(p) end |
#apdex_t ⇒ Object
309 310 311 |
# File 'lib/new_relic/agent/transaction.rb', line 309 def apdex_t transaction_specific_apdex_t || Agent.config[:apdex_t] end |
#custom_parameters ⇒ Object
341 342 343 |
# File 'lib/new_relic/agent/transaction.rb', line 341 def custom_parameters @custom_parameters ||= {} end |
#freeze_name ⇒ Object
122 123 124 125 126 |
# File 'lib/new_relic/agent/transaction.rb', line 122 def freeze_name return if name_frozen? @name = NewRelic::Agent.instance.transaction_rules.rename(@name) @name_frozen = true end |
#has_parent? ⇒ Boolean
140 141 142 |
# File 'lib/new_relic/agent/transaction.rb', line 140 def has_parent? self.class.stack.size > 1 end |
#merge_stats_hash ⇒ Object
208 209 210 211 |
# File 'lib/new_relic/agent/transaction.rb', line 208 def merge_stats_hash stats_hash.resolve_scopes!(@name) NewRelic::Agent.instance.stats_engine.merge!(stats_hash) end |
#name_frozen? ⇒ Boolean
128 129 130 |
# File 'lib/new_relic/agent/transaction.rb', line 128 def name_frozen? @name_frozen end |
#notice_error(e, options = {}) ⇒ Object
Do not call this. Invoke the class method instead.
262 263 264 265 266 267 268 269 270 271 |
# File 'lib/new_relic/agent/transaction.rb', line 262 def notice_error(e, ={}) # :nodoc: params = custom_parameters [:referer] = referer if referer [:request_params] = filtered_params if filtered_params [:uri] = uri if uri .merge!(custom_parameters) if !@exceptions.keys.include?(e) @exceptions[e] = end end |
#noticed_error_ids ⇒ Object
110 111 112 |
# File 'lib/new_relic/agent/transaction.rb', line 110 def noticed_error_ids @noticed_error_ids ||= [] end |
#parent ⇒ Object
132 133 134 |
# File 'lib/new_relic/agent/transaction.rb', line 132 def parent has_parent? && self.class.stack[-2] end |
#queue_time ⇒ Object
349 350 351 |
# File 'lib/new_relic/agent/transaction.rb', line 349 def queue_time @apdex_start ? @start_time - @apdex_start : 0 end |
#record_apdex(end_time = Time.now, is_error = nil) ⇒ Object
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 |
# File 'lib/new_relic/agent/transaction.rb', line 293 def record_apdex(end_time=Time.now, is_error=nil) return unless recording_web_transaction? && NewRelic::Agent.is_execution_traced? freeze_name action_duration = end_time - start_time total_duration = end_time - apdex_start is_error = is_error.nil? ? !exceptions.empty? : is_error apdex_bucket_global = self.class.apdex_bucket(total_duration, is_error, apdex_t) apdex_bucket_txn = self.class.apdex_bucket(action_duration, is_error, apdex_t) @stats_hash.record(APDEX_METRIC_SPEC, apdex_bucket_global, apdex_t) txn_apdex_metric = NewRelic::MetricSpec.new(@name.gsub(/^[^\/]+\//, 'Apdex/')) @stats_hash.record(txn_apdex_metric, apdex_bucket_txn, apdex_t) end |
#record_exceptions ⇒ Object
213 214 215 216 217 218 |
# File 'lib/new_relic/agent/transaction.rb', line 213 def record_exceptions @exceptions.each do |exception, | [:metric] = @name agent.error_collector.notice_error(exception, ) end end |
#recording_web_transaction? ⇒ Boolean
367 368 369 |
# File 'lib/new_relic/agent/transaction.rb', line 367 def recording_web_transaction? [:controller, :uri, :rack, :sinatra].include?(@type) end |
#referer ⇒ Object
For the current web transaction, return the full referer, minus the host string, or nil.
168 169 170 |
# File 'lib/new_relic/agent/transaction.rb', line 168 def referer @referer ||= self.class.referer_from_request(@request) end |
#root? ⇒ Boolean
136 137 138 |
# File 'lib/new_relic/agent/transaction.rb', line 136 def root? self.class.stack.size == 1 end |
#set_user_attributes(attributes) ⇒ Object
357 358 359 |
# File 'lib/new_relic/agent/transaction.rb', line 357 def set_user_attributes(attributes) user_attributes.merge!(attributes) end |
#start(transaction_type) ⇒ Object
Indicate that we are entering a measured controller action or task. Make sure you unwind every push with a pop call.
146 147 148 149 150 151 152 153 154 |
# File 'lib/new_relic/agent/transaction.rb', line 146 def start(transaction_type) transaction_sampler.notice_first_scope_push(start_time) sql_sampler.notice_first_scope_push(start_time) NewRelic::Agent::StatsEngine::GCProfiler.init agent.stats_engine.start_transaction transaction_sampler.notice_transaction(uri, filtered_params) sql_sampler.notice_transaction(uri, filtered_params) end |
#stop(metric = ::NewRelic::Agent::UNKNOWN_METRIC, end_time = Time.now) ⇒ Object
Unwind one stack level. It knows if it’s back at the outermost caller and does the appropriate wrapup of the context.
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 |
# File 'lib/new_relic/agent/transaction.rb', line 180 def stop(metric=::NewRelic::Agent::UNKNOWN_METRIC, end_time=Time.now) @name ||= metric unless name_frozen? freeze_name log_underflow if @type.nil? # these record metrics so need to be done before merging stats if self.root? # this one records metrics and wants to happen # before the transaction sampler is finished if traced? record_transaction_cpu gc_time = NewRelic::Agent::StatsEngine::GCProfiler.capture end @transaction_trace = transaction_sampler.notice_scope_empty(self, Time.now, gc_time) sql_sampler.notice_scope_empty(@name) overview_metrics = transaction_overview_metrics end record_exceptions merge_stats_hash # these tear everything down so need to be done after merging stats if self.root? agent.events.notify(:transaction_finished, @name, start_time.to_f, end_time.to_f - start_time.to_f, overview_metrics) agent.stats_engine.end_transaction end end |
#transaction_overview_metrics ⇒ Object
229 230 231 232 233 234 235 236 |
# File 'lib/new_relic/agent/transaction.rb', line 229 def transaction_overview_metrics metrics = {} stats = @stats_hash OVERVIEW_SPECS.each do |(dest_key, spec)| metrics[dest_key] = stats[spec].total_call_time if stats.key?(spec) end metrics end |
#transaction_specific_apdex_t ⇒ Object
313 314 315 316 |
# File 'lib/new_relic/agent/transaction.rb', line 313 def transaction_specific_apdex_t key = :web_transactions_apdex Agent.config[key] && Agent.config[key][self.name] end |
#uri ⇒ Object
For the current web transaction, return the path of the URI minus the host part and query string, or nil.
163 164 165 |
# File 'lib/new_relic/agent/transaction.rb', line 163 def uri @uri ||= self.class.uri_from_request(@request) unless @request.nil? end |
#user_attributes ⇒ Object
345 346 347 |
# File 'lib/new_relic/agent/transaction.rb', line 345 def user_attributes @user_atrributes ||= {} 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.
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 |
# File 'lib/new_relic/agent/transaction.rb', line 325 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 |