pgtask-otel 0.2.0

OpenTelemetry conventions and propagation for pgtask
Documentation
use std::fmt;

use opentelemetry::{
    Context, KeyValue,
    baggage::BaggageExt,
    global,
    propagation::{Extractor, Injector, TextMapPropagator, text_map_propagator::FieldIter},
    trace::{SpanContext, SpanId, TraceContextExt, TraceFlags, TraceId, TraceState},
};
use pgtask_otel::{configure_propagation, inject_context, set_parent_from_headers};
use serde_json::{Map, Value};

struct KeysPropagator {
    fields: Vec<String>,
}

impl fmt::Debug for KeysPropagator {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        formatter.debug_struct("KeysPropagator").finish()
    }
}

impl TextMapPropagator for KeysPropagator {
    fn inject_context(&self, _context: &Context, _injector: &mut dyn Injector) {}

    fn extract_with_context(&self, context: &Context, extractor: &dyn Extractor) -> Context {
        assert!(extractor.keys().contains(&"application"));
        assert_eq!(extractor.get("application"), Some("kept"));
        assert_eq!(extractor.get("numeric"), None);
        assert_eq!(extractor.get("missing"), None);
        context.clone()
    }

    fn fields(&self) -> FieldIter<'_> {
        FieldIter::new(&self.fields)
    }
}

#[test]
fn propagation_uses_json_headers_without_replacing_application_values() {
    configure_propagation();
    let span_context = SpanContext::new(
        TraceId::from_hex("4bf92f3577b34da6a3ce929d0e0e4736").unwrap(),
        SpanId::from_hex("00f067aa0ba902b7").unwrap(),
        TraceFlags::SAMPLED,
        false,
        TraceState::default(),
    );
    let context = Context::new()
        .with_remote_span_context(span_context)
        .with_baggage([KeyValue::new("tenant", "acme")]);
    let mut original = Map::new();
    original.insert("application".to_owned(), Value::String("kept".to_owned()));
    original.insert("numeric".to_owned(), Value::from(1));

    let headers = inject_context(&original, &context);

    assert_eq!(headers["application"], "kept");
    assert_eq!(
        headers["traceparent"],
        "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"
    );
    assert_eq!(headers["baggage"], "tenant=acme");

    global::set_text_map_propagator(KeysPropagator { fields: Vec::new() });
    assert!(set_parent_from_headers(&tracing::info_span!("consumer"), &headers).is_err());
    configure_propagation();
}