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
- #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.
- #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
-
#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 TransactionInfo.get.transaction = self end |
Instance Attribute Details
#apdex_start ⇒ Object
A Time instance used for calculating the apdex score, which
20 21 22 |
# File 'lib/new_relic/agent/transaction.rb', line 20 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
23 24 25 |
# File 'lib/new_relic/agent/transaction.rb', line 23 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
23 24 25 |
# File 'lib/new_relic/agent/transaction.rb', line 23 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
23 24 25 |
# File 'lib/new_relic/agent/transaction.rb', line 23 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
23 24 25 |
# File 'lib/new_relic/agent/transaction.rb', line 23 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
23 24 25 |
# File 'lib/new_relic/agent/transaction.rb', line 23 def jruby_cpu_start @jruby_cpu_start end |
#name ⇒ Object
Returns the value of attribute name.
25 26 27 |
# File 'lib/new_relic/agent/transaction.rb', line 25 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
23 24 25 |
# File 'lib/new_relic/agent/transaction.rb', line 23 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.
31 32 33 |
# File 'lib/new_relic/agent/transaction.rb', line 31 def request @request end |
#start_time ⇒ Object
A Time instance for the start time, never nil
19 20 21 |
# File 'lib/new_relic/agent/transaction.rb', line 19 def start_time @start_time end |
#stats_hash ⇒ Object (readonly)
Returns the value of attribute stats_hash.
26 27 28 |
# File 'lib/new_relic/agent/transaction.rb', line 26 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
23 24 25 |
# File 'lib/new_relic/agent/transaction.rb', line 23 def type @type end |
Class Method Details
.abort_transaction! ⇒ Object
Indicate that you don’t want to keep the currently saved transaction information
154 155 156 |
# File 'lib/new_relic/agent/transaction.rb', line 154 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.
271 272 273 |
# File 'lib/new_relic/agent/transaction.rb', line 271 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
385 386 387 388 389 390 391 392 393 394 395 396 |
# File 'lib/new_relic/agent/transaction.rb', line 385 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
275 276 277 |
# File 'lib/new_relic/agent/transaction.rb', line 275 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
244 245 246 247 248 249 250 251 252 253 254 255 |
# File 'lib/new_relic/agent/transaction.rb', line 244 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
381 382 383 |
# File 'lib/new_relic/agent/transaction.rb', line 381 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).
351 352 353 |
# File 'lib/new_relic/agent/transaction.rb', line 351 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.
361 362 363 364 365 |
# File 'lib/new_relic/agent/transaction.rb', line 361 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
279 280 281 |
# File 'lib/new_relic/agent/transaction.rb', line 279 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 Thread.current[:newrelic_transaction] ||= [] 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.
368 369 370 371 372 373 374 375 376 377 |
# File 'lib/new_relic/agent/transaction.rb', line 368 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
283 284 285 |
# File 'lib/new_relic/agent/transaction.rb', line 283 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
169 170 171 |
# File 'lib/new_relic/agent/transaction.rb', line 169 def abort_transaction! transaction_sampler.ignore_transaction end |
#add_custom_parameters(p) ⇒ Object
341 342 343 |
# File 'lib/new_relic/agent/transaction.rb', line 341 def add_custom_parameters(p) custom_parameters.merge!(p) end |
#custom_parameters ⇒ Object
329 330 331 |
# File 'lib/new_relic/agent/transaction.rb', line 329 def custom_parameters @custom_parameters ||= {} end |
#freeze_name ⇒ Object
118 119 120 121 122 |
# File 'lib/new_relic/agent/transaction.rb', line 118 def freeze_name return if name_frozen? @name = NewRelic::Agent.instance.transaction_rules.rename(@name) @name_frozen = true end |
#has_parent? ⇒ Boolean
136 137 138 |
# File 'lib/new_relic/agent/transaction.rb', line 136 def has_parent? self.class.stack.size > 1 end |
#merge_stats_hash ⇒ Object
204 205 206 207 |
# File 'lib/new_relic/agent/transaction.rb', line 204 def merge_stats_hash stats_hash.resolve_scopes!(@name) NewRelic::Agent.instance.stats_engine.merge!(stats_hash) end |
#name_frozen? ⇒ Boolean
124 125 126 |
# File 'lib/new_relic/agent/transaction.rb', line 124 def name_frozen? @name_frozen end |
#notice_error(e, options = {}) ⇒ Object
Do not call this. Invoke the class method instead.
258 259 260 261 262 263 264 265 266 267 |
# File 'lib/new_relic/agent/transaction.rb', line 258 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 |
#parent ⇒ Object
128 129 130 |
# File 'lib/new_relic/agent/transaction.rb', line 128 def parent has_parent? && self.class.stack[-2] end |
#queue_time ⇒ Object
337 338 339 |
# File 'lib/new_relic/agent/transaction.rb', line 337 def queue_time @apdex_start ? @start_time - @apdex_start : 0 end |
#record_apdex(end_time = Time.now, is_error = nil) ⇒ Object
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 |
# File 'lib/new_relic/agent/transaction.rb', line 289 def record_apdex(end_time=Time.now, is_error=nil) return unless recording_web_transaction? && NewRelic::Agent.is_execution_traced? freeze_name apdex_t = TransactionInfo.get.apdex_t 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
209 210 211 212 213 214 |
# File 'lib/new_relic/agent/transaction.rb', line 209 def record_exceptions @exceptions.each do |exception, | [:metric] = @name agent.error_collector.notice_error(exception, ) end end |
#recording_web_transaction? ⇒ Boolean
355 356 357 |
# File 'lib/new_relic/agent/transaction.rb', line 355 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.
164 165 166 |
# File 'lib/new_relic/agent/transaction.rb', line 164 def referer @referer ||= self.class.referer_from_request(@request) end |
#root? ⇒ Boolean
132 133 134 |
# File 'lib/new_relic/agent/transaction.rb', line 132 def root? self.class.stack.size == 1 end |
#set_user_attributes(attributes) ⇒ Object
345 346 347 |
# File 'lib/new_relic/agent/transaction.rb', line 345 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.
142 143 144 145 146 147 148 149 150 |
# File 'lib/new_relic/agent/transaction.rb', line 142 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.
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
# File 'lib/new_relic/agent/transaction.rb', line 176 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, end_time.to_f - start_time.to_f, overview_metrics) agent.stats_engine.end_transaction end end |
#transaction_overview_metrics ⇒ Object
225 226 227 228 229 230 231 232 |
# File 'lib/new_relic/agent/transaction.rb', line 225 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 |
#uri ⇒ Object
For the current web transaction, return the path of the URI minus the host part and query string, or nil.
159 160 161 |
# File 'lib/new_relic/agent/transaction.rb', line 159 def uri @uri ||= self.class.uri_from_request(@request) unless @request.nil? end |
#user_attributes ⇒ Object
333 334 335 |
# File 'lib/new_relic/agent/transaction.rb', line 333 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.
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 |
# File 'lib/new_relic/agent/transaction.rb', line 313 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 |