Module: AllStak::Propagation
- Defined in:
- lib/allstak/propagation.rb
Constant Summary collapse
- TRACE_ID_RE =
/\A[0-9a-f]{32}\z/.freeze
- SPAN_ID_RE =
/\A[0-9a-f]{16}\z/.freeze
- ZERO_TRACE_ID_RE =
/\A0{32}\z/.freeze
- ZERO_SPAN_ID_RE =
/\A0{16}\z/.freeze
Class Method Summary collapse
- .apply_headers(headers, trace_id:, request_id: nil, span_id: nil, sampled: true) ⇒ Object
- .apply_request_headers(req, trace_id:, request_id: nil, span_id: nil, sampled: true) ⇒ Object
- .baggage(trace_id:, request_id: nil, span_id: nil) ⇒ Object
- .merge_baggage(existing, trace_id:, request_id: nil, span_id: nil) ⇒ Object
- .normalize_span_id(span_id) ⇒ Object
- .normalize_trace_id(trace_id) ⇒ Object
- .parse_traceparent(header) ⇒ Object
-
.trace_flags(sampled) ⇒ Object
W3C traceparent trace-flags: “01” = sampled, “00” = not sampled.
- .valid_span_id?(span_id) ⇒ Boolean
- .valid_trace_id?(trace_id) ⇒ Boolean
Class Method Details
.apply_headers(headers, trace_id:, request_id: nil, span_id: nil, sampled: true) ⇒ Object
80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/allstak/propagation.rb', line 80 def apply_headers(headers, trace_id:, request_id: nil, span_id: nil, sampled: true) wire_trace_id = normalize_trace_id(trace_id) wire_span_id = span_id && !span_id.to_s.empty? ? normalize_span_id(span_id) : nil headers["X-AllStak-Trace-Id"] = wire_trace_id headers["X-AllStak-Request-Id"] = request_id if request_id && !request_id.to_s.empty? if wire_span_id headers["X-AllStak-Span-Id"] = wire_span_id headers["traceparent"] = "00-#{wire_trace_id}-#{wire_span_id}-#{trace_flags(sampled)}" end headers["baggage"] = merge_baggage(headers["baggage"], trace_id: wire_trace_id, request_id: request_id, span_id: wire_span_id) headers["AllStak-Baggage"] = baggage(trace_id: wire_trace_id, request_id: request_id, span_id: wire_span_id) end |
.apply_request_headers(req, trace_id:, request_id: nil, span_id: nil, sampled: true) ⇒ Object
93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/allstak/propagation.rb', line 93 def apply_request_headers(req, trace_id:, request_id: nil, span_id: nil, sampled: true) wire_trace_id = normalize_trace_id(trace_id) wire_span_id = span_id && !span_id.to_s.empty? ? normalize_span_id(span_id) : nil req["X-AllStak-Trace-Id"] ||= wire_trace_id req["X-AllStak-Request-Id"] ||= request_id if request_id && !request_id.to_s.empty? if wire_span_id req["X-AllStak-Span-Id"] ||= wire_span_id req["traceparent"] ||= "00-#{wire_trace_id}-#{wire_span_id}-#{trace_flags(sampled)}" end req["baggage"] = merge_baggage(req["baggage"], trace_id: wire_trace_id, request_id: request_id, span_id: wire_span_id) req["AllStak-Baggage"] = baggage(trace_id: wire_trace_id, request_id: request_id, span_id: wire_span_id) end |
.baggage(trace_id:, request_id: nil, span_id: nil) ⇒ Object
12 13 14 15 16 17 |
# File 'lib/allstak/propagation.rb', line 12 def baggage(trace_id:, request_id: nil, span_id: nil) parts = ["allstak-trace_id=#{trace_id}"] parts << "allstak-request_id=#{request_id}" if request_id && !request_id.to_s.empty? parts << "allstak-span_id=#{span_id}" if span_id && !span_id.to_s.empty? parts.join(",") end |
.merge_baggage(existing, trace_id:, request_id: nil, span_id: nil) ⇒ Object
19 20 21 22 23 24 |
# File 'lib/allstak/propagation.rb', line 19 def merge_baggage(existing, trace_id:, request_id: nil, span_id: nil) preserved = existing.to_s.split(",").map(&:strip).reject do |part| part.empty? || part.downcase.start_with?("allstak-") end (preserved + baggage(trace_id: trace_id, request_id: request_id, span_id: span_id).split(",")).join(",") end |
.normalize_span_id(span_id) ⇒ Object
55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/allstak/propagation.rb', line 55 def normalize_span_id(span_id) hex = span_id.to_s.gsub(/[^0-9a-f]/i, "").downcase candidate = if hex.length >= 16 hex[0, 16] elsif !hex.empty? hex.ljust(16, "0") end return candidate if candidate && valid_span_id?(candidate) SecureRandom.hex(8) end |
.normalize_trace_id(trace_id) ⇒ Object
43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/allstak/propagation.rb', line 43 def normalize_trace_id(trace_id) hex = trace_id.to_s.gsub(/[^0-9a-f]/i, "").downcase candidate = if hex.length >= 32 hex[0, 32] elsif !hex.empty? hex.ljust(32, "0") end return candidate if candidate && valid_trace_id?(candidate) SecureRandom.hex(16) end |
.parse_traceparent(header) ⇒ Object
67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/allstak/propagation.rb', line 67 def parse_traceparent(header) match = /\A00-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})\z/i.match(header.to_s.strip) return nil unless match trace_id = match[1].downcase parent_span_id = match[2].downcase return nil unless valid_trace_id?(trace_id) && valid_span_id?(parent_span_id) { trace_id: trace_id, parent_span_id: parent_span_id, sampled: (match[3].to_i(16) & 1) == 1 } end |
.trace_flags(sampled) ⇒ Object
W3C traceparent trace-flags: “01” = sampled, “00” = not sampled. ‘sampled` defaults to true to preserve historical behavior for callers that do not pass an explicit sampling decision.
29 30 31 |
# File 'lib/allstak/propagation.rb', line 29 def trace_flags(sampled) sampled == false ? "00" : "01" end |
.valid_span_id?(span_id) ⇒ Boolean
38 39 40 41 |
# File 'lib/allstak/propagation.rb', line 38 def valid_span_id?(span_id) value = span_id.to_s.downcase value.match?(SPAN_ID_RE) && !value.match?(ZERO_SPAN_ID_RE) end |
.valid_trace_id?(trace_id) ⇒ Boolean
33 34 35 36 |
# File 'lib/allstak/propagation.rb', line 33 def valid_trace_id?(trace_id) value = trace_id.to_s.downcase value.match?(TRACE_ID_RE) && !value.match?(ZERO_TRACE_ID_RE) end |