class Sentry::PropagationContext

def self.extract_sample_rand_from_baggage(baggage, trace_id = nil)

def self.extract_sample_rand_from_baggage(baggage, trace_id = nil)
  return unless baggage&.items
  sample_rand_str = baggage.items["sample_rand"]
  return unless sample_rand_str
  generator = Utils::SampleRand.new(trace_id: trace_id)
  generator.generate_from_value(sample_rand_str)
end

def self.extract_sentry_trace(sentry_trace)

Returns:
  • (Array, nil) -

Parameters:
  • sentry_trace (String) -- the sentry-trace header value from the previous transaction.
def self.extract_sentry_trace(sentry_trace)
  value = sentry_trace.to_s.strip
  return if value.empty?
  match = SENTRY_TRACE_REGEXP.match(value)
  return if match.nil?
  trace_id, parent_span_id, sampled_flag = match[1..3]
  parent_sampled = sampled_flag.nil? ? nil : sampled_flag != "0"
  [trace_id, parent_span_id, parent_sampled]
end

def self.generate_sample_rand(baggage, trace_id, parent_sampled)

def self.generate_sample_rand(baggage, trace_id, parent_sampled)
  generator = Utils::SampleRand.new(trace_id: trace_id)
  if baggage&.items && !parent_sampled.nil?
    sample_rate_str = baggage.items["sample_rate"]
    sample_rate = sample_rate_str&.to_f
    if sample_rate && !parent_sampled.nil?
      generator.generate_from_sampling_decision(parent_sampled, sample_rate)
    else
      generator.generate_from_trace_id
    end
  else
    generator.generate_from_trace_id
  end
end

def self.should_continue_trace?(incoming_baggage)

Returns:
  • (Boolean) -

Parameters:
  • incoming_baggage (Baggage) -- the baggage from the incoming request
def self.should_continue_trace?(incoming_baggage)
  return true unless Sentry.initialized?
  configuration = Sentry.configuration
  sdk_org_id = configuration.effective_org_id
  baggage_org_id = incoming_baggage.items["org_id"]
  # Mismatched org IDs always start a new trace regardless of strict mode
  if sdk_org_id && baggage_org_id && sdk_org_id != baggage_org_id
    Sentry.sdk_logger.debug(LOGGER_PROGNAME) do
      "Starting a new trace because org IDs don't match (incoming baggage org_id: #{baggage_org_id}, SDK org_id: #{sdk_org_id})"
    end
    return false
  end
  return true unless configuration.strict_trace_continuation
  # In strict mode, both must be present and match (unless both are missing)
  if sdk_org_id.nil? && baggage_org_id.nil?
    true
  elsif sdk_org_id.nil? || baggage_org_id.nil?
    Sentry.sdk_logger.debug(LOGGER_PROGNAME) do
      "Starting a new trace because strict trace continuation is enabled and one org ID is missing " \
        "(incoming baggage org_id: #{baggage_org_id.inspect}, SDK org_id: #{sdk_org_id.inspect})"
    end
    false
  else
    true
  end
end

def get_baggage

Returns:
  • (Baggage, nil) -
def get_baggage
  populate_head_baggage if @baggage.nil? || @baggage.mutable
  @baggage
end

def get_dynamic_sampling_context

Returns:
  • (Hash, nil) -
def get_dynamic_sampling_context
  get_baggage&.dynamic_sampling_context
end

def get_trace_context

Returns:
  • (Hash) -
def get_trace_context
  {
    trace_id: trace_id,
    span_id: span_id,
    parent_span_id: parent_span_id
  }
end

def get_traceparent

Returns:
  • (String) -
def get_traceparent
  "#{trace_id}-#{span_id}"
end

def initialize(scope, env = nil)

def initialize(scope, env = nil)
  @scope = scope
  @parent_span_id = nil
  @parent_sampled = nil
  @baggage = nil
  @incoming_trace = false
  @sample_rand = nil
  if env
    sentry_trace_header = env["HTTP_SENTRY_TRACE"] || env[SENTRY_TRACE_HEADER_NAME]
    baggage_header = env["HTTP_BAGGAGE"] || env[BAGGAGE_HEADER_NAME]
    if sentry_trace_header
      sentry_trace_data = self.class.extract_sentry_trace(sentry_trace_header)
      if sentry_trace_data
        incoming_baggage =
          if baggage_header && !baggage_header.empty?
            Baggage.from_incoming_header(baggage_header)
          else
            # If there's an incoming sentry-trace but no incoming baggage header,
            # for instance in traces coming from older SDKs,
            # baggage will be empty and frozen and won't be populated as head SDK.
            Baggage.new({})
          end
        if self.class.should_continue_trace?(incoming_baggage)
          @trace_id, @parent_span_id, @parent_sampled = sentry_trace_data
          @baggage = incoming_baggage
          @sample_rand = self.class.extract_sample_rand_from_baggage(@baggage, @trace_id)
          @baggage.freeze!
          @incoming_trace = true
        end
      end
    end
  end
  @trace_id ||= Utils.uuid
  @span_id = Utils.uuid.slice(0, 16)
  @sample_rand ||= self.class.generate_sample_rand(@baggage, @trace_id, @parent_sampled)
end

def populate_head_baggage

def populate_head_baggage
  return unless Sentry.initialized?
  configuration = Sentry.configuration
  items = {
    "trace_id" => trace_id,
    "sample_rand" => Utils::SampleRand.format(@sample_rand),
    "environment" => configuration.environment,
    "release" => configuration.release,
    "public_key" => configuration.dsn&.public_key,
    "org_id" => configuration.effective_org_id
  }
  items.compact!
  @baggage = Baggage.new(items, mutable: false)
end