class OneApm::Transaction
Constants
- OA_APDEX_F
- OA_APDEX_METRIC
- OA_APDEX_S
- OA_APDEX_T
- OA_CONTROLLER_OA_MIDDLEWARE_PREFIX
- OA_CONTROLLER_PREFIX
- OA_EMPTY_SUMMARY_METRICS
- OA_FAILED_TO_STOP_MESSAGE
- OA_GRAPE_PREFIX
- OA_JRUBY_CPU_TIME_ERROR
- OA_MIDDLEWARE_PREFIX
- OA_MIDDLEWARE_SUMMARY_METRICS
- OA_NESTED_TRACE_STOP_OPTIONS
- OA_OTHER_SUMMARY_METRIC
- OA_OTHER_TRANSACTION_PREFIX
- OA_QUEUE_TIME_METRIC
- OA_RACK_PREFIX
- OA_SINATRA_PREFIX
- OA_SUBTRANSACTION_PREFIX
- OA_TASK_PREFIX
- OA_TRACE_IGNORE_OPTIONS
- OA_TRACE_OPTIONS_SCOPED
- OA_TRACE_OPTIONS_UNSCOPED
- OA_TRANSACTION_NAMING_SOURCES
- OA_UNKNOWN_METRIC
- OA_WEB_SUMMARY_METRIC
- OA_WEB_TRANSACTION_CATEGORIES
- OA_WEB_TRANSACTION_PREFIX
Attributes
apdex_start[RW]
cat_path_hashes[R]
category[R]
database_metric_name[R]
exceptions[RW]
filtered_params[RW]
frame_stack[R]
frozen_name[R]
gc_start_snapshot[R]
guid[R]
http_response_code[RW]
ignore_frames[RW]
jruby_cpu_start[RW]
metrics[R]
process_cpu_start[RW]
request[RW]
start_time[RW]
transaction_trace[R]
Public Class Methods
apdex_bucket(duration, failed, apdex_t)
click to toggle source
-
duration: response time
-
failed: the request is failed or not
-
apdex_s: satisfy
-
apdex_t
: tolerate -
apdex_f: frustrate
# File lib/one_apm/transaction/class_methods.rb, line 98 def apdex_bucket(duration, failed, apdex_t) case when failed :apdex_f # frustrate if request failed when duration <= apdex_t :apdex_s # satisfy if duration < tolerate when duration <= 4 * apdex_t :apdex_t # tolerate if duration < 4 * tolerate else :apdex_f # otherwise frustrate end end
nested_transaction_name(name)
click to toggle source
# File lib/one_apm/transaction/class_methods.rb, line 83 def nested_transaction_name(name) if name.start_with?(Transaction::OA_WEB_TRANSACTION_PREFIX) || name.start_with?(Transaction::OA_OTHER_TRANSACTION_PREFIX) "#{Transaction::OA_SUBTRANSACTION_PREFIX}#{name}" else name end end
new(category, options)
click to toggle source
# File lib/one_apm/transaction.rb, line 50 def initialize(category, options) @frame_stack = [] @has_children = false self.default_name = options[:transaction_name] @overridden_name = nil @frozen_name = nil @category = category @start_time = Time.now @apdex_start = options[:apdex_start_time] || @start_time @jruby_cpu_start = jruby_cpu_time @process_cpu_start = process_cpu @gc_start_snapshot = OneApm::Collector::StatsEngine::GCProfiler.take_snapshot @filtered_params = options[:filtered_params] || {} @request = options[:request] @exceptions = {} @metrics = TransactionMetrics.new @guid = OneApm::Helper.generate_guid @cat_path_hashes = nil @ignore_this_transaction = false @ignore_apdex = false @ignore_enduser = false @ignore_frames = options[:ignore_frames] || [] end
referer_from_request(req)
click to toggle source
Make a safe attempt to get the referer from a request object, generally successful when it's a Rack
request.
# File lib/one_apm/transaction/class_methods.rb, line 125 def referer_from_request(req) if req && req.respond_to?(:referer) req.referer.to_s.split('?').first end end
start(state, category, options)
click to toggle source
# File lib/one_apm/transaction/class_methods.rb, line 15 def start(state, category, options) category ||= :controller txn = state.current_transaction if txn txn.create_nested_frame(state, category, options) else txn = start_new_transaction(state, category, options) end txn rescue => e OneApm::Manager.logger.error("Exception during Transaction.start", e) nil end
start_new_transaction(state, category, options)
click to toggle source
# File lib/one_apm/transaction/class_methods.rb, line 8 def start_new_transaction(state, category, options) txn = Transaction.new(category, options) state.reset(txn) txn.start(state) txn end
stop(state, end_time=Time.now)
click to toggle source
# File lib/one_apm/transaction/class_methods.rb, line 30 def stop(state, end_time=Time.now) txn = state.current_transaction if txn.nil? OneApm::Manager.logger.error(Transaction::OA_FAILED_TO_STOP_MESSAGE) return end nested_frame = txn.frame_stack.pop if txn.frame_stack.empty? txn.stop(state, end_time, nested_frame) state.reset else nested_name = nested_transaction_name(nested_frame.name) if nested_name.start_with?(Transaction::OA_MIDDLEWARE_PREFIX) summary_metrics = Transaction::OA_MIDDLEWARE_SUMMARY_METRICS else summary_metrics = Transaction::OA_EMPTY_SUMMARY_METRICS end options = Transaction::OA_NESTED_TRACE_STOP_OPTIONS options = Transaction::OA_TRACE_IGNORE_OPTIONS if txn.ignore_frame?(nested_name) OneApm::Support::MethodTracer::Helpers.trace_execution_scoped_footer( state, nested_frame.start_time.to_f, nested_name, summary_metrics, nested_frame, options, end_time.to_f) end :transaction_stopped rescue => e state.reset OneApm::Manager.logger.error("Exception during Transaction.stop", e) nil end
uri_from_request(req)
click to toggle source
Make a safe attempt to get the URI, without the host and query string.
# File lib/one_apm/transaction/class_methods.rb, line 112 def uri_from_request(req) approximate_uri = case # when req.respond_to?(:fullpath ) then req.fullpath # when req.respond_to?(:path ) then req.path when req.respond_to?(:request_uri) then req.request_uri when req.respond_to?(:uri ) then req.uri when req.respond_to?(:url ) then req.url end return approximate_uri[%r{^(https?://.*?)?(/[^?]*)}, 1] + approximate_uri[%r{^(https?://.*?)?(/[^?]*)}, 2] || '/' if approximate_uri end
wrap(state, name, category, options = {}) { || ... }
click to toggle source
# File lib/one_apm/transaction/class_methods.rb, line 71 def wrap(state, name, category, options = {}) Transaction.start(state, category, options.merge(:transaction_name => name)) begin yield rescue => e Transaction.notice_error(e) raise e ensure Transaction.stop(state) end end
Public Instance Methods
abort_transaction!(state)
click to toggle source
Call this to ensure that the current transaction is not saved
# File lib/one_apm/transaction.rb, line 171 def abort_transaction!(state) transaction_sampler.ignore_transaction(state) end
apdex_bucket(duration)
click to toggle source
# File lib/one_apm/transaction/transaction_apdex.rb, line 6 def apdex_bucket(duration) Transaction.apdex_bucket(duration, had_error?, apdex_t) end
apdex_t()
click to toggle source
# File lib/one_apm/transaction/transaction_apdex.rb, line 10 def apdex_t transaction_specific_apdex_t || OneApm::Manager.config[:apdex_t] end
background_summary_metrics()
click to toggle source
# File lib/one_apm/transaction/transaction_summary.rb, line 14 def background_summary_metrics segments = @frozen_name.split('/') if segments.size > 2 ["OtherTransaction/#{segments[1]}/all", OA_OTHER_SUMMARY_METRIC] else [] end end
cat_path_hash(state)
click to toggle source
# File lib/one_apm/transaction.rb, line 273 def cat_path_hash(state) referring_path_hash = cat_referring_path_hash(state) || '0' seed = referring_path_hash.to_i(16) result = agent.cross_app_monitor.path_hash(best_name, seed) record_cat_path_hash(result) result end
cat_referring_path_hash(state)
click to toggle source
# File lib/one_apm/transaction.rb, line 288 def cat_referring_path_hash(state) agent.cross_app_monitor.client_referring_transaction_path_hash(state) end
cat_trip_id(state)
click to toggle source
# File lib/one_apm/transaction.rb, line 269 def cat_trip_id(state) agent.cross_app_monitor.client_referring_transaction_trip_id(state) || guid end
commit!(state, end_time, outermost_segment_name)
click to toggle source
# File lib/one_apm/transaction.rb, line 127 def commit!(state, end_time, outermost_segment_name) record_transaction_cpu(state) record_gc(state, end_time) sql_sampler.on_finishing_transaction(state, @frozen_name) record_summary_metrics(outermost_segment_name, end_time) record_apdex(state, end_time) unless ignore_apdex? record_queue_time record_exceptions merge_metrics send_transaction_finished_event(state, start_time, end_time) end
cpu_burn()
click to toggle source
# File lib/one_apm/transaction/transaction_cpu.rb, line 6 def cpu_burn normal_cpu_burn || jruby_cpu_burn end
create_nested_frame(state, category, options)
click to toggle source
# File lib/one_apm/transaction.rb, line 243 def create_nested_frame(state, category, options) @has_children = true if options[:filtered_params] && !options[:filtered_params].empty? @filtered_params = options[:filtered_params] end frame_stack.push OneApm::Support::MethodTracer::Helpers.trace_execution_scoped_header(state, Time.now.to_f) name_last_frame(options[:transaction_name]) set_default_transaction_name(options[:transaction_name], category) end
ignore_frame?(tx_name)
click to toggle source
# File lib/one_apm/transaction.rb, line 310 def ignore_frame? tx_name return false if ignore_frames.empty? ignore_frames.any?{|iframe| tx_name.to_s.match(/#{iframe}/)} end
instrumentation_state()
click to toggle source
# File lib/one_apm/transaction.rb, line 235 def instrumentation_state @instrumentation_state ||= {} end
jruby_cpu_burn()
click to toggle source
# File lib/one_apm/transaction/transaction_jruby_functions.rb, line 34 def jruby_cpu_burn return unless @jruby_cpu_start jruby_cpu_time - @jruby_cpu_start end
jruby_cpu_time()
click to toggle source
# File lib/one_apm/transaction/transaction_jruby_functions.rb, line 20 def jruby_cpu_time return nil unless @@java_classes_loaded threadMBean = Java::JavaLangManagement::ManagementFactory.getThreadMXBean() return nil unless threadMBean.isCurrentThreadCpuTimeSupported java_utime = threadMBean.getCurrentThreadUserTime() # ns -1 == java_utime ? 0.0 : java_utime/1e9 rescue => e OneApm::Manager.logger.log_once(:warn, :jruby_cpu_time, OA_JRUBY_CPU_TIME_ERROR, e) OneApm::Manager.logger.debug(OA_JRUBY_CPU_TIME_ERROR, e) nil end
merge_metrics()
click to toggle source
# File lib/one_apm/transaction.rb, line 230 def merge_metrics return if ignore_frame?(best_name) agent.stats_engine.merge_transaction_metrics!(@metrics, best_name) end
needs_middleware_summary_metrics?(name)
click to toggle source
# File lib/one_apm/transaction/transaction_summary.rb, line 23 def needs_middleware_summary_metrics?(name) name.start_with?(OA_MIDDLEWARE_PREFIX) end
normal_cpu_burn()
click to toggle source
# File lib/one_apm/transaction/transaction_cpu.rb, line 10 def normal_cpu_burn return unless @process_cpu_start process_cpu - @process_cpu_start end
noticed_error_ids()
click to toggle source
# File lib/one_apm/transaction.rb, line 239 def noticed_error_ids @noticed_error_ids ||= [] end
process_cpu()
click to toggle source
# File lib/one_apm/transaction/transaction_cpu.rb, line 15 def process_cpu return nil if defined? JRuby p = Process.times p.stime + p.utime end
record_apdex(state, end_time=Time.now)
click to toggle source
# File lib/one_apm/transaction.rb, line 196 def record_apdex(state, end_time=Time.now) return unless recording_web_transaction? && state.is_execution_traced? freeze_name_and_execute_if_not_ignored do action_duration = end_time - start_time total_duration = end_time - apdex_start apdex_bucket_global = apdex_bucket(total_duration) apdex_bucket_txn = apdex_bucket(action_duration) @metrics.record_unscoped(OA_APDEX_METRIC, apdex_bucket_global, apdex_t) txn_apdex_metric = @frozen_name.gsub(/^[^\/]+\//, 'Apdex/') @metrics.record_unscoped(txn_apdex_metric, apdex_bucket_txn, apdex_t) end end
record_cat_path_hash(hash)
click to toggle source
# File lib/one_apm/transaction.rb, line 281 def record_cat_path_hash(hash) @cat_path_hashes ||= [] if @cat_path_hashes.size < 10 && !@cat_path_hashes.include?(hash) @cat_path_hashes << hash end end
record_exceptions()
click to toggle source
# File lib/one_apm/transaction.rb, line 223 def record_exceptions @exceptions.each do |exception, options| options[:metric] = best_name agent.error_collector.notice_error(exception, options) end end
record_gc(state, end_time)
click to toggle source
# File lib/one_apm/transaction.rb, line 182 def record_gc(state, end_time) gc_stop_snapshot = OneApm::Collector::StatsEngine::GCProfiler.take_snapshot gc_delta = OneApm::Collector::StatsEngine::GCProfiler.record_delta(gc_start_snapshot, gc_stop_snapshot) @transaction_trace = transaction_sampler.on_finishing_transaction(state, self, end_time, gc_delta) end
record_queue_time()
click to toggle source
# File lib/one_apm/transaction.rb, line 212 def record_queue_time value = queue_time if value > 0.0 if value < OneApm::Support::MethodTracer::Helpers::OA_MAX_ALLOWED_METRIC_DURATION @metrics.record_unscoped(OA_QUEUE_TIME_METRIC, value) else OneApm::Manager.logger.log_once(:warn, :too_high_queue_time, "Not recording unreasonably large queue time of #{value} s") end end end
record_summary_metrics(outermost_segment_name, end_time)
click to toggle source
The summary metrics recorded by this method all end up with a duration equal to the transaction itself, and an exclusive time of zero.
# File lib/one_apm/transaction.rb, line 190 def record_summary_metrics(outermost_segment_name, end_time) metrics = summary_metrics metrics << @frozen_name unless @frozen_name == outermost_segment_name @metrics.record_unscoped(metrics, end_time.to_f - start_time.to_f, 0) end
record_transaction_cpu(state)
click to toggle source
# File lib/one_apm/transaction.rb, line 175 def record_transaction_cpu(state) burn = cpu_burn if burn transaction_sampler.notice_transaction_cpu_time(state, burn) end end
reqest_url()
click to toggle source
# File lib/one_apm/transaction.rb, line 166 def reqest_url request.url rescue '' end
send_transaction_finished_event(state, start_time, end_time)
click to toggle source
This event is fired when the transaction is fully completed. The metric values and sampler can't be successfully modified from this event.
# File lib/one_apm/transaction.rb, line 144 def send_transaction_finished_event(state, start_time, end_time) duration = end_time.to_f - start_time.to_f payload = { :name => @frozen_name, :start_timestamp => start_time.to_f, :duration => duration, :metrics => @metrics, :custom_params => custom_parameters, :guid => guid, :request_url => reqest_url } append_cat_info(state, duration, payload) append_apdex_perf_zone(duration, payload) append_synthetics_to(state, payload) append_referring_transaction_guid_to(state, payload) append_http_response_code(payload) append_metric_ids_to(payload) agent.events.notify(:transaction_finished, payload) end
start(state)
click to toggle source
# File lib/one_apm/transaction.rb, line 77 def start(state) return if !state.is_execution_traced? transaction_sampler.on_start_transaction(state, start_time, uri) sql_sampler.on_start_transaction(state, start_time, uri) agent.events.notify(:start_transaction) OneApm::Agent::BusyCalculator.dispatcher_start(start_time) frame_stack.push OneApm::Support::MethodTracer::Helpers.trace_execution_scoped_header(state, start_time.to_f) name_last_frame @default_name end
stop(state, end_time, outermost_frame)
click to toggle source
# File lib/one_apm/transaction.rb, line 89 def stop(state, end_time, outermost_frame) return if !state.is_execution_traced? freeze_name_and_execute_if_not_ignored ignore! if user_defined_rules_ignore? if @has_children name = Transaction.nested_transaction_name(outermost_frame.name) trace_options = OA_TRACE_OPTIONS_SCOPED else name = @frozen_name trace_options = OA_TRACE_OPTIONS_UNSCOPED end trace_options = OA_TRACE_IGNORE_OPTIONS if ignore_frame?(outermost_frame.name) # These metrics are recorded here instead of in record_summary_metrics # in order to capture the exclusive time associated with the outer-most # TT node. if needs_middleware_summary_metrics?(name) summary_metrics_with_exclusive_time = OA_MIDDLEWARE_SUMMARY_METRICS else summary_metrics_with_exclusive_time = OA_EMPTY_SUMMARY_METRICS end OneApm::Support::MethodTracer::Helpers.trace_execution_scoped_footer( state, start_time.to_f, name, summary_metrics_with_exclusive_time, outermost_frame, trace_options, end_time.to_f) OneApm::Agent::BusyCalculator.dispatcher_finish(end_time) commit!(state, end_time, name) unless @ignore_this_transaction end
summary_metrics()
click to toggle source
# File lib/one_apm/transaction/transaction_summary.rb, line 6 def summary_metrics if @frozen_name.start_with?(OA_WEB_TRANSACTION_PREFIX) [OA_WEB_SUMMARY_METRIC] else background_summary_metrics end end
transaction_specific_apdex_t()
click to toggle source
# File lib/one_apm/transaction/transaction_apdex.rb, line 14 def transaction_specific_apdex_t key = :web_transactions_apdex OneApm::Manager.config[key] && OneApm::Manager.config[key][best_name] end
user_defined_rules_ignore?()
click to toggle source
# File lib/one_apm/transaction.rb, line 254 def user_defined_rules_ignore? return unless uri return if (rules = OneApm::Manager.config[:"rules.ignore_url_regexes"]).empty? parsed = OneApm::Support::HTTPClients::URIUtil.parse_url(uri) filtered_uri = OneApm::Support::HTTPClients::URIUtil.filter_uri(parsed) rules.any? do |rule| filtered_uri.match(rule) end rescue URI::InvalidURIError => e OneApm::Manager.logger.debug("Error parsing URI: #{uri}", e) false end