1use crate::datadog;
5use async_stream::try_stream;
6use flate2::{
7 write::{GzEncoder, ZlibEncoder},
8 Compression,
9};
10use futures_core::stream::Stream;
11use reqwest::header::{HeaderMap, HeaderValue};
12use serde::{Deserialize, Serialize};
13use std::io::Write;
14
15#[non_exhaustive]
17#[derive(Clone, Default, Debug)]
18pub struct ListSpansGetOptionalParams {
19 pub filter_query: Option<String>,
21 pub filter_from: Option<String>,
23 pub filter_to: Option<String>,
25 pub sort: Option<crate::datadogV2::model::SpansSort>,
27 pub page_cursor: Option<String>,
29 pub page_limit: Option<i32>,
31}
32
33impl ListSpansGetOptionalParams {
34 pub fn filter_query(mut self, value: String) -> Self {
36 self.filter_query = Some(value);
37 self
38 }
39 pub fn filter_from(mut self, value: String) -> Self {
41 self.filter_from = Some(value);
42 self
43 }
44 pub fn filter_to(mut self, value: String) -> Self {
46 self.filter_to = Some(value);
47 self
48 }
49 pub fn sort(mut self, value: crate::datadogV2::model::SpansSort) -> Self {
51 self.sort = Some(value);
52 self
53 }
54 pub fn page_cursor(mut self, value: String) -> Self {
56 self.page_cursor = Some(value);
57 self
58 }
59 pub fn page_limit(mut self, value: i32) -> Self {
61 self.page_limit = Some(value);
62 self
63 }
64}
65
66#[derive(Debug, Clone, Serialize, Deserialize)]
68#[serde(untagged)]
69pub enum AggregateSpansError {
70 APIErrorResponse(crate::datadogV2::model::APIErrorResponse),
71 UnknownValue(serde_json::Value),
72}
73
74#[derive(Debug, Clone, Serialize, Deserialize)]
76#[serde(untagged)]
77pub enum ListSpansError {
78 JSONAPIErrorResponse(crate::datadogV2::model::JSONAPIErrorResponse),
79 UnknownValue(serde_json::Value),
80}
81
82#[derive(Debug, Clone, Serialize, Deserialize)]
84#[serde(untagged)]
85pub enum ListSpansGetError {
86 JSONAPIErrorResponse(crate::datadogV2::model::JSONAPIErrorResponse),
87 UnknownValue(serde_json::Value),
88}
89
90#[derive(Debug, Clone)]
92pub struct SpansAPI {
93 config: datadog::Configuration,
94 client: reqwest_middleware::ClientWithMiddleware,
95}
96
97impl Default for SpansAPI {
98 fn default() -> Self {
99 Self::with_config(datadog::Configuration::default())
100 }
101}
102
103impl SpansAPI {
104 pub fn new() -> Self {
105 Self::default()
106 }
107 pub fn with_config(config: datadog::Configuration) -> Self {
108 let mut reqwest_client_builder = reqwest::Client::builder();
109
110 if let Some(proxy_url) = &config.proxy_url {
111 let proxy = reqwest::Proxy::all(proxy_url).expect("Failed to parse proxy URL");
112 reqwest_client_builder = reqwest_client_builder.proxy(proxy);
113 }
114
115 let mut middleware_client_builder =
116 reqwest_middleware::ClientBuilder::new(reqwest_client_builder.build().unwrap());
117
118 if config.enable_retry {
119 struct RetryableStatus;
120 impl reqwest_retry::RetryableStrategy for RetryableStatus {
121 fn handle(
122 &self,
123 res: &Result<reqwest::Response, reqwest_middleware::Error>,
124 ) -> Option<reqwest_retry::Retryable> {
125 match res {
126 Ok(success) => reqwest_retry::default_on_request_success(success),
127 Err(_) => None,
128 }
129 }
130 }
131 let backoff_policy = reqwest_retry::policies::ExponentialBackoff::builder()
132 .build_with_max_retries(config.max_retries);
133
134 let retry_middleware =
135 reqwest_retry::RetryTransientMiddleware::new_with_policy_and_strategy(
136 backoff_policy,
137 RetryableStatus,
138 );
139
140 middleware_client_builder = middleware_client_builder.with(retry_middleware);
141 }
142
143 let client = middleware_client_builder.build();
144
145 Self { config, client }
146 }
147
148 pub fn with_client_and_config(
149 config: datadog::Configuration,
150 client: reqwest_middleware::ClientWithMiddleware,
151 ) -> Self {
152 Self { config, client }
153 }
154
155 pub async fn aggregate_spans(
158 &self,
159 body: crate::datadogV2::model::SpansAggregateRequest,
160 ) -> Result<crate::datadogV2::model::SpansAggregateResponse, datadog::Error<AggregateSpansError>>
161 {
162 match self.aggregate_spans_with_http_info(body).await {
163 Ok(response_content) => {
164 if let Some(e) = response_content.entity {
165 Ok(e)
166 } else {
167 Err(datadog::Error::Serde(serde::de::Error::custom(
168 "response content was None",
169 )))
170 }
171 }
172 Err(err) => Err(err),
173 }
174 }
175
176 pub async fn aggregate_spans_with_http_info(
179 &self,
180 body: crate::datadogV2::model::SpansAggregateRequest,
181 ) -> Result<
182 datadog::ResponseContent<crate::datadogV2::model::SpansAggregateResponse>,
183 datadog::Error<AggregateSpansError>,
184 > {
185 let local_configuration = &self.config;
186 let operation_id = "v2.aggregate_spans";
187
188 let local_client = &self.client;
189
190 let local_uri_str = format!(
191 "{}/api/v2/spans/analytics/aggregate",
192 local_configuration.get_operation_host(operation_id)
193 );
194 let mut local_req_builder =
195 local_client.request(reqwest::Method::POST, local_uri_str.as_str());
196
197 let mut headers = HeaderMap::new();
199 headers.insert("Content-Type", HeaderValue::from_static("application/json"));
200 headers.insert("Accept", HeaderValue::from_static("application/json"));
201
202 match HeaderValue::from_str(local_configuration.user_agent.as_str()) {
204 Ok(user_agent) => headers.insert(reqwest::header::USER_AGENT, user_agent),
205 Err(e) => {
206 log::warn!("Failed to parse user agent header: {e}, falling back to default");
207 headers.insert(
208 reqwest::header::USER_AGENT,
209 HeaderValue::from_static(datadog::DEFAULT_USER_AGENT.as_str()),
210 )
211 }
212 };
213
214 if let Some(local_key) = local_configuration.auth_keys.get("apiKeyAuth") {
216 headers.insert(
217 "DD-API-KEY",
218 HeaderValue::from_str(local_key.key.as_str())
219 .expect("failed to parse DD-API-KEY header"),
220 );
221 };
222 if let Some(local_key) = local_configuration.auth_keys.get("appKeyAuth") {
223 headers.insert(
224 "DD-APPLICATION-KEY",
225 HeaderValue::from_str(local_key.key.as_str())
226 .expect("failed to parse DD-APPLICATION-KEY header"),
227 );
228 };
229
230 let output = Vec::new();
232 let mut ser = serde_json::Serializer::with_formatter(output, datadog::DDFormatter);
233 if body.serialize(&mut ser).is_ok() {
234 if let Some(content_encoding) = headers.get("Content-Encoding") {
235 match content_encoding.to_str().unwrap_or_default() {
236 "gzip" => {
237 let mut enc = GzEncoder::new(Vec::new(), Compression::default());
238 let _ = enc.write_all(ser.into_inner().as_slice());
239 match enc.finish() {
240 Ok(buf) => {
241 local_req_builder = local_req_builder.body(buf);
242 }
243 Err(e) => return Err(datadog::Error::Io(e)),
244 }
245 }
246 "deflate" => {
247 let mut enc = ZlibEncoder::new(Vec::new(), Compression::default());
248 let _ = enc.write_all(ser.into_inner().as_slice());
249 match enc.finish() {
250 Ok(buf) => {
251 local_req_builder = local_req_builder.body(buf);
252 }
253 Err(e) => return Err(datadog::Error::Io(e)),
254 }
255 }
256 "zstd1" => {
257 let mut enc = zstd::stream::Encoder::new(Vec::new(), 0).unwrap();
258 let _ = enc.write_all(ser.into_inner().as_slice());
259 match enc.finish() {
260 Ok(buf) => {
261 local_req_builder = local_req_builder.body(buf);
262 }
263 Err(e) => return Err(datadog::Error::Io(e)),
264 }
265 }
266 _ => {
267 local_req_builder = local_req_builder.body(ser.into_inner());
268 }
269 }
270 } else {
271 local_req_builder = local_req_builder.body(ser.into_inner());
272 }
273 }
274
275 local_req_builder = local_req_builder.headers(headers);
276 let local_req = local_req_builder.build()?;
277 log::debug!("request content: {:?}", local_req.body());
278 let local_resp = local_client.execute(local_req).await?;
279
280 let local_status = local_resp.status();
281 let local_content = local_resp.text().await?;
282 log::debug!("response content: {}", local_content);
283
284 if !local_status.is_client_error() && !local_status.is_server_error() {
285 match serde_json::from_str::<crate::datadogV2::model::SpansAggregateResponse>(
286 &local_content,
287 ) {
288 Ok(e) => {
289 return Ok(datadog::ResponseContent {
290 status: local_status,
291 content: local_content,
292 entity: Some(e),
293 })
294 }
295 Err(e) => return Err(datadog::Error::Serde(e)),
296 };
297 } else {
298 let local_entity: Option<AggregateSpansError> =
299 serde_json::from_str(&local_content).ok();
300 let local_error = datadog::ResponseContent {
301 status: local_status,
302 content: local_content,
303 entity: local_entity,
304 };
305 Err(datadog::Error::ResponseError(local_error))
306 }
307 }
308
309 pub async fn list_spans(
317 &self,
318 body: crate::datadogV2::model::SpansListRequest,
319 ) -> Result<crate::datadogV2::model::SpansListResponse, datadog::Error<ListSpansError>> {
320 match self.list_spans_with_http_info(body).await {
321 Ok(response_content) => {
322 if let Some(e) = response_content.entity {
323 Ok(e)
324 } else {
325 Err(datadog::Error::Serde(serde::de::Error::custom(
326 "response content was None",
327 )))
328 }
329 }
330 Err(err) => Err(err),
331 }
332 }
333
334 pub fn list_spans_with_pagination(
335 &self,
336 mut body: crate::datadogV2::model::SpansListRequest,
337 ) -> impl Stream<Item = Result<crate::datadogV2::model::Span, datadog::Error<ListSpansError>>> + '_
338 {
339 try_stream! {
340 let mut page_size: i32 = 10;
341 if body.data.is_none() {
342 body.data = Some(crate::datadogV2::model::SpansListRequestData::new());
343 }
344 if body.data.as_ref().unwrap().attributes.is_none() {
345 body.data.as_mut().unwrap().attributes = Some(crate::datadogV2::model::SpansListRequestAttributes::new());
346 }
347 if body.data.as_ref().unwrap().attributes.as_ref().unwrap().page.is_none() {
348 body.data.as_mut().unwrap().attributes.as_mut().unwrap().page = Some(crate::datadogV2::model::SpansListRequestPage::new());
349 }
350 if body.data.as_ref().unwrap().attributes.as_ref().unwrap().page.as_ref().unwrap().limit.is_none() {
351 body.data.as_mut().unwrap().attributes.as_mut().unwrap().page.as_mut().unwrap().limit = Some(page_size);
352 } else {
353 page_size = body.data.as_ref().unwrap().attributes.as_ref().unwrap().page.as_ref().unwrap().limit.unwrap().clone();
354 }
355 loop {
356 let resp = self.list_spans( body.clone(),).await?;
357 let Some(data) = resp.data else { break };
358
359 let r = data;
360 let count = r.len();
361 for team in r {
362 yield team;
363 }
364
365 if count < page_size as usize {
366 break;
367 }
368 let Some(meta) = resp.meta else { break };
369 let Some(page) = meta.page else { break };
370 let Some(after) = page.after else { break };
371
372 body.data.as_mut().unwrap().attributes.as_mut().unwrap().page.as_mut().unwrap().cursor = Some(after);
373 }
374 }
375 }
376
377 pub async fn list_spans_with_http_info(
385 &self,
386 body: crate::datadogV2::model::SpansListRequest,
387 ) -> Result<
388 datadog::ResponseContent<crate::datadogV2::model::SpansListResponse>,
389 datadog::Error<ListSpansError>,
390 > {
391 let local_configuration = &self.config;
392 let operation_id = "v2.list_spans";
393
394 let local_client = &self.client;
395
396 let local_uri_str = format!(
397 "{}/api/v2/spans/events/search",
398 local_configuration.get_operation_host(operation_id)
399 );
400 let mut local_req_builder =
401 local_client.request(reqwest::Method::POST, local_uri_str.as_str());
402
403 let mut headers = HeaderMap::new();
405 headers.insert("Content-Type", HeaderValue::from_static("application/json"));
406 headers.insert("Accept", HeaderValue::from_static("application/json"));
407
408 match HeaderValue::from_str(local_configuration.user_agent.as_str()) {
410 Ok(user_agent) => headers.insert(reqwest::header::USER_AGENT, user_agent),
411 Err(e) => {
412 log::warn!("Failed to parse user agent header: {e}, falling back to default");
413 headers.insert(
414 reqwest::header::USER_AGENT,
415 HeaderValue::from_static(datadog::DEFAULT_USER_AGENT.as_str()),
416 )
417 }
418 };
419
420 if let Some(local_key) = local_configuration.auth_keys.get("apiKeyAuth") {
422 headers.insert(
423 "DD-API-KEY",
424 HeaderValue::from_str(local_key.key.as_str())
425 .expect("failed to parse DD-API-KEY header"),
426 );
427 };
428 if let Some(local_key) = local_configuration.auth_keys.get("appKeyAuth") {
429 headers.insert(
430 "DD-APPLICATION-KEY",
431 HeaderValue::from_str(local_key.key.as_str())
432 .expect("failed to parse DD-APPLICATION-KEY header"),
433 );
434 };
435
436 let output = Vec::new();
438 let mut ser = serde_json::Serializer::with_formatter(output, datadog::DDFormatter);
439 if body.serialize(&mut ser).is_ok() {
440 if let Some(content_encoding) = headers.get("Content-Encoding") {
441 match content_encoding.to_str().unwrap_or_default() {
442 "gzip" => {
443 let mut enc = GzEncoder::new(Vec::new(), Compression::default());
444 let _ = enc.write_all(ser.into_inner().as_slice());
445 match enc.finish() {
446 Ok(buf) => {
447 local_req_builder = local_req_builder.body(buf);
448 }
449 Err(e) => return Err(datadog::Error::Io(e)),
450 }
451 }
452 "deflate" => {
453 let mut enc = ZlibEncoder::new(Vec::new(), Compression::default());
454 let _ = enc.write_all(ser.into_inner().as_slice());
455 match enc.finish() {
456 Ok(buf) => {
457 local_req_builder = local_req_builder.body(buf);
458 }
459 Err(e) => return Err(datadog::Error::Io(e)),
460 }
461 }
462 "zstd1" => {
463 let mut enc = zstd::stream::Encoder::new(Vec::new(), 0).unwrap();
464 let _ = enc.write_all(ser.into_inner().as_slice());
465 match enc.finish() {
466 Ok(buf) => {
467 local_req_builder = local_req_builder.body(buf);
468 }
469 Err(e) => return Err(datadog::Error::Io(e)),
470 }
471 }
472 _ => {
473 local_req_builder = local_req_builder.body(ser.into_inner());
474 }
475 }
476 } else {
477 local_req_builder = local_req_builder.body(ser.into_inner());
478 }
479 }
480
481 local_req_builder = local_req_builder.headers(headers);
482 let local_req = local_req_builder.build()?;
483 log::debug!("request content: {:?}", local_req.body());
484 let local_resp = local_client.execute(local_req).await?;
485
486 let local_status = local_resp.status();
487 let local_content = local_resp.text().await?;
488 log::debug!("response content: {}", local_content);
489
490 if !local_status.is_client_error() && !local_status.is_server_error() {
491 match serde_json::from_str::<crate::datadogV2::model::SpansListResponse>(&local_content)
492 {
493 Ok(e) => {
494 return Ok(datadog::ResponseContent {
495 status: local_status,
496 content: local_content,
497 entity: Some(e),
498 })
499 }
500 Err(e) => return Err(datadog::Error::Serde(e)),
501 };
502 } else {
503 let local_entity: Option<ListSpansError> = serde_json::from_str(&local_content).ok();
504 let local_error = datadog::ResponseContent {
505 status: local_status,
506 content: local_content,
507 entity: local_entity,
508 };
509 Err(datadog::Error::ResponseError(local_error))
510 }
511 }
512
513 pub async fn list_spans_get(
521 &self,
522 params: ListSpansGetOptionalParams,
523 ) -> Result<crate::datadogV2::model::SpansListResponse, datadog::Error<ListSpansGetError>> {
524 match self.list_spans_get_with_http_info(params).await {
525 Ok(response_content) => {
526 if let Some(e) = response_content.entity {
527 Ok(e)
528 } else {
529 Err(datadog::Error::Serde(serde::de::Error::custom(
530 "response content was None",
531 )))
532 }
533 }
534 Err(err) => Err(err),
535 }
536 }
537
538 pub fn list_spans_get_with_pagination(
539 &self,
540 mut params: ListSpansGetOptionalParams,
541 ) -> impl Stream<Item = Result<crate::datadogV2::model::Span, datadog::Error<ListSpansGetError>>> + '_
542 {
543 try_stream! {
544 let mut page_size: i32 = 10;
545 if params.page_limit.is_none() {
546 params.page_limit = Some(page_size);
547 } else {
548 page_size = params.page_limit.unwrap().clone();
549 }
550 loop {
551 let resp = self.list_spans_get(params.clone()).await?;
552 let Some(data) = resp.data else { break };
553
554 let r = data;
555 let count = r.len();
556 for team in r {
557 yield team;
558 }
559
560 if count < page_size as usize {
561 break;
562 }
563 let Some(meta) = resp.meta else { break };
564 let Some(page) = meta.page else { break };
565 let Some(after) = page.after else { break };
566
567 params.page_cursor = Some(after);
568 }
569 }
570 }
571
572 pub async fn list_spans_get_with_http_info(
580 &self,
581 params: ListSpansGetOptionalParams,
582 ) -> Result<
583 datadog::ResponseContent<crate::datadogV2::model::SpansListResponse>,
584 datadog::Error<ListSpansGetError>,
585 > {
586 let local_configuration = &self.config;
587 let operation_id = "v2.list_spans_get";
588
589 let filter_query = params.filter_query;
591 let filter_from = params.filter_from;
592 let filter_to = params.filter_to;
593 let sort = params.sort;
594 let page_cursor = params.page_cursor;
595 let page_limit = params.page_limit;
596
597 let local_client = &self.client;
598
599 let local_uri_str = format!(
600 "{}/api/v2/spans/events",
601 local_configuration.get_operation_host(operation_id)
602 );
603 let mut local_req_builder =
604 local_client.request(reqwest::Method::GET, local_uri_str.as_str());
605
606 if let Some(ref local_query_param) = filter_query {
607 local_req_builder =
608 local_req_builder.query(&[("filter[query]", &local_query_param.to_string())]);
609 };
610 if let Some(ref local_query_param) = filter_from {
611 local_req_builder =
612 local_req_builder.query(&[("filter[from]", &local_query_param.to_string())]);
613 };
614 if let Some(ref local_query_param) = filter_to {
615 local_req_builder =
616 local_req_builder.query(&[("filter[to]", &local_query_param.to_string())]);
617 };
618 if let Some(ref local_query_param) = sort {
619 local_req_builder =
620 local_req_builder.query(&[("sort", &local_query_param.to_string())]);
621 };
622 if let Some(ref local_query_param) = page_cursor {
623 local_req_builder =
624 local_req_builder.query(&[("page[cursor]", &local_query_param.to_string())]);
625 };
626 if let Some(ref local_query_param) = page_limit {
627 local_req_builder =
628 local_req_builder.query(&[("page[limit]", &local_query_param.to_string())]);
629 };
630
631 let mut headers = HeaderMap::new();
633 headers.insert("Accept", HeaderValue::from_static("application/json"));
634
635 match HeaderValue::from_str(local_configuration.user_agent.as_str()) {
637 Ok(user_agent) => headers.insert(reqwest::header::USER_AGENT, user_agent),
638 Err(e) => {
639 log::warn!("Failed to parse user agent header: {e}, falling back to default");
640 headers.insert(
641 reqwest::header::USER_AGENT,
642 HeaderValue::from_static(datadog::DEFAULT_USER_AGENT.as_str()),
643 )
644 }
645 };
646
647 if let Some(local_key) = local_configuration.auth_keys.get("apiKeyAuth") {
649 headers.insert(
650 "DD-API-KEY",
651 HeaderValue::from_str(local_key.key.as_str())
652 .expect("failed to parse DD-API-KEY header"),
653 );
654 };
655 if let Some(local_key) = local_configuration.auth_keys.get("appKeyAuth") {
656 headers.insert(
657 "DD-APPLICATION-KEY",
658 HeaderValue::from_str(local_key.key.as_str())
659 .expect("failed to parse DD-APPLICATION-KEY header"),
660 );
661 };
662
663 local_req_builder = local_req_builder.headers(headers);
664 let local_req = local_req_builder.build()?;
665 log::debug!("request content: {:?}", local_req.body());
666 let local_resp = local_client.execute(local_req).await?;
667
668 let local_status = local_resp.status();
669 let local_content = local_resp.text().await?;
670 log::debug!("response content: {}", local_content);
671
672 if !local_status.is_client_error() && !local_status.is_server_error() {
673 match serde_json::from_str::<crate::datadogV2::model::SpansListResponse>(&local_content)
674 {
675 Ok(e) => {
676 return Ok(datadog::ResponseContent {
677 status: local_status,
678 content: local_content,
679 entity: Some(e),
680 })
681 }
682 Err(e) => return Err(datadog::Error::Serde(e)),
683 };
684 } else {
685 let local_entity: Option<ListSpansGetError> = serde_json::from_str(&local_content).ok();
686 let local_error = datadog::ResponseContent {
687 status: local_status,
688 content: local_content,
689 entity: local_entity,
690 };
691 Err(datadog::Error::ResponseError(local_error))
692 }
693 }
694}