opentelemetry_otlp/exporter/http/
trace.rs1use std::sync::Arc;
2
3use super::OtlpHttpClient;
4use futures_core::future::BoxFuture;
5use http::{header::CONTENT_TYPE, Method};
6use opentelemetry::otel_debug;
7use opentelemetry_sdk::{
8 error::{OTelSdkError, OTelSdkResult},
9 trace::{SpanData, SpanExporter},
10};
11
12impl SpanExporter for OtlpHttpClient {
13 fn export(&mut self, batch: Vec<SpanData>) -> BoxFuture<'static, OTelSdkResult> {
14 let client = match self
15 .client
16 .lock()
17 .map_err(|e| OTelSdkError::InternalFailure(format!("Mutex lock failed: {}", e)))
18 .and_then(|g| match &*g {
19 Some(client) => Ok(Arc::clone(client)),
20 _ => Err(OTelSdkError::AlreadyShutdown),
21 }) {
22 Ok(client) => client,
23 Err(err) => return Box::pin(std::future::ready(Err(err))),
24 };
25
26 let (body, content_type) = match self.build_trace_export_body(batch) {
27 Ok(body) => body,
28 Err(e) => {
29 return Box::pin(std::future::ready(Err(OTelSdkError::InternalFailure(
30 e.to_string(),
31 ))))
32 }
33 };
34
35 let mut request = match http::Request::builder()
36 .method(Method::POST)
37 .uri(&self.collector_endpoint)
38 .header(CONTENT_TYPE, content_type)
39 .body(body.into())
40 {
41 Ok(req) => req,
42 Err(e) => {
43 return Box::pin(std::future::ready(Err(OTelSdkError::InternalFailure(
44 e.to_string(),
45 ))))
46 }
47 };
48
49 for (k, v) in &self.headers {
50 request.headers_mut().insert(k.clone(), v.clone());
51 }
52
53 Box::pin(async move {
54 let request_uri = request.uri().to_string();
55 otel_debug!(name: "HttpTracesClient.CallingExport");
56 let response = client
57 .send_bytes(request)
58 .await
59 .map_err(|e| OTelSdkError::InternalFailure(format!("{e:?}")))?;
60
61 if !response.status().is_success() {
62 let error = format!(
63 "OpenTelemetry trace export failed. Url: {}, Status Code: {}, Response: {:?}",
64 response.status().as_u16(),
65 request_uri,
66 response.body()
67 );
68 return Err(OTelSdkError::InternalFailure(error));
69 }
70
71 Ok(())
72 })
73 }
74
75 fn shutdown(&mut self) -> OTelSdkResult {
76 let mut client_guard = self.client.lock().map_err(|e| {
77 OTelSdkError::InternalFailure(format!("Failed to acquire client lock: {}", e))
78 })?;
79
80 if client_guard.take().is_none() {
81 return Err(OTelSdkError::AlreadyShutdown);
82 }
83
84 Ok(())
85 }
86
87 fn set_resource(&mut self, resource: &opentelemetry_sdk::Resource) {
88 self.resource = resource.into();
89 }
90}