datadog_api_client/datadogV2/api/
api_audit.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 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/// ListAuditLogsOptionalParams is a struct for passing parameters to the method [`AuditAPI::list_audit_logs`]
16#[non_exhaustive]
17#[derive(Clone, Default, Debug)]
18pub struct ListAuditLogsOptionalParams {
19    /// Search query following Audit Logs syntax.
20    pub filter_query: Option<String>,
21    /// Minimum timestamp for requested events.
22    pub filter_from: Option<chrono::DateTime<chrono::Utc>>,
23    /// Maximum timestamp for requested events.
24    pub filter_to: Option<chrono::DateTime<chrono::Utc>>,
25    /// Order of events in results.
26    pub sort: Option<crate::datadogV2::model::AuditLogsSort>,
27    /// List following results with a cursor provided in the previous query.
28    pub page_cursor: Option<String>,
29    /// Maximum number of events in the response.
30    pub page_limit: Option<i32>,
31}
32
33impl ListAuditLogsOptionalParams {
34    /// Search query following Audit Logs syntax.
35    pub fn filter_query(mut self, value: String) -> Self {
36        self.filter_query = Some(value);
37        self
38    }
39    /// Minimum timestamp for requested events.
40    pub fn filter_from(mut self, value: chrono::DateTime<chrono::Utc>) -> Self {
41        self.filter_from = Some(value);
42        self
43    }
44    /// Maximum timestamp for requested events.
45    pub fn filter_to(mut self, value: chrono::DateTime<chrono::Utc>) -> Self {
46        self.filter_to = Some(value);
47        self
48    }
49    /// Order of events in results.
50    pub fn sort(mut self, value: crate::datadogV2::model::AuditLogsSort) -> Self {
51        self.sort = Some(value);
52        self
53    }
54    /// List following results with a cursor provided in the previous query.
55    pub fn page_cursor(mut self, value: String) -> Self {
56        self.page_cursor = Some(value);
57        self
58    }
59    /// Maximum number of events in the response.
60    pub fn page_limit(mut self, value: i32) -> Self {
61        self.page_limit = Some(value);
62        self
63    }
64}
65
66/// SearchAuditLogsOptionalParams is a struct for passing parameters to the method [`AuditAPI::search_audit_logs`]
67#[non_exhaustive]
68#[derive(Clone, Default, Debug)]
69pub struct SearchAuditLogsOptionalParams {
70    pub body: Option<crate::datadogV2::model::AuditLogsSearchEventsRequest>,
71}
72
73impl SearchAuditLogsOptionalParams {
74    pub fn body(mut self, value: crate::datadogV2::model::AuditLogsSearchEventsRequest) -> Self {
75        self.body = Some(value);
76        self
77    }
78}
79
80/// ListAuditLogsError is a struct for typed errors of method [`AuditAPI::list_audit_logs`]
81#[derive(Debug, Clone, Serialize, Deserialize)]
82#[serde(untagged)]
83pub enum ListAuditLogsError {
84    APIErrorResponse(crate::datadogV2::model::APIErrorResponse),
85    UnknownValue(serde_json::Value),
86}
87
88/// SearchAuditLogsError is a struct for typed errors of method [`AuditAPI::search_audit_logs`]
89#[derive(Debug, Clone, Serialize, Deserialize)]
90#[serde(untagged)]
91pub enum SearchAuditLogsError {
92    APIErrorResponse(crate::datadogV2::model::APIErrorResponse),
93    UnknownValue(serde_json::Value),
94}
95
96/// Search your Audit Logs events over HTTP.
97#[derive(Debug, Clone)]
98pub struct AuditAPI {
99    config: datadog::Configuration,
100    client: reqwest_middleware::ClientWithMiddleware,
101}
102
103impl Default for AuditAPI {
104    fn default() -> Self {
105        Self::with_config(datadog::Configuration::default())
106    }
107}
108
109impl AuditAPI {
110    pub fn new() -> Self {
111        Self::default()
112    }
113    pub fn with_config(config: datadog::Configuration) -> Self {
114        let mut reqwest_client_builder = reqwest::Client::builder();
115
116        if let Some(proxy_url) = &config.proxy_url {
117            let proxy = reqwest::Proxy::all(proxy_url).expect("Failed to parse proxy URL");
118            reqwest_client_builder = reqwest_client_builder.proxy(proxy);
119        }
120
121        let mut middleware_client_builder =
122            reqwest_middleware::ClientBuilder::new(reqwest_client_builder.build().unwrap());
123
124        if config.enable_retry {
125            struct RetryableStatus;
126            impl reqwest_retry::RetryableStrategy for RetryableStatus {
127                fn handle(
128                    &self,
129                    res: &Result<reqwest::Response, reqwest_middleware::Error>,
130                ) -> Option<reqwest_retry::Retryable> {
131                    match res {
132                        Ok(success) => reqwest_retry::default_on_request_success(success),
133                        Err(_) => None,
134                    }
135                }
136            }
137            let backoff_policy = reqwest_retry::policies::ExponentialBackoff::builder()
138                .build_with_max_retries(config.max_retries);
139
140            let retry_middleware =
141                reqwest_retry::RetryTransientMiddleware::new_with_policy_and_strategy(
142                    backoff_policy,
143                    RetryableStatus,
144                );
145
146            middleware_client_builder = middleware_client_builder.with(retry_middleware);
147        }
148
149        let client = middleware_client_builder.build();
150
151        Self { config, client }
152    }
153
154    pub fn with_client_and_config(
155        config: datadog::Configuration,
156        client: reqwest_middleware::ClientWithMiddleware,
157    ) -> Self {
158        Self { config, client }
159    }
160
161    /// List endpoint returns events that match a Audit Logs search query.
162    /// [Results are paginated][1].
163    ///
164    /// Use this endpoint to see your latest Audit Logs events.
165    ///
166    /// [1]: <https://docs.datadoghq.com/logs/guide/collect-multiple-logs-with-pagination>
167    pub async fn list_audit_logs(
168        &self,
169        params: ListAuditLogsOptionalParams,
170    ) -> Result<crate::datadogV2::model::AuditLogsEventsResponse, datadog::Error<ListAuditLogsError>>
171    {
172        match self.list_audit_logs_with_http_info(params).await {
173            Ok(response_content) => {
174                if let Some(e) = response_content.entity {
175                    Ok(e)
176                } else {
177                    Err(datadog::Error::Serde(serde::de::Error::custom(
178                        "response content was None",
179                    )))
180                }
181            }
182            Err(err) => Err(err),
183        }
184    }
185
186    pub fn list_audit_logs_with_pagination(
187        &self,
188        mut params: ListAuditLogsOptionalParams,
189    ) -> impl Stream<
190        Item = Result<crate::datadogV2::model::AuditLogsEvent, datadog::Error<ListAuditLogsError>>,
191    > + '_ {
192        try_stream! {
193            let mut page_size: i32 = 10;
194            if params.page_limit.is_none() {
195                params.page_limit = Some(page_size);
196            } else {
197                page_size = params.page_limit.unwrap().clone();
198            }
199            loop {
200                let resp = self.list_audit_logs(params.clone()).await?;
201                let Some(data) = resp.data else { break };
202
203                let r = data;
204                let count = r.len();
205                for team in r {
206                    yield team;
207                }
208
209                if count < page_size as usize {
210                    break;
211                }
212                let Some(meta) = resp.meta else { break };
213                let Some(page) = meta.page else { break };
214                let Some(after) = page.after else { break };
215
216                params.page_cursor = Some(after);
217            }
218        }
219    }
220
221    /// List endpoint returns events that match a Audit Logs search query.
222    /// [Results are paginated][1].
223    ///
224    /// Use this endpoint to see your latest Audit Logs events.
225    ///
226    /// [1]: <https://docs.datadoghq.com/logs/guide/collect-multiple-logs-with-pagination>
227    pub async fn list_audit_logs_with_http_info(
228        &self,
229        params: ListAuditLogsOptionalParams,
230    ) -> Result<
231        datadog::ResponseContent<crate::datadogV2::model::AuditLogsEventsResponse>,
232        datadog::Error<ListAuditLogsError>,
233    > {
234        let local_configuration = &self.config;
235        let operation_id = "v2.list_audit_logs";
236
237        // unbox and build optional parameters
238        let filter_query = params.filter_query;
239        let filter_from = params.filter_from;
240        let filter_to = params.filter_to;
241        let sort = params.sort;
242        let page_cursor = params.page_cursor;
243        let page_limit = params.page_limit;
244
245        let local_client = &self.client;
246
247        let local_uri_str = format!(
248            "{}/api/v2/audit/events",
249            local_configuration.get_operation_host(operation_id)
250        );
251        let mut local_req_builder =
252            local_client.request(reqwest::Method::GET, local_uri_str.as_str());
253
254        if let Some(ref local_query_param) = filter_query {
255            local_req_builder =
256                local_req_builder.query(&[("filter[query]", &local_query_param.to_string())]);
257        };
258        if let Some(ref local_query_param) = filter_from {
259            local_req_builder = local_req_builder.query(&[(
260                "filter[from]",
261                &local_query_param.to_rfc3339_opts(chrono::SecondsFormat::Millis, true),
262            )]);
263        };
264        if let Some(ref local_query_param) = filter_to {
265            local_req_builder = local_req_builder.query(&[(
266                "filter[to]",
267                &local_query_param.to_rfc3339_opts(chrono::SecondsFormat::Millis, true),
268            )]);
269        };
270        if let Some(ref local_query_param) = sort {
271            local_req_builder =
272                local_req_builder.query(&[("sort", &local_query_param.to_string())]);
273        };
274        if let Some(ref local_query_param) = page_cursor {
275            local_req_builder =
276                local_req_builder.query(&[("page[cursor]", &local_query_param.to_string())]);
277        };
278        if let Some(ref local_query_param) = page_limit {
279            local_req_builder =
280                local_req_builder.query(&[("page[limit]", &local_query_param.to_string())]);
281        };
282
283        // build headers
284        let mut headers = HeaderMap::new();
285        headers.insert("Accept", HeaderValue::from_static("application/json"));
286
287        // build user agent
288        match HeaderValue::from_str(local_configuration.user_agent.as_str()) {
289            Ok(user_agent) => headers.insert(reqwest::header::USER_AGENT, user_agent),
290            Err(e) => {
291                log::warn!("Failed to parse user agent header: {e}, falling back to default");
292                headers.insert(
293                    reqwest::header::USER_AGENT,
294                    HeaderValue::from_static(datadog::DEFAULT_USER_AGENT.as_str()),
295                )
296            }
297        };
298
299        // build auth
300        if let Some(local_key) = local_configuration.auth_keys.get("apiKeyAuth") {
301            headers.insert(
302                "DD-API-KEY",
303                HeaderValue::from_str(local_key.key.as_str())
304                    .expect("failed to parse DD-API-KEY header"),
305            );
306        };
307        if let Some(local_key) = local_configuration.auth_keys.get("appKeyAuth") {
308            headers.insert(
309                "DD-APPLICATION-KEY",
310                HeaderValue::from_str(local_key.key.as_str())
311                    .expect("failed to parse DD-APPLICATION-KEY header"),
312            );
313        };
314
315        local_req_builder = local_req_builder.headers(headers);
316        let local_req = local_req_builder.build()?;
317        log::debug!("request content: {:?}", local_req.body());
318        let local_resp = local_client.execute(local_req).await?;
319
320        let local_status = local_resp.status();
321        let local_content = local_resp.text().await?;
322        log::debug!("response content: {}", local_content);
323
324        if !local_status.is_client_error() && !local_status.is_server_error() {
325            match serde_json::from_str::<crate::datadogV2::model::AuditLogsEventsResponse>(
326                &local_content,
327            ) {
328                Ok(e) => {
329                    return Ok(datadog::ResponseContent {
330                        status: local_status,
331                        content: local_content,
332                        entity: Some(e),
333                    })
334                }
335                Err(e) => return Err(datadog::Error::Serde(e)),
336            };
337        } else {
338            let local_entity: Option<ListAuditLogsError> =
339                serde_json::from_str(&local_content).ok();
340            let local_error = datadog::ResponseContent {
341                status: local_status,
342                content: local_content,
343                entity: local_entity,
344            };
345            Err(datadog::Error::ResponseError(local_error))
346        }
347    }
348
349    /// List endpoint returns Audit Logs events that match an Audit search query.
350    /// [Results are paginated][1].
351    ///
352    /// Use this endpoint to build complex Audit Logs events filtering and search.
353    ///
354    /// [1]: <https://docs.datadoghq.com/logs/guide/collect-multiple-logs-with-pagination>
355    pub async fn search_audit_logs(
356        &self,
357        params: SearchAuditLogsOptionalParams,
358    ) -> Result<
359        crate::datadogV2::model::AuditLogsEventsResponse,
360        datadog::Error<SearchAuditLogsError>,
361    > {
362        match self.search_audit_logs_with_http_info(params).await {
363            Ok(response_content) => {
364                if let Some(e) = response_content.entity {
365                    Ok(e)
366                } else {
367                    Err(datadog::Error::Serde(serde::de::Error::custom(
368                        "response content was None",
369                    )))
370                }
371            }
372            Err(err) => Err(err),
373        }
374    }
375
376    pub fn search_audit_logs_with_pagination(
377        &self,
378        mut params: SearchAuditLogsOptionalParams,
379    ) -> impl Stream<
380        Item = Result<
381            crate::datadogV2::model::AuditLogsEvent,
382            datadog::Error<SearchAuditLogsError>,
383        >,
384    > + '_ {
385        try_stream! {
386            let mut page_size: i32 = 10;
387            if params.body.is_none() {
388                params.body = Some(crate::datadogV2::model::AuditLogsSearchEventsRequest::new());
389            }
390            if params.body.as_ref().unwrap().page.is_none() {
391                params.body.as_mut().unwrap().page = Some(crate::datadogV2::model::AuditLogsQueryPageOptions::new());
392            }
393            if params.body.as_ref().unwrap().page.as_ref().unwrap().limit.is_none() {
394                params.body.as_mut().unwrap().page.as_mut().unwrap().limit = Some(page_size);
395            } else {
396                page_size = params.body.as_ref().unwrap().page.as_ref().unwrap().limit.unwrap().clone();
397            }
398            loop {
399                let resp = self.search_audit_logs(params.clone()).await?;
400                let Some(data) = resp.data else { break };
401
402                let r = data;
403                let count = r.len();
404                for team in r {
405                    yield team;
406                }
407
408                if count < page_size as usize {
409                    break;
410                }
411                let Some(meta) = resp.meta else { break };
412                let Some(page) = meta.page else { break };
413                let Some(after) = page.after else { break };
414
415                params.body.as_mut().unwrap().page.as_mut().unwrap().cursor = Some(after);
416            }
417        }
418    }
419
420    /// List endpoint returns Audit Logs events that match an Audit search query.
421    /// [Results are paginated][1].
422    ///
423    /// Use this endpoint to build complex Audit Logs events filtering and search.
424    ///
425    /// [1]: <https://docs.datadoghq.com/logs/guide/collect-multiple-logs-with-pagination>
426    pub async fn search_audit_logs_with_http_info(
427        &self,
428        params: SearchAuditLogsOptionalParams,
429    ) -> Result<
430        datadog::ResponseContent<crate::datadogV2::model::AuditLogsEventsResponse>,
431        datadog::Error<SearchAuditLogsError>,
432    > {
433        let local_configuration = &self.config;
434        let operation_id = "v2.search_audit_logs";
435
436        // unbox and build optional parameters
437        let body = params.body;
438
439        let local_client = &self.client;
440
441        let local_uri_str = format!(
442            "{}/api/v2/audit/events/search",
443            local_configuration.get_operation_host(operation_id)
444        );
445        let mut local_req_builder =
446            local_client.request(reqwest::Method::POST, local_uri_str.as_str());
447
448        // build headers
449        let mut headers = HeaderMap::new();
450        headers.insert("Content-Type", HeaderValue::from_static("application/json"));
451        headers.insert("Accept", HeaderValue::from_static("application/json"));
452
453        // build user agent
454        match HeaderValue::from_str(local_configuration.user_agent.as_str()) {
455            Ok(user_agent) => headers.insert(reqwest::header::USER_AGENT, user_agent),
456            Err(e) => {
457                log::warn!("Failed to parse user agent header: {e}, falling back to default");
458                headers.insert(
459                    reqwest::header::USER_AGENT,
460                    HeaderValue::from_static(datadog::DEFAULT_USER_AGENT.as_str()),
461                )
462            }
463        };
464
465        // build auth
466        if let Some(local_key) = local_configuration.auth_keys.get("apiKeyAuth") {
467            headers.insert(
468                "DD-API-KEY",
469                HeaderValue::from_str(local_key.key.as_str())
470                    .expect("failed to parse DD-API-KEY header"),
471            );
472        };
473        if let Some(local_key) = local_configuration.auth_keys.get("appKeyAuth") {
474            headers.insert(
475                "DD-APPLICATION-KEY",
476                HeaderValue::from_str(local_key.key.as_str())
477                    .expect("failed to parse DD-APPLICATION-KEY header"),
478            );
479        };
480
481        // build body parameters
482        let output = Vec::new();
483        let mut ser = serde_json::Serializer::with_formatter(output, datadog::DDFormatter);
484        if body.serialize(&mut ser).is_ok() {
485            if let Some(content_encoding) = headers.get("Content-Encoding") {
486                match content_encoding.to_str().unwrap_or_default() {
487                    "gzip" => {
488                        let mut enc = GzEncoder::new(Vec::new(), Compression::default());
489                        let _ = enc.write_all(ser.into_inner().as_slice());
490                        match enc.finish() {
491                            Ok(buf) => {
492                                local_req_builder = local_req_builder.body(buf);
493                            }
494                            Err(e) => return Err(datadog::Error::Io(e)),
495                        }
496                    }
497                    "deflate" => {
498                        let mut enc = ZlibEncoder::new(Vec::new(), Compression::default());
499                        let _ = enc.write_all(ser.into_inner().as_slice());
500                        match enc.finish() {
501                            Ok(buf) => {
502                                local_req_builder = local_req_builder.body(buf);
503                            }
504                            Err(e) => return Err(datadog::Error::Io(e)),
505                        }
506                    }
507                    "zstd1" => {
508                        let mut enc = zstd::stream::Encoder::new(Vec::new(), 0).unwrap();
509                        let _ = enc.write_all(ser.into_inner().as_slice());
510                        match enc.finish() {
511                            Ok(buf) => {
512                                local_req_builder = local_req_builder.body(buf);
513                            }
514                            Err(e) => return Err(datadog::Error::Io(e)),
515                        }
516                    }
517                    _ => {
518                        local_req_builder = local_req_builder.body(ser.into_inner());
519                    }
520                }
521            } else {
522                local_req_builder = local_req_builder.body(ser.into_inner());
523            }
524        }
525
526        local_req_builder = local_req_builder.headers(headers);
527        let local_req = local_req_builder.build()?;
528        log::debug!("request content: {:?}", local_req.body());
529        let local_resp = local_client.execute(local_req).await?;
530
531        let local_status = local_resp.status();
532        let local_content = local_resp.text().await?;
533        log::debug!("response content: {}", local_content);
534
535        if !local_status.is_client_error() && !local_status.is_server_error() {
536            match serde_json::from_str::<crate::datadogV2::model::AuditLogsEventsResponse>(
537                &local_content,
538            ) {
539                Ok(e) => {
540                    return Ok(datadog::ResponseContent {
541                        status: local_status,
542                        content: local_content,
543                        entity: Some(e),
544                    })
545                }
546                Err(e) => return Err(datadog::Error::Serde(e)),
547            };
548        } else {
549            let local_entity: Option<SearchAuditLogsError> =
550                serde_json::from_str(&local_content).ok();
551            let local_error = datadog::ResponseContent {
552                status: local_status,
553                content: local_content,
554                entity: local_entity,
555            };
556            Err(datadog::Error::ResponseError(local_error))
557        }
558    }
559}