datadog_api_client/datadogV2/api/
api_service_level_objectives.rs

1// Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License.
2// This product includes software developed at Datadog (https://www.datadoghq.com/).
3// Copyright 2019-Present Datadog, Inc.
4use crate::datadog;
5use flate2::{
6    write::{GzEncoder, ZlibEncoder},
7    Compression,
8};
9use log::warn;
10use reqwest::header::{HeaderMap, HeaderValue};
11use serde::{Deserialize, Serialize};
12use std::io::Write;
13
14/// CreateSLOReportJobError is a struct for typed errors of method [`ServiceLevelObjectivesAPI::create_slo_report_job`]
15#[derive(Debug, Clone, Serialize, Deserialize)]
16#[serde(untagged)]
17pub enum CreateSLOReportJobError {
18    APIErrorResponse(crate::datadogV2::model::APIErrorResponse),
19    UnknownValue(serde_json::Value),
20}
21
22/// GetSLOReportError is a struct for typed errors of method [`ServiceLevelObjectivesAPI::get_slo_report`]
23#[derive(Debug, Clone, Serialize, Deserialize)]
24#[serde(untagged)]
25pub enum GetSLOReportError {
26    APIErrorResponse(crate::datadogV2::model::APIErrorResponse),
27    UnknownValue(serde_json::Value),
28}
29
30/// GetSLOReportJobStatusError is a struct for typed errors of method [`ServiceLevelObjectivesAPI::get_slo_report_job_status`]
31#[derive(Debug, Clone, Serialize, Deserialize)]
32#[serde(untagged)]
33pub enum GetSLOReportJobStatusError {
34    APIErrorResponse(crate::datadogV2::model::APIErrorResponse),
35    UnknownValue(serde_json::Value),
36}
37
38/// [Service Level Objectives](<https://docs.datadoghq.com/monitors/service_level_objectives/#configuration>)
39/// (SLOs) are a key part of the site reliability engineering toolkit.
40/// SLOs provide a framework for defining clear targets around application performance,
41/// which ultimately help teams provide a consistent customer experience,
42/// balance feature development with platform stability,
43/// and improve communication with internal and external users.
44#[derive(Debug, Clone)]
45pub struct ServiceLevelObjectivesAPI {
46    config: datadog::Configuration,
47    client: reqwest_middleware::ClientWithMiddleware,
48}
49
50impl Default for ServiceLevelObjectivesAPI {
51    fn default() -> Self {
52        Self::with_config(datadog::Configuration::default())
53    }
54}
55
56impl ServiceLevelObjectivesAPI {
57    pub fn new() -> Self {
58        Self::default()
59    }
60    pub fn with_config(config: datadog::Configuration) -> Self {
61        let mut reqwest_client_builder = reqwest::Client::builder();
62
63        if let Some(proxy_url) = &config.proxy_url {
64            let proxy = reqwest::Proxy::all(proxy_url).expect("Failed to parse proxy URL");
65            reqwest_client_builder = reqwest_client_builder.proxy(proxy);
66        }
67
68        let mut middleware_client_builder =
69            reqwest_middleware::ClientBuilder::new(reqwest_client_builder.build().unwrap());
70
71        if config.enable_retry {
72            struct RetryableStatus;
73            impl reqwest_retry::RetryableStrategy for RetryableStatus {
74                fn handle(
75                    &self,
76                    res: &Result<reqwest::Response, reqwest_middleware::Error>,
77                ) -> Option<reqwest_retry::Retryable> {
78                    match res {
79                        Ok(success) => reqwest_retry::default_on_request_success(success),
80                        Err(_) => None,
81                    }
82                }
83            }
84            let backoff_policy = reqwest_retry::policies::ExponentialBackoff::builder()
85                .build_with_max_retries(config.max_retries);
86
87            let retry_middleware =
88                reqwest_retry::RetryTransientMiddleware::new_with_policy_and_strategy(
89                    backoff_policy,
90                    RetryableStatus,
91                );
92
93            middleware_client_builder = middleware_client_builder.with(retry_middleware);
94        }
95
96        let client = middleware_client_builder.build();
97
98        Self { config, client }
99    }
100
101    pub fn with_client_and_config(
102        config: datadog::Configuration,
103        client: reqwest_middleware::ClientWithMiddleware,
104    ) -> Self {
105        Self { config, client }
106    }
107
108    /// Create a job to generate an SLO report. The report job is processed asynchronously and eventually results in a CSV report being available for download.
109    ///
110    /// Check the status of the job and download the CSV report using the returned `report_id`.
111    pub async fn create_slo_report_job(
112        &self,
113        body: crate::datadogV2::model::SloReportCreateRequest,
114    ) -> Result<
115        crate::datadogV2::model::SLOReportPostResponse,
116        datadog::Error<CreateSLOReportJobError>,
117    > {
118        match self.create_slo_report_job_with_http_info(body).await {
119            Ok(response_content) => {
120                if let Some(e) = response_content.entity {
121                    Ok(e)
122                } else {
123                    Err(datadog::Error::Serde(serde::de::Error::custom(
124                        "response content was None",
125                    )))
126                }
127            }
128            Err(err) => Err(err),
129        }
130    }
131
132    /// Create a job to generate an SLO report. The report job is processed asynchronously and eventually results in a CSV report being available for download.
133    ///
134    /// Check the status of the job and download the CSV report using the returned `report_id`.
135    pub async fn create_slo_report_job_with_http_info(
136        &self,
137        body: crate::datadogV2::model::SloReportCreateRequest,
138    ) -> Result<
139        datadog::ResponseContent<crate::datadogV2::model::SLOReportPostResponse>,
140        datadog::Error<CreateSLOReportJobError>,
141    > {
142        let local_configuration = &self.config;
143        let operation_id = "v2.create_slo_report_job";
144        if local_configuration.is_unstable_operation_enabled(operation_id) {
145            warn!("Using unstable operation {operation_id}");
146        } else {
147            let local_error = datadog::UnstableOperationDisabledError {
148                msg: "Operation 'v2.create_slo_report_job' is not enabled".to_string(),
149            };
150            return Err(datadog::Error::UnstableOperationDisabledError(local_error));
151        }
152
153        let local_client = &self.client;
154
155        let local_uri_str = format!(
156            "{}/api/v2/slo/report",
157            local_configuration.get_operation_host(operation_id)
158        );
159        let mut local_req_builder =
160            local_client.request(reqwest::Method::POST, local_uri_str.as_str());
161
162        // build headers
163        let mut headers = HeaderMap::new();
164        headers.insert("Content-Type", HeaderValue::from_static("application/json"));
165        headers.insert("Accept", HeaderValue::from_static("application/json"));
166
167        // build user agent
168        match HeaderValue::from_str(local_configuration.user_agent.as_str()) {
169            Ok(user_agent) => headers.insert(reqwest::header::USER_AGENT, user_agent),
170            Err(e) => {
171                log::warn!("Failed to parse user agent header: {e}, falling back to default");
172                headers.insert(
173                    reqwest::header::USER_AGENT,
174                    HeaderValue::from_static(datadog::DEFAULT_USER_AGENT.as_str()),
175                )
176            }
177        };
178
179        // build auth
180        if let Some(local_key) = local_configuration.auth_keys.get("apiKeyAuth") {
181            headers.insert(
182                "DD-API-KEY",
183                HeaderValue::from_str(local_key.key.as_str())
184                    .expect("failed to parse DD-API-KEY header"),
185            );
186        };
187        if let Some(local_key) = local_configuration.auth_keys.get("appKeyAuth") {
188            headers.insert(
189                "DD-APPLICATION-KEY",
190                HeaderValue::from_str(local_key.key.as_str())
191                    .expect("failed to parse DD-APPLICATION-KEY header"),
192            );
193        };
194
195        // build body parameters
196        let output = Vec::new();
197        let mut ser = serde_json::Serializer::with_formatter(output, datadog::DDFormatter);
198        if body.serialize(&mut ser).is_ok() {
199            if let Some(content_encoding) = headers.get("Content-Encoding") {
200                match content_encoding.to_str().unwrap_or_default() {
201                    "gzip" => {
202                        let mut enc = GzEncoder::new(Vec::new(), Compression::default());
203                        let _ = enc.write_all(ser.into_inner().as_slice());
204                        match enc.finish() {
205                            Ok(buf) => {
206                                local_req_builder = local_req_builder.body(buf);
207                            }
208                            Err(e) => return Err(datadog::Error::Io(e)),
209                        }
210                    }
211                    "deflate" => {
212                        let mut enc = ZlibEncoder::new(Vec::new(), Compression::default());
213                        let _ = enc.write_all(ser.into_inner().as_slice());
214                        match enc.finish() {
215                            Ok(buf) => {
216                                local_req_builder = local_req_builder.body(buf);
217                            }
218                            Err(e) => return Err(datadog::Error::Io(e)),
219                        }
220                    }
221                    "zstd1" => {
222                        let mut enc = zstd::stream::Encoder::new(Vec::new(), 0).unwrap();
223                        let _ = enc.write_all(ser.into_inner().as_slice());
224                        match enc.finish() {
225                            Ok(buf) => {
226                                local_req_builder = local_req_builder.body(buf);
227                            }
228                            Err(e) => return Err(datadog::Error::Io(e)),
229                        }
230                    }
231                    _ => {
232                        local_req_builder = local_req_builder.body(ser.into_inner());
233                    }
234                }
235            } else {
236                local_req_builder = local_req_builder.body(ser.into_inner());
237            }
238        }
239
240        local_req_builder = local_req_builder.headers(headers);
241        let local_req = local_req_builder.build()?;
242        log::debug!("request content: {:?}", local_req.body());
243        let local_resp = local_client.execute(local_req).await?;
244
245        let local_status = local_resp.status();
246        let local_content = local_resp.text().await?;
247        log::debug!("response content: {}", local_content);
248
249        if !local_status.is_client_error() && !local_status.is_server_error() {
250            match serde_json::from_str::<crate::datadogV2::model::SLOReportPostResponse>(
251                &local_content,
252            ) {
253                Ok(e) => {
254                    return Ok(datadog::ResponseContent {
255                        status: local_status,
256                        content: local_content,
257                        entity: Some(e),
258                    })
259                }
260                Err(e) => return Err(datadog::Error::Serde(e)),
261            };
262        } else {
263            let local_entity: Option<CreateSLOReportJobError> =
264                serde_json::from_str(&local_content).ok();
265            let local_error = datadog::ResponseContent {
266                status: local_status,
267                content: local_content,
268                entity: local_entity,
269            };
270            Err(datadog::Error::ResponseError(local_error))
271        }
272    }
273
274    /// Download an SLO report. This can only be performed after the report job has completed.
275    ///
276    /// Reports are not guaranteed to exist indefinitely. Datadog recommends that you download the report as soon as it is available.
277    pub async fn get_slo_report(
278        &self,
279        report_id: String,
280    ) -> Result<String, datadog::Error<GetSLOReportError>> {
281        match self.get_slo_report_with_http_info(report_id).await {
282            Ok(response_content) => {
283                if let Some(e) = response_content.entity {
284                    Ok(e)
285                } else {
286                    Err(datadog::Error::Serde(serde::de::Error::custom(
287                        "response content was None",
288                    )))
289                }
290            }
291            Err(err) => Err(err),
292        }
293    }
294
295    /// Download an SLO report. This can only be performed after the report job has completed.
296    ///
297    /// Reports are not guaranteed to exist indefinitely. Datadog recommends that you download the report as soon as it is available.
298    pub async fn get_slo_report_with_http_info(
299        &self,
300        report_id: String,
301    ) -> Result<datadog::ResponseContent<String>, datadog::Error<GetSLOReportError>> {
302        let local_configuration = &self.config;
303        let operation_id = "v2.get_slo_report";
304        if local_configuration.is_unstable_operation_enabled(operation_id) {
305            warn!("Using unstable operation {operation_id}");
306        } else {
307            let local_error = datadog::UnstableOperationDisabledError {
308                msg: "Operation 'v2.get_slo_report' is not enabled".to_string(),
309            };
310            return Err(datadog::Error::UnstableOperationDisabledError(local_error));
311        }
312
313        let local_client = &self.client;
314
315        let local_uri_str = format!(
316            "{}/api/v2/slo/report/{report_id}/download",
317            local_configuration.get_operation_host(operation_id),
318            report_id = datadog::urlencode(report_id)
319        );
320        let mut local_req_builder =
321            local_client.request(reqwest::Method::GET, local_uri_str.as_str());
322
323        // build headers
324        let mut headers = HeaderMap::new();
325        headers.insert("Accept", HeaderValue::from_static("application/json"));
326
327        // build user agent
328        match HeaderValue::from_str(local_configuration.user_agent.as_str()) {
329            Ok(user_agent) => headers.insert(reqwest::header::USER_AGENT, user_agent),
330            Err(e) => {
331                log::warn!("Failed to parse user agent header: {e}, falling back to default");
332                headers.insert(
333                    reqwest::header::USER_AGENT,
334                    HeaderValue::from_static(datadog::DEFAULT_USER_AGENT.as_str()),
335                )
336            }
337        };
338
339        // build auth
340        if let Some(local_key) = local_configuration.auth_keys.get("apiKeyAuth") {
341            headers.insert(
342                "DD-API-KEY",
343                HeaderValue::from_str(local_key.key.as_str())
344                    .expect("failed to parse DD-API-KEY header"),
345            );
346        };
347        if let Some(local_key) = local_configuration.auth_keys.get("appKeyAuth") {
348            headers.insert(
349                "DD-APPLICATION-KEY",
350                HeaderValue::from_str(local_key.key.as_str())
351                    .expect("failed to parse DD-APPLICATION-KEY header"),
352            );
353        };
354
355        local_req_builder = local_req_builder.headers(headers);
356        let local_req = local_req_builder.build()?;
357        log::debug!("request content: {:?}", local_req.body());
358        let local_resp = local_client.execute(local_req).await?;
359
360        let local_status = local_resp.status();
361        let local_content = local_resp.text().await?;
362        log::debug!("response content: {}", local_content);
363
364        if !local_status.is_client_error() && !local_status.is_server_error() {
365            match serde_json::from_str::<String>(&local_content) {
366                Ok(e) => {
367                    return Ok(datadog::ResponseContent {
368                        status: local_status,
369                        content: local_content,
370                        entity: Some(e),
371                    })
372                }
373                Err(e) => return Err(datadog::Error::Serde(e)),
374            };
375        } else {
376            let local_entity: Option<GetSLOReportError> = serde_json::from_str(&local_content).ok();
377            let local_error = datadog::ResponseContent {
378                status: local_status,
379                content: local_content,
380                entity: local_entity,
381            };
382            Err(datadog::Error::ResponseError(local_error))
383        }
384    }
385
386    /// Get the status of the SLO report job.
387    pub async fn get_slo_report_job_status(
388        &self,
389        report_id: String,
390    ) -> Result<
391        crate::datadogV2::model::SLOReportStatusGetResponse,
392        datadog::Error<GetSLOReportJobStatusError>,
393    > {
394        match self
395            .get_slo_report_job_status_with_http_info(report_id)
396            .await
397        {
398            Ok(response_content) => {
399                if let Some(e) = response_content.entity {
400                    Ok(e)
401                } else {
402                    Err(datadog::Error::Serde(serde::de::Error::custom(
403                        "response content was None",
404                    )))
405                }
406            }
407            Err(err) => Err(err),
408        }
409    }
410
411    /// Get the status of the SLO report job.
412    pub async fn get_slo_report_job_status_with_http_info(
413        &self,
414        report_id: String,
415    ) -> Result<
416        datadog::ResponseContent<crate::datadogV2::model::SLOReportStatusGetResponse>,
417        datadog::Error<GetSLOReportJobStatusError>,
418    > {
419        let local_configuration = &self.config;
420        let operation_id = "v2.get_slo_report_job_status";
421        if local_configuration.is_unstable_operation_enabled(operation_id) {
422            warn!("Using unstable operation {operation_id}");
423        } else {
424            let local_error = datadog::UnstableOperationDisabledError {
425                msg: "Operation 'v2.get_slo_report_job_status' is not enabled".to_string(),
426            };
427            return Err(datadog::Error::UnstableOperationDisabledError(local_error));
428        }
429
430        let local_client = &self.client;
431
432        let local_uri_str = format!(
433            "{}/api/v2/slo/report/{report_id}/status",
434            local_configuration.get_operation_host(operation_id),
435            report_id = datadog::urlencode(report_id)
436        );
437        let mut local_req_builder =
438            local_client.request(reqwest::Method::GET, local_uri_str.as_str());
439
440        // build headers
441        let mut headers = HeaderMap::new();
442        headers.insert("Accept", HeaderValue::from_static("application/json"));
443
444        // build user agent
445        match HeaderValue::from_str(local_configuration.user_agent.as_str()) {
446            Ok(user_agent) => headers.insert(reqwest::header::USER_AGENT, user_agent),
447            Err(e) => {
448                log::warn!("Failed to parse user agent header: {e}, falling back to default");
449                headers.insert(
450                    reqwest::header::USER_AGENT,
451                    HeaderValue::from_static(datadog::DEFAULT_USER_AGENT.as_str()),
452                )
453            }
454        };
455
456        // build auth
457        if let Some(local_key) = local_configuration.auth_keys.get("apiKeyAuth") {
458            headers.insert(
459                "DD-API-KEY",
460                HeaderValue::from_str(local_key.key.as_str())
461                    .expect("failed to parse DD-API-KEY header"),
462            );
463        };
464        if let Some(local_key) = local_configuration.auth_keys.get("appKeyAuth") {
465            headers.insert(
466                "DD-APPLICATION-KEY",
467                HeaderValue::from_str(local_key.key.as_str())
468                    .expect("failed to parse DD-APPLICATION-KEY header"),
469            );
470        };
471
472        local_req_builder = local_req_builder.headers(headers);
473        let local_req = local_req_builder.build()?;
474        log::debug!("request content: {:?}", local_req.body());
475        let local_resp = local_client.execute(local_req).await?;
476
477        let local_status = local_resp.status();
478        let local_content = local_resp.text().await?;
479        log::debug!("response content: {}", local_content);
480
481        if !local_status.is_client_error() && !local_status.is_server_error() {
482            match serde_json::from_str::<crate::datadogV2::model::SLOReportStatusGetResponse>(
483                &local_content,
484            ) {
485                Ok(e) => {
486                    return Ok(datadog::ResponseContent {
487                        status: local_status,
488                        content: local_content,
489                        entity: Some(e),
490                    })
491                }
492                Err(e) => return Err(datadog::Error::Serde(e)),
493            };
494        } else {
495            let local_entity: Option<GetSLOReportJobStatusError> =
496                serde_json::from_str(&local_content).ok();
497            let local_error = datadog::ResponseContent {
498                status: local_status,
499                content: local_content,
500                entity: local_entity,
501            };
502            Err(datadog::Error::ResponseError(local_error))
503        }
504    }
505}