Skip to content

feat: w3c field - #1180

Open
maxday wants to merge 3 commits into
mainfrom
maxday/w3c
Open

maxday wants to merge 3 commits into
mainfrom
maxday/w3c

Conversation

@maxday

@maxday maxday commented Oct 5, 2026

Copy link
Copy Markdown
Member

✍️ Description of changes:

Adds context.w3c() which exposes allowlisted W3C trace-context fields (traceparent, tracestate, baggage) carried on clientContext.w3c, and strips w3c from clientContext so callers can only read trace fields through the helper.

🔏 By submitting this pull request

  • I confirm that I've ran cargo +nightly fmt.
  • I confirm that I've ran cargo clippy --fix.
  • I confirm that I've made a best effort attempt to update all relevant documentation.
  • I confirm that my contribution is made under the terms of the Apache 2.0 license.

@maxday maxday changed the title Maxday/w3c feat: w3c field Oct 5, 2026
@maxday
maxday marked this pull request as ready for review October 5, 2026 14:08
@darklight3it
darklight3it self-requested a review October 8, 2026 15:27

/// Pop `w3c` out of the parsed `clientContext` and return a normalized
/// map of the allowlisted string fields (see `W3C_ALLOWED_FIELDS`).
fn extract_and_strip_w3c(client_context: Option<&mut serde_json::Value>) -> HashMap<String, String> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here I think you can simplify significantly and drop the mutability.

There's no need to pop w3c out of the client context: ClientContext doesn't declare that field, and since it doesn't use deny_unknown_fields, serde just ignores it without erroring.

So client_context_value doesn't need to be mut, and the helper can take a plain &Value, letting the caller handle the Option:

let w3c_fields = client_context_value
    .as_ref()
    .map(Self::w3c_fields_from)
    .unwrap_or_default();
let client_context: Option<ClientContext> = client_context_value
     .map(serde_json::from_value)
     .transpose()?;
/// Read the allowlisted string fields (see `W3C_ALLOWED_FIELDS`) from
/// `clientContext.w3c`; anything else is dropped.
fn w3c_fields_from(client_context: &serde_json::Value) -> HashMap<String, String> {
    let w3c = &client_context["w3c"];
    W3C_ALLOWED_FIELDS
        .iter()
        .filter_map(|key| Some((key.to_string(), w3c.get(*key)?.as_str()?.to_owned())))
        .collect()
}

&client_context["w3c"] yields Value::Null so all the invalid shapes fall out of the filter_map. Since from_value still consumes the Value, the ClientContext strings are moved rather than copied, so there's no extra cost compared to the current code.

transpose it's what you can use in place of

match client_context_value {
    Some(v) => Some(serde_json::from_value(v)?),
    None => None,
}

Comment on lines +186 to +188
pub fn w3c(&self) -> HashMap<String, String> {
self.w3c_fields.clone()
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would not return a copy here. This is not very idiomatic for Rust.

I think you should return a borrow here.

pub fn w3c(&seld)  -> &HashMap<String, String>{
   &self.w3c_fields
}

In this way you have compile time guarantee of immutability. If the customer wants to mutate the hashmap they are forced to do something like.

ctx.w3c().clone().

Leaving to them the choice of whether to copy or not.

Doing that will probably make one of your test not compile.

}

#[test]
fn w3c_returns_all_allowlisted_fields_and_strips_source() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The strips_source part is not tested and also it's not important because the client_context ignores it.


let mut fields = HashMap::new();
for key in W3C_ALLOWED_FIELDS {
if let Some(serde_json::Value::String(s)) = w3c_obj.get(*key) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The W3c standard explicitly tells to preferably any case for all three of them. But it refers specifically to haders.

This is contentious but I think we should go in this direction. Had problem in the past with this kind of issues.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should also not accept tracestate if traceparent is not set but in this case I can understand that you are doing this because you want to defer this kind of validation to OTEL SDK code.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants