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)
-
(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)
-
(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
-
(Baggage, nil)-
def get_baggage populate_head_baggage if @baggage.nil? || @baggage.mutable @baggage end
def get_dynamic_sampling_context
-
(Hash, nil)-
def get_dynamic_sampling_context get_baggage&.dynamic_sampling_context end
def get_trace_context
-
(Hash)-
def get_trace_context { trace_id: trace_id, span_id: span_id, parent_span_id: parent_span_id } end
def get_traceparent
-
(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