Skip to content

[Feature]: Extend XrayPropagator to support _X_AMZN_TRACE_ID environment variable #494

@johannesfloriangeiger

Description

@johannesfloriangeiger

Related Problems?

No response

What component are you working with?

opentelemetry-aws

Describe the solution you'd like:

Consider the following minimal example:

mod xray_propagator;

use crate::xray_propagator::XrayPropagator;
use lambda_runtime::{
    Error, LambdaEvent, Runtime, layers::OpenTelemetryLayer as OTELLayer, service_fn,
};
use opentelemetry::{
    Context, global,
    trace::{TraceContextExt, TracerProvider},
};
use opentelemetry_http::HeaderExtractor;
use serde_json::Value;
use std::env;
use tracing_subscriber::prelude::*;

async fn handler(_: LambdaEvent<Value>) -> Result<(), Error> {
    let context = global::get_text_map_propagator(|propagator| {
        println!("{:?}", propagator);
        let carrier = http::HeaderMap::new();
        let extractor = HeaderExtractor(&carrier);

        propagator.extract_with_context(&Context::current(), &extractor)
    });

    let x_amzn_trace_id = env::var("_X_AMZN_TRACE_ID").unwrap();
    println!("x_amzn_trace_id: {}", x_amzn_trace_id);

    println!(
        "trace_id pre attach: {}",
        Context::current().span().span_context().trace_id()
    );

    let _guard = context.attach();

    println!(
        "trace_id post attach: {}",
        Context::current().span().span_context().trace_id()
    );

    Ok(())
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    global::set_text_map_propagator(XrayPropagator::new());
    let tracer_provider = opentelemetry_sdk::trace::SdkTracerProvider::builder().build();
    let tracer = tracer_provider.tracer("OpenTelemetryRustLambda");
    tracing_subscriber::registry()
        .with(tracing_opentelemetry::OpenTelemetryLayer::new(tracer))
        .init();

    Runtime::new(service_fn(handler))
        .layer(OTELLayer::new(|| {}))
        .run()
        .await
}

(note that I copied the XrayPropagator from https://raw.githubusercontent.com/open-telemetry/opentelemetry-rust-contrib/refs/heads/main/opentelemetry-aws/src/trace/xray_propagator.rs into my local directory to make changes easier).

When I run this with cargo lambda watch and invoke it with cargo lambda invoke --data-ascii '{}' the output shows that the XrayPropagator is used and a difference between the x_amzn_trace_id and the trace ID pre and post attach of the propagated Context. This is due to the XrayPropagator only considering the x-amzn-trace-id header when extracting the Context (see https://github.com/open-telemetry/opentelemetry-rust-contrib/blob/main/opentelemetry-aws/src/trace/xray_propagator.rs#L207-L209).

When this function is being replaced with e.g.

    fn extract_span_context(&self, extractor: &dyn Extractor) -> Option<SpanContext> {
        match extractor.get(AWS_XRAY_TRACE_HEADER) {
            None => {
                match env::var(AWS_XRAY_ENV) {
                    Ok(env) => span_context_from_str(env.as_str())
                    Err(_) => None,
                }
            }
            Some(header) => span_context_from_str(header.trim()),
        }
    }

instead, running the same commands as above show a different trace ID post attachment of the context, the one from the _X_AMZN_TRACE_ID environment variable.

Considered Alternatives

No response

Additional Context

No response

Tip

React with 👍 to help prioritize this issue. Please use comments to provide useful context, avoiding +1 or me too, to help us triage it. Learn more here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions