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