#![cfg(feature = "otlp")]
use std::{collections::BTreeMap, time::Duration};
use rs_zero::observability::{OtlpProtocol, OtlpTraceConfig, install_otlp_tracing};
use tokio::net::TcpStream;
use tracing::{Level, span};
#[tokio::test]
#[ignore = "requires external OTLP collector from examples/production-adapters/docker-compose.external.yml"]
async fn observability_otlp_external_exports_span_and_shutdowns() {
let endpoint = std::env::var("RS_ZERO_OTLP_ENDPOINT")
.unwrap_or_else(|_| "http://127.0.0.1:14318".to_string());
assert_collector_port_is_open(&endpoint).await;
let mut resource = BTreeMap::new();
resource.insert(
"service.name".to_string(),
"rs-zero-otlp-external".to_string(),
);
let handle = install_otlp_tracing(
OtlpTraceConfig {
endpoint: http_trace_endpoint(&endpoint),
protocol: OtlpProtocol::HttpProtobuf,
resource,
timeout: Duration::from_secs(5),
..OtlpTraceConfig::default()
},
"info".to_string(),
)
.expect("install otlp tracing");
let span = span!(Level::INFO, "rs_zero_otlp_external", adapter = "otlp");
let entered = span.enter();
tracing::info!(event = "external_otlp_probe", "sending external otlp span");
drop(entered);
drop(span);
handle.flush().expect("flush otlp spans");
handle.shutdown().expect("shutdown otlp exporter");
}
async fn assert_collector_port_is_open(endpoint: &str) {
let authority = endpoint_authority(endpoint);
TcpStream::connect(&authority)
.await
.unwrap_or_else(|error| panic!("connect OTLP collector at {authority}: {error}"));
}
fn http_trace_endpoint(endpoint: &str) -> String {
let scheme = if endpoint.starts_with("https://") {
"https"
} else {
"http"
};
format!("{scheme}://{}/v1/traces", endpoint_authority(endpoint))
}
fn endpoint_authority(endpoint: &str) -> String {
endpoint
.strip_prefix("http://")
.or_else(|| endpoint.strip_prefix("https://"))
.unwrap_or(endpoint)
.split('/')
.next()
.unwrap_or(endpoint)
.to_string()
}