//! Spans reach a REAL OTLP/HTTP receiver: a live server accepting //! protobuf at /v1/traces, decoded with the official proto types — the //! exact wire contract any collector speaks. use std::sync::Arc; use opentelemetry_proto::tonic::collector::trace::v1::ExportTraceServiceRequest; use prost::Message; use tokio::sync::Mutex; type Received = Arc>>; #[tokio::test(flavor = "multi_thread")] async fn spans_export_to_a_real_otlp_receiver() { let received: Received = Arc::new(Mutex::new(Vec::new())); let state = received.clone(); let app = axum::Router::new() .route( "/v1/traces", axum::routing::post( |axum::extract::State(state): axum::extract::State, body: axum::body::Bytes| async move { let request = ExportTraceServiceRequest::decode(body.as_ref()).expect("otlp protobuf"); state.lock().await.push(request); // An empty ExportTraceServiceResponse. ( [("content-type", "application/x-protobuf")], Vec::::new(), ) }, ), ) .with_state(state); let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap(); let endpoint = format!("http://{}", listener.local_addr().unwrap()); tokio::spawn(async move { axum::serve(listener, app).await.unwrap(); }); let guard = cm_telemetry::init("clawmates-test", Some(&endpoint)).expect("init"); { let span = tracing::info_span!("approval_decision", approval_id = "ap_123"); let _entered = span.enter(); tracing::info!("decided"); } guard.flush(); // Find our span among everything exported. let requests = received.lock().await; assert!(!requests.is_empty(), "no OTLP export arrived"); let mut span_names = Vec::new(); let mut service_names = Vec::new(); for request in requests.iter() { for resource in &request.resource_spans { if let Some(res) = &resource.resource { for attr in &res.attributes { if attr.key == "service.name" { if let Some(value) = &attr.value { service_names.push(format!("{value:?}")); } } } } for scope in &resource.scope_spans { for span in &scope.spans { span_names.push(span.name.clone()); } } } } assert!( span_names.iter().any(|name| name == "approval_decision"), "spans: {span_names:?}" ); assert!( service_names.iter().any(|s| s.contains("clawmates-test")), "services: {service_names:?}" ); }