lib/elastic_apm/transaction.rb
# frozen_string_literal: true require 'securerandom' module ElasticAPM # rubocop:disable Metrics/ClassLength # @api private class Transaction DEFAULT_TYPE = 'custom'.freeze # rubocop:disable Metrics/MethodLength def initialize( instrumenter, name = nil, type = nil, context: nil, sampled: true ) @id = SecureRandom.uuid @instrumenter = instrumenter @name = name @type = type || DEFAULT_TYPE @timestamp = Util.micros @spans = [] @span_id_ticker = -1 @dropped_spans = 0 @notifications = [] # for AS::Notifications @context = context || Context.new @sampled = sampled yield self if block_given? end # rubocop:enable Metrics/MethodLength attr_accessor :id, :name, :result, :type attr_reader :context, :duration, :dropped_spans, :root_span, :timestamp, :spans, :notifications, :sampled, :instrumenter def release @instrumenter.current_transaction = nil end def done(result = nil) @duration = Util.micros - @timestamp @result = result self end def done? !!(@result && @duration) end def submit(result = nil, status: nil, headers: {}) done result unless duration if status context.response = Context::Response.new(status, headers: headers) end release @instrumenter.submit_transaction self self end def running_spans spans.select(&:running?) end # rubocop:disable Metrics/MethodLength def span(name, type = nil, backtrace: nil, context: nil) unless sampled? return yield if block_given? return end if spans.length >= instrumenter.config.transaction_max_spans @dropped_spans += 1 return yield if block_given? return end span = build_and_start_span(name, type, context, backtrace) return span unless block_given? begin result = yield span ensure span.done end result end # rubocop:enable Metrics/MethodLength def build_and_start_span(name, type, context, backtrace) span = next_span(name, type, context) spans << span if backtrace && span_frames_min_duration? span.original_backtrace = backtrace end span.start end def current_span spans.reverse.lazy.find(&:running?) end def sampled? !!sampled end def inspect "<ElasticAPM::Transaction id:#{id}" \ " name:#{name.inspect}" \ " type:#{type.inspect}" \ '>' end private def next_span_id @span_id_ticker += 1 end def next_span(name, type, context) Span.new( self, next_span_id, name, type, parent: current_span, context: context ) end def span_frames_min_duration? @instrumenter.agent.config.span_frames_min_duration != 0 end end # rubocop:enable Metrics/ClassLength end