# typed: true module Datadog module ContextFlush # Consumes only completed traces (where all spans have finished) class Finished # Consumes and returns completed traces (where all spans have finished) # from the provided +context+, if any. # # Any traces consumed are removed from +context+ as a side effect. # # @return [Array] trace to be flushed, or +nil+ if the trace is not finished def consume!(context) trace, sampled = get_trace(context) trace if sampled end protected def get_trace(context) context.get end end # Performs partial trace flushing to avoid large traces residing in memory for too long class Partial # Start flushing partial trace after this many active spans in one trace DEFAULT_MIN_SPANS_FOR_PARTIAL_FLUSH = 500 def initialize(options = {}) @min_spans_for_partial = options.fetch(:min_spans_before_partial_flush, DEFAULT_MIN_SPANS_FOR_PARTIAL_FLUSH) end # Consumes and returns completed or partially completed # traces from the provided +context+, if any. # # Partially completed traces, where not all spans have finished, # will only be returned if there are at least # +@min_spans_for_partial+ finished spans. # # Any spans consumed are removed from +context+ as a side effect. # # @return [Array] partial or complete trace to be flushed, or +nil+ if no spans are finished def consume!(context) trace, sampled = get_trace(context) return nil unless sampled return trace if trace && !trace.empty? partial_trace(context) end protected def get_trace(context) context.get end private def partial_trace(context) return nil if context.finished_span_count < @min_spans_for_partial finished_spans(context) end def finished_spans(context) trace = context.delete_span_if(&:finished?) # Ensure that the first span in a partial trace has # sampling and origin information. if trace[0] context.annotate_for_flush!(trace[0]) else Datadog.logger.debug('Tried to retrieve trace from context, but got nothing. ' \ "Is there another consumer for this context? #{context.trace_id}") end trace unless trace.empty? end end end end