Module: Foam::Otel::SessionStitching
- Defined in:
- lib/foam/otel/session_stitching.rb
Overview
Session stitching (owner ruling 2026-07-26): the browser package stamps
session.id on every signal and propagates it to backends as W3C
Baggage (baggage: session.id=... beside traceparent). Every server
package's floor gains this tiny baggage→attributes pass: when an
inbound request carries the session baggage, foam copies session.id
(and session.previous_id across a rotation) onto every span and log
record it emits — so one user session stitches browser → backend with
no ingest-side join. No-op when the baggage is absent (backend-only
traffic pays one hash lookup per key). Never raises (rule 9).
Foam's W3C propagator set already includes Baggage (init.rb
configure_propagation), so the inbound extraction is free; the CORS
side (Access-Control-Allow-Headers: traceparent, baggage) is the
FDE's wiring obligation, documented in the README.
These processors ride FOAM'S OWN pipeline only (door 1) — a door-2 tap never mutates the customer's records (additive readers, ingest.rb).
Defined Under Namespace
Classes: LogRecordProcessor, SpanProcessor
Constant Summary collapse
- SESSION_ID_KEY =
"session.id"- SESSION_PREVIOUS_ID_KEY =
"session.previous_id"- BAGGAGE_KEYS =
[SESSION_ID_KEY, SESSION_PREVIOUS_ID_KEY].freeze
Class Method Summary collapse
-
.session_attributes(context) ⇒ Object
The session baggage entries present in
context, as an attributes hash — {} when none (the no-op path).
Class Method Details
.session_attributes(context) ⇒ Object
The session baggage entries present in context, as an attributes
hash — {} when none (the no-op path). Values pass through VERBATIM
except for encoding hygiene: the baggage extractor percent-DECODES
header values, so a hostile inbound baggage: session.id=%FF%FE
would stamp invalid UTF-8 onto EVERY span/log of the request and the
upstream OTLP encoder would drop each WHOLE batch (rule 15) —
scrub_utf8 replaces invalid bytes with U+FFFD and touches nothing
else (the same capture-time pass api.rb applies).
39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/foam/otel/session_stitching.rb', line 39 def session_attributes(context) BAGGAGE_KEYS.each_with_object({}) do |key, out| value = OpenTelemetry::Baggage.value(key, context: context) next unless value.is_a?(String) && !value.empty? value = Redaction.scrub_utf8(value) out[key] = value if value.is_a?(String) && !value.empty? end rescue StandardError, SystemStackError {} end |