A play's trace holds the playlist, audio and saved place it fetched (#192)
hls.js sends traceparent on its own requests (xhrSetup); a beacon, which cannot set a header, and Safari's player, fetching the playlist itself, carry it in the query, which the server reads where there is no header. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
21
src/web.rs
21
src/web.rs
@@ -1329,7 +1329,7 @@ mod tests {
|
||||
let with = |v: &str| {
|
||||
let mut h = HeaderMap::new();
|
||||
h.insert("traceparent", v.parse().unwrap());
|
||||
remote_parent(&h)
|
||||
remote_parent(&h, None)
|
||||
};
|
||||
let cx = with("00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01").expect("parsed");
|
||||
assert_eq!(cx.span().span_context().trace_id().to_string(), "4bf92f3577b34da6a3ce929d0e0e4736");
|
||||
@@ -1339,7 +1339,11 @@ mod tests {
|
||||
"00-00000000000000000000000000000000-00f067aa0ba902b7-01", "00-4bf92f3577b34da6a3ce929d0e0e4736"] {
|
||||
assert!(with(bad).is_none(), "{bad}");
|
||||
}
|
||||
assert!(remote_parent(&HeaderMap::new()).is_none());
|
||||
assert!(remote_parent(&HeaderMap::new(), None).is_none());
|
||||
// From the query, where a beacon or Safari's player cannot send a header (#192).
|
||||
let q = remote_parent(&HeaderMap::new(), Some("x=1&traceparent=00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"));
|
||||
assert_eq!(q.unwrap().span().span_context().trace_id().to_string(), "4bf92f3577b34da6a3ce929d0e0e4736");
|
||||
assert!(remote_parent(&HeaderMap::new(), Some("traceparent=nonsense")).is_none());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -2456,10 +2460,15 @@ async fn client_event(user: crate::db::User, Json(e): Json<ClientEvent>) -> Stat
|
||||
}
|
||||
|
||||
/// The trace a request from the page belongs to, from its `traceparent` (#190), so the requests
|
||||
/// one action sets off are one trace. None for a missing or malformed one.
|
||||
fn remote_parent(headers: &HeaderMap) -> Option<opentelemetry::Context> {
|
||||
/// one action sets off are one trace. None for a missing or malformed one. In the query where no
|
||||
/// header can be set: a position saved by sendBeacon, and the playlist Safari's player fetches
|
||||
/// itself (#192).
|
||||
fn remote_parent(headers: &HeaderMap, query: Option<&str>) -> Option<opentelemetry::Context> {
|
||||
use opentelemetry::trace::{SpanContext, SpanId, TraceContextExt, TraceFlags, TraceId, TraceState};
|
||||
let v = headers.get("traceparent")?.to_str().ok()?;
|
||||
let v = match headers.get("traceparent") {
|
||||
Some(h) => h.to_str().ok()?,
|
||||
None => query?.split('&').find_map(|kv| kv.strip_prefix("traceparent="))?,
|
||||
};
|
||||
let mut parts = v.split('-');
|
||||
let (version, trace, span) = (parts.next()?, parts.next()?, parts.next()?);
|
||||
if version != "00" || trace.len() != 32 || span.len() != 16 {
|
||||
@@ -2514,7 +2523,7 @@ async fn access_log(req: Request, next: Next) -> Response {
|
||||
http.response.status_code = tracing::field::Empty,
|
||||
)
|
||||
};
|
||||
if let Some(parent) = remote_parent(req.headers()) {
|
||||
if let Some(parent) = remote_parent(req.headers(), req.uri().query()) {
|
||||
use tracing_opentelemetry::OpenTelemetrySpanExt;
|
||||
let _ = span.set_parent(parent);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user