From 65a77350fe9f576eee623fc8037befb409025f44 Mon Sep 17 00:00:00 2001 From: "ci.datadog-api-spec" Date: Thu, 28 May 2026 16:06:23 +0000 Subject: [PATCH] Regenerate client from commit 1ec43f9 of spec repo --- .generator/schemas/v2/openapi.yaml | 578 ++++++++++++++++++ examples/v2_apm-trace_GetPrunedTraceByID.rs | 22 + examples/v2_apm-trace_GetTraceByID.rs | 22 + src/datadog/configuration.rs | 2 + src/datadogV2/api/api_apm_trace.rs | 483 +++++++++++++++ src/datadogV2/api/mod.rs | 1 + src/datadogV2/mod.rs | 1 + src/datadogV2/model/mod.rs | 24 + .../model/model_apm_span_error_flag.rs | 42 ++ src/datadogV2/model/model_apm_trace_span.rs | 303 +++++++++ .../model/model_pruned_trace_attributes.rs | 121 ++++ .../model/model_pruned_trace_data.rs | 126 ++++ .../model/model_pruned_trace_response.rs | 92 +++ .../model/model_pruned_trace_type.rs | 48 ++ src/datadogV2/model/model_summarized_span.rs | 252 ++++++++ src/datadogV2/model/model_summarized_trace.rs | 102 ++++ src/datadogV2/model/model_trace_attributes.rs | 107 ++++ src/datadogV2/model/model_trace_data.rs | 124 ++++ src/datadogV2/model/model_trace_response.rs | 92 +++ src/datadogV2/model/model_trace_type.rs | 48 ++ tests/scenarios/features/v2/apm_trace.feature | 48 ++ tests/scenarios/features/v2/undo.json | 12 + tests/scenarios/function_mappings.rs | 100 +++ 23 files changed, 2750 insertions(+) create mode 100644 examples/v2_apm-trace_GetPrunedTraceByID.rs create mode 100644 examples/v2_apm-trace_GetTraceByID.rs create mode 100644 src/datadogV2/api/api_apm_trace.rs create mode 100644 src/datadogV2/model/model_apm_span_error_flag.rs create mode 100644 src/datadogV2/model/model_apm_trace_span.rs create mode 100644 src/datadogV2/model/model_pruned_trace_attributes.rs create mode 100644 src/datadogV2/model/model_pruned_trace_data.rs create mode 100644 src/datadogV2/model/model_pruned_trace_response.rs create mode 100644 src/datadogV2/model/model_pruned_trace_type.rs create mode 100644 src/datadogV2/model/model_summarized_span.rs create mode 100644 src/datadogV2/model/model_summarized_trace.rs create mode 100644 src/datadogV2/model/model_trace_attributes.rs create mode 100644 src/datadogV2/model/model_trace_data.rs create mode 100644 src/datadogV2/model/model_trace_response.rs create mode 100644 src/datadogV2/model/model_trace_type.rs create mode 100644 tests/scenarios/features/v2/apm_trace.feature diff --git a/.generator/schemas/v2/openapi.yaml b/.generator/schemas/v2/openapi.yaml index bc16917af1..6a07925729 100644 --- a/.generator/schemas/v2/openapi.yaml +++ b/.generator/schemas/v2/openapi.yaml @@ -1692,6 +1692,16 @@ components: example: 1706803070 format: int64 type: integer + TraceIDPathParameter: + description: |- + The trace ID. Accepts either a 32-character hexadecimal string (128-bit trace ID) + or a decimal string of up to 39 digits. + example: "0000000000000000abc1230000000000" + in: path + name: trace_id + required: true + schema: + type: string UserID: description: "The ID of the user." in: path @@ -2085,6 +2095,126 @@ components: required: - apiTrigger type: object + APMSpanErrorFlag: + description: Error flag for a span. `1` when the span is in error, `0` otherwise. + enum: + - 0 + - 1 + example: 0 + format: int32 + type: integer + x-enum-varnames: + - NO_ERROR + - ERROR + APMTraceSpan: + description: A single APM span returned as part of a trace. + properties: + duration: + description: The duration of the span, in nanoseconds. + example: 500000000 + format: int64 + type: integer + endTime: + description: The end time of the span, in Unix nanoseconds. + example: 1716800000500000000 + format: int64 + type: integer + error: + $ref: "#/components/schemas/APMSpanErrorFlag" + meta: + additionalProperties: + type: string + description: |- + String-valued tags attached to the span. Tag keys starting with `_` are + filtered out of the response. + example: + env: production + http.method: GET + type: object + metrics: + additionalProperties: + format: double + type: number + description: |- + Numeric metrics attached to the span. Metric keys starting with `_` are + filtered out of the response. + example: + http.status_code: 200 + type: object + name: + description: The operation name of the span. + example: web.request + type: string + parentID: + description: The ID of the parent span, or `0` when the span is a trace root. + example: 0 + format: int64 + type: integer + resource: + description: The resource that the span describes. + example: GET /products + type: string + resourceHash: + description: A hash of the resource field. + example: 6a4e9b7f + type: string + restricted: + description: Whether access to the span is restricted by the organization's data access policies. + example: false + type: boolean + self_time: + description: The time spent in the span itself, excluding time spent in child spans, in nanoseconds. + example: 250000000 + format: double + type: number + service: + description: The name of the service that emitted the span. + example: web-store + type: string + spanID: + description: The span ID, as an unsigned 64-bit integer. + example: 9876543210987654321 + format: int64 + type: integer + startTime: + description: The start time of the span, in Unix nanoseconds. + example: 1716800000000000000 + format: int64 + type: integer + traceID: + description: The lower 64 bits of the trace ID, as an unsigned 64-bit integer. + example: 12345678901234567890 + format: int64 + type: integer + traceIDFull: + description: The full 128-bit trace ID, encoded as a 32-character hexadecimal string. + example: "0000000000000000abc1230000000000" + type: string + type: + description: The type of the span (for example, `web`, `db`, or `rpc`). + example: web + type: string + required: + - service + - name + - resource + - traceID + - spanID + - parentID + - startTime + - endTime + - duration + - error + - type + - meta + - metrics + - traceIDFull + type: object + APMTraceSpans: + description: The list of spans that compose the trace. + items: + $ref: "#/components/schemas/APMTraceSpan" + type: array AWSAccountConfigID: description: |- Unique Datadog ID of the AWS Account Integration Config. @@ -65918,6 +66048,60 @@ components: $ref: "#/components/schemas/Project" type: array type: object + PrunedTraceAttributes: + description: The attributes of a pruned trace returned by the Get pruned trace by ID endpoint. + properties: + is_truncated: + description: |- + Indicates whether the underlying trace was truncated because its size + exceeded the maximum that can be retrieved from storage. + example: false + type: boolean + size_bytes: + description: The size, in bytes, of the original (non-pruned) trace before summarization. + example: 12345 + format: int32 + maximum: 2147483647 + type: integer + summarized_trace: + $ref: "#/components/schemas/SummarizedTrace" + required: + - summarized_trace + - is_truncated + - size_bytes + type: object + PrunedTraceData: + description: A pruned trace resource document. + properties: + attributes: + $ref: "#/components/schemas/PrunedTraceAttributes" + id: + description: The full 128-bit trace ID, encoded as a 32-character hexadecimal string. + example: "0000000000000000abc1230000000000" + type: string + type: + $ref: "#/components/schemas/PrunedTraceType" + required: + - id + - type + - attributes + type: object + PrunedTraceResponse: + description: Response containing a single pruned trace. + properties: + data: + $ref: "#/components/schemas/PrunedTraceData" + required: + - data + type: object + PrunedTraceType: + description: The type of the pruned trace resource. The value is always `pruned_trace`. + enum: + - pruned_trace + example: pruned_trace + type: string + x-enum-varnames: + - PRUNED_TRACE PublishAppResponse: description: The response object after an app is successfully published. properties: @@ -83449,6 +83633,110 @@ components: type: string x-enum-varnames: - SUITES_SEARCH + SummarizedSpan: + description: A node in the pruned trace tree. + properties: + children: + description: The child spans of this node in the pruned tree. + example: [] + items: + $ref: "#/components/schemas/SummarizedSpan" + type: array + durationSeconds: + description: The duration of the span, in seconds. + example: 0.5 + format: double + type: number + endTime: + description: The end time of the span, in RFC3339 format. + example: "2026-05-27T12:00:00.5Z" + format: date-time + type: string + error: + $ref: "#/components/schemas/APMSpanErrorFlag" + hidden_child_spans_count: + description: The number of child spans that were pruned from this node when summarizing the trace. + example: 0 + format: int32 + maximum: 2147483647 + type: integer + meta: + additionalProperties: + type: string + description: String-valued tags attached to the span. + example: + env: production + type: object + metrics: + additionalProperties: + format: double + type: number + description: Numeric metrics attached to the span. + example: + http.status_code: 200 + type: object + name: + description: The operation name of the span. + example: web.request + type: string + parentID: + description: The ID of the parent span, or `0` when the span is the trace root. + example: 0 + format: int64 + type: integer + resource: + description: The resource that the span describes. + example: GET /products + type: string + service: + description: The name of the service that emitted the span. + example: web-store + type: string + spanID: + description: The span ID, as an unsigned 64-bit integer. + example: 9876543210987654321 + format: int64 + type: integer + span_kind: + description: |- + The OpenTelemetry span kind, for example `INTERNAL`, `SERVER`, `CLIENT`, + `PRODUCER`, or `CONSUMER`. + example: SERVER + type: string + startTime: + description: The start time of the span, in RFC3339 format. + example: "2026-05-27T12:00:00Z" + format: date-time + type: string + required: + - service + - name + - resource + - parentID + - spanID + - startTime + - endTime + - durationSeconds + - error + - meta + - metrics + - span_kind + - hidden_child_spans_count + - children + type: object + SummarizedTrace: + description: A summarized, hierarchical view of a trace. + properties: + root: + $ref: "#/components/schemas/SummarizedSpan" + traceId: + description: The full 128-bit trace ID, encoded as a 32-character hexadecimal string. + example: "0000000000000000abc1230000000000" + type: string + required: + - traceId + - root + type: object SuppressionVersionHistory: description: Response object containing the version history of a suppression. properties: @@ -90629,6 +90917,51 @@ components: type: string x-enum-varnames: - SECRET + TraceAttributes: + description: The attributes of a trace returned by the Get trace by ID endpoint. + properties: + is_truncated: + description: Indicates whether the trace was truncated because its size exceeded the maximum response payload. + example: false + type: boolean + spans: + $ref: "#/components/schemas/APMTraceSpans" + required: + - is_truncated + - spans + type: object + TraceData: + description: A trace resource document. + properties: + attributes: + $ref: "#/components/schemas/TraceAttributes" + id: + description: The full 128-bit trace ID, encoded as a 32-character hexadecimal string. + example: "0000000000000000abc1230000000000" + type: string + type: + $ref: "#/components/schemas/TraceType" + required: + - id + - type + - attributes + type: object + TraceResponse: + description: Response containing a single trace. + properties: + data: + $ref: "#/components/schemas/TraceData" + required: + - data + type: object + TraceType: + description: The type of the trace resource. The value is always `trace`. + enum: + - trace + example: trace + type: string + x-enum-varnames: + - TRACE Trigger: description: "One of the triggers that can start the execution of a workflow." oneOf: @@ -141040,6 +141373,159 @@ paths: tags: - Rum Audience Management x-unstable: "**Note**: This endpoint may be subject to changes." + /api/v2/pruned_trace/{trace_id}: + get: + description: |- + Retrieve a pruned, hierarchical view of an APM trace by its trace ID. + The trace is summarized as a tree of spans rooted at the trace root and reduced in size + to keep rendering large traces in the UI practical. + This endpoint is rate limited to `60` requests per minute per organization. + operationId: GetPrunedTraceByID + parameters: + - $ref: "#/components/parameters/TraceIDPathParameter" + - description: |- + Span ID to expand and preserve in the pruned tree even when its branch would + normally be summarized. + example: 9876543210987654321 + in: query + name: expand_span_id + required: false + schema: + format: int64 + type: integer + - description: |- + Optional Unix time hint, in seconds, used to optimize the lookup of the trace + in long-term storage. + example: 1716800000 + in: query + name: time_hint + required: false + schema: + format: int32 + maximum: 2147483647 + type: integer + - description: |- + Force the trace to be loaded from a specific source. When unset, the API picks + the source automatically. + example: driveline + in: query + name: force_source + required: false + schema: + type: string + - description: |- + Restrict the pruned tree to spans matching the given `key:value` pairs. + Values may be passed as repeated query parameters. + example: + - service:web-store + in: query + name: include_path + required: false + schema: + items: + type: string + type: array + - description: |- + Regex patterns of tag keys whose values must be included in the pruned spans. + Values may be passed as repeated query parameters. + example: + - "^http\\." + in: query + name: tag_include + required: false + schema: + items: + type: string + type: array + - description: |- + Regex patterns of tag keys whose values must be excluded from the pruned spans. + Values may be passed as repeated query parameters. + example: + - "^_dd\\." + in: query + name: tag_exclude + required: false + schema: + items: + type: string + type: array + - description: When set to `true`, only service entry spans are included in the pruned tree. + example: false + in: query + name: only_service_entry_spans + required: false + schema: + type: boolean + responses: + "200": + content: + application/json: + examples: + default: + value: + data: + attributes: + is_truncated: false + size_bytes: 12345 + summarized_trace: + root: + children: [] + durationSeconds: 0.5 + endTime: "2026-05-27T12:00:00.5Z" + error: 0 + hidden_child_spans_count: 0 + meta: + env: production + metrics: + http.status_code: 200 + name: web.request + parentID: 0 + resource: GET /products + service: web-store + spanID: 9876543210987654321 + span_kind: SERVER + startTime: "2026-05-27T12:00:00Z" + traceId: "0000000000000000abc1230000000000" + id: "0000000000000000abc1230000000000" + type: pruned_trace + schema: + $ref: "#/components/schemas/PrunedTraceResponse" + description: OK + "403": + content: + application/json: + schema: + $ref: "#/components/schemas/JSONAPIErrorResponse" + description: Forbidden + "404": + content: + application/json: + schema: + $ref: "#/components/schemas/JSONAPIErrorResponse" + description: Not Found + "429": + $ref: "#/components/responses/TooManyRequestsResponse" + "504": + content: + application/json: + schema: + $ref: "#/components/schemas/JSONAPIErrorResponse" + description: Gateway Timeout + security: + - apiKeyAuth: [] + appKeyAuth: [] + - AuthZ: + - apm_read + summary: Get a pruned trace by ID + tags: + - APM Trace + x-permission: + operator: OR + permissions: + - apm_read + x-unstable: |- + **Note**: This endpoint is in preview and is subject to change. + If you have any feedback, contact [Datadog support](https://docs.datadoghq.com/help/). /api/v2/query/scalar: post: description: |- @@ -165634,6 +166120,96 @@ paths: operator: OR permissions: - test_optimization_read + /api/v2/trace/{trace_id}: + get: + description: |- + Retrieve a full APM trace by its trace ID, including every span in the trace. + Traces are returned from live storage when available and fall back to longer-term storage. + This endpoint is rate limited to `60` requests per minute per organization. + operationId: GetTraceByID + parameters: + - $ref: "#/components/parameters/TraceIDPathParameter" + - description: |- + List of span fields to include in the response. When omitted, every available field is returned. + Values may be passed as repeated query parameters or as a single comma-separated value. + example: + - service + - resource_name + in: query + name: include_fields + required: false + schema: + items: + type: string + type: array + responses: + "200": + content: + application/json: + examples: + default: + value: + data: + attributes: + is_truncated: false + spans: + - duration: 500000000 + endTime: 1716800000500000000 + error: 0 + meta: + env: production + http.method: GET + metrics: + http.status_code: 200 + name: web.request + parentID: 0 + resource: GET /products + service: web-store + spanID: 9876543210987654321 + startTime: 1716800000000000000 + traceID: 12345678901234567890 + traceIDFull: 0000000000000000abc1230000000000 + type: web + id: "0000000000000000abc1230000000000" + type: trace + schema: + $ref: "#/components/schemas/TraceResponse" + description: OK + "403": + content: + application/json: + schema: + $ref: "#/components/schemas/JSONAPIErrorResponse" + description: Forbidden + "404": + content: + application/json: + schema: + $ref: "#/components/schemas/JSONAPIErrorResponse" + description: Not Found + "413": + content: + application/json: + schema: + $ref: "#/components/schemas/JSONAPIErrorResponse" + description: Payload Too Large + "429": + $ref: "#/components/responses/TooManyRequestsResponse" + security: + - apiKeyAuth: [] + appKeyAuth: [] + - AuthZ: + - apm_read + summary: Get a trace by ID + tags: + - APM Trace + x-permission: + operator: OR + permissions: + - apm_read + x-unstable: |- + **Note**: This endpoint is in preview and is subject to change. + If you have any feedback, contact [Datadog support](https://docs.datadoghq.com/help/). /api/v2/usage/application_security: get: deprecated: true @@ -168360,6 +168936,8 @@ tags: description: Find out more at url: https://docs.datadoghq.com/tracing/trace_pipeline/trace_retention/ name: APM Retention Filters + - description: Retrieve full or pruned APM traces by trace ID. + name: APM Trace - description: |- Configure your Datadog-AWS integration directly through the Datadog API. For more information, see the [AWS integration page](https://docs.datadoghq.com/integrations/amazon_web_services). diff --git a/examples/v2_apm-trace_GetPrunedTraceByID.rs b/examples/v2_apm-trace_GetPrunedTraceByID.rs new file mode 100644 index 0000000000..dc7d65356f --- /dev/null +++ b/examples/v2_apm-trace_GetPrunedTraceByID.rs @@ -0,0 +1,22 @@ +// Get a pruned trace by ID returns "OK" response +use datadog_api_client::datadog; +use datadog_api_client::datadogV2::api_apm_trace::APMTraceAPI; +use datadog_api_client::datadogV2::api_apm_trace::GetPrunedTraceByIDOptionalParams; + +#[tokio::main] +async fn main() { + let mut configuration = datadog::Configuration::new(); + configuration.set_unstable_operation_enabled("v2.GetPrunedTraceByID", true); + let api = APMTraceAPI::with_config(configuration); + let resp = api + .get_pruned_trace_by_id( + "trace_id".to_string(), + GetPrunedTraceByIDOptionalParams::default(), + ) + .await; + if let Ok(value) = resp { + println!("{:#?}", value); + } else { + println!("{:#?}", resp.unwrap_err()); + } +} diff --git a/examples/v2_apm-trace_GetTraceByID.rs b/examples/v2_apm-trace_GetTraceByID.rs new file mode 100644 index 0000000000..800469a78b --- /dev/null +++ b/examples/v2_apm-trace_GetTraceByID.rs @@ -0,0 +1,22 @@ +// Get a trace by ID returns "OK" response +use datadog_api_client::datadog; +use datadog_api_client::datadogV2::api_apm_trace::APMTraceAPI; +use datadog_api_client::datadogV2::api_apm_trace::GetTraceByIDOptionalParams; + +#[tokio::main] +async fn main() { + let mut configuration = datadog::Configuration::new(); + configuration.set_unstable_operation_enabled("v2.GetTraceByID", true); + let api = APMTraceAPI::with_config(configuration); + let resp = api + .get_trace_by_id( + "trace_id".to_string(), + GetTraceByIDOptionalParams::default(), + ) + .await; + if let Ok(value) = resp { + println!("{:#?}", value); + } else { + println!("{:#?}", resp.unwrap_err()); + } +} diff --git a/src/datadog/configuration.rs b/src/datadog/configuration.rs index 088b06811d..11c845aa14 100644 --- a/src/datadog/configuration.rs +++ b/src/datadog/configuration.rs @@ -575,6 +575,8 @@ impl Default for Configuration { ("v2.query_event_filtered_users".to_owned(), false), ("v2.query_users".to_owned(), false), ("v2.update_connection".to_owned(), false), + ("v2.get_pruned_trace_by_id".to_owned(), false), + ("v2.get_trace_by_id".to_owned(), false), ("v2.create_scorecard_outcomes_batch".to_owned(), false), ("v2.list_entity_risk_scores".to_owned(), false), ("v2.create_incident_service".to_owned(), false), diff --git a/src/datadogV2/api/api_apm_trace.rs b/src/datadogV2/api/api_apm_trace.rs new file mode 100644 index 0000000000..fe52bf5d75 --- /dev/null +++ b/src/datadogV2/api/api_apm_trace.rs @@ -0,0 +1,483 @@ +// Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2019-Present Datadog, Inc. +use crate::datadog; +use log::warn; +use reqwest::header::{HeaderMap, HeaderValue}; +use serde::{Deserialize, Serialize}; + +/// GetPrunedTraceByIDOptionalParams is a struct for passing parameters to the method [`APMTraceAPI::get_pruned_trace_by_id`] +#[non_exhaustive] +#[derive(Clone, Default, Debug)] +pub struct GetPrunedTraceByIDOptionalParams { + /// Span ID to expand and preserve in the pruned tree even when its branch would + /// normally be summarized. + pub expand_span_id: Option, + /// Optional Unix time hint, in seconds, used to optimize the lookup of the trace + /// in long-term storage. + pub time_hint: Option, + /// Force the trace to be loaded from a specific source. When unset, the API picks + /// the source automatically. + pub force_source: Option, + /// Restrict the pruned tree to spans matching the given `key:value` pairs. + /// Values may be passed as repeated query parameters. + pub include_path: Option>, + /// Regex patterns of tag keys whose values must be included in the pruned spans. + /// Values may be passed as repeated query parameters. + pub tag_include: Option>, + /// Regex patterns of tag keys whose values must be excluded from the pruned spans. + /// Values may be passed as repeated query parameters. + pub tag_exclude: Option>, + /// When set to `true`, only service entry spans are included in the pruned tree. + pub only_service_entry_spans: Option, +} + +impl GetPrunedTraceByIDOptionalParams { + /// Span ID to expand and preserve in the pruned tree even when its branch would + /// normally be summarized. + pub fn expand_span_id(mut self, value: i64) -> Self { + self.expand_span_id = Some(value); + self + } + /// Optional Unix time hint, in seconds, used to optimize the lookup of the trace + /// in long-term storage. + pub fn time_hint(mut self, value: i32) -> Self { + self.time_hint = Some(value); + self + } + /// Force the trace to be loaded from a specific source. When unset, the API picks + /// the source automatically. + pub fn force_source(mut self, value: String) -> Self { + self.force_source = Some(value); + self + } + /// Restrict the pruned tree to spans matching the given `key:value` pairs. + /// Values may be passed as repeated query parameters. + pub fn include_path(mut self, value: Vec) -> Self { + self.include_path = Some(value); + self + } + /// Regex patterns of tag keys whose values must be included in the pruned spans. + /// Values may be passed as repeated query parameters. + pub fn tag_include(mut self, value: Vec) -> Self { + self.tag_include = Some(value); + self + } + /// Regex patterns of tag keys whose values must be excluded from the pruned spans. + /// Values may be passed as repeated query parameters. + pub fn tag_exclude(mut self, value: Vec) -> Self { + self.tag_exclude = Some(value); + self + } + /// When set to `true`, only service entry spans are included in the pruned tree. + pub fn only_service_entry_spans(mut self, value: bool) -> Self { + self.only_service_entry_spans = Some(value); + self + } +} + +/// GetTraceByIDOptionalParams is a struct for passing parameters to the method [`APMTraceAPI::get_trace_by_id`] +#[non_exhaustive] +#[derive(Clone, Default, Debug)] +pub struct GetTraceByIDOptionalParams { + /// List of span fields to include in the response. When omitted, every available field is returned. + /// Values may be passed as repeated query parameters or as a single comma-separated value. + pub include_fields: Option>, +} + +impl GetTraceByIDOptionalParams { + /// List of span fields to include in the response. When omitted, every available field is returned. + /// Values may be passed as repeated query parameters or as a single comma-separated value. + pub fn include_fields(mut self, value: Vec) -> Self { + self.include_fields = Some(value); + self + } +} + +/// GetPrunedTraceByIDError is a struct for typed errors of method [`APMTraceAPI::get_pruned_trace_by_id`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum GetPrunedTraceByIDError { + JSONAPIErrorResponse(crate::datadogV2::model::JSONAPIErrorResponse), + APIErrorResponse(crate::datadogV2::model::APIErrorResponse), + UnknownValue(serde_json::Value), +} + +/// GetTraceByIDError is a struct for typed errors of method [`APMTraceAPI::get_trace_by_id`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum GetTraceByIDError { + JSONAPIErrorResponse(crate::datadogV2::model::JSONAPIErrorResponse), + APIErrorResponse(crate::datadogV2::model::APIErrorResponse), + UnknownValue(serde_json::Value), +} + +/// Retrieve full or pruned APM traces by trace ID. +#[derive(Debug, Clone)] +pub struct APMTraceAPI { + config: datadog::Configuration, + client: reqwest_middleware::ClientWithMiddleware, +} + +impl Default for APMTraceAPI { + fn default() -> Self { + Self::with_config(datadog::Configuration::default()) + } +} + +impl APMTraceAPI { + pub fn new() -> Self { + Self::default() + } + pub fn with_config(config: datadog::Configuration) -> Self { + let reqwest_client_builder = { + let builder = reqwest::Client::builder(); + #[cfg(not(target_arch = "wasm32"))] + let builder = if let Some(proxy_url) = &config.proxy_url { + builder.proxy(reqwest::Proxy::all(proxy_url).expect("Failed to parse proxy URL")) + } else { + builder + }; + builder + }; + + let middleware_client_builder = { + let builder = + reqwest_middleware::ClientBuilder::new(reqwest_client_builder.build().unwrap()); + #[cfg(feature = "retry")] + let builder = if config.enable_retry { + struct RetryableStatus; + impl reqwest_retry::RetryableStrategy for RetryableStatus { + fn handle( + &self, + res: &Result, + ) -> Option { + match res { + Ok(success) => reqwest_retry::default_on_request_success(success), + Err(_) => None, + } + } + } + let backoff_policy = reqwest_retry::policies::ExponentialBackoff::builder() + .build_with_max_retries(config.max_retries); + + let retry_middleware = + reqwest_retry::RetryTransientMiddleware::new_with_policy_and_strategy( + backoff_policy, + RetryableStatus, + ); + + builder.with(retry_middleware) + } else { + builder + }; + builder + }; + + let client = middleware_client_builder.build(); + + Self { config, client } + } + + pub fn with_client_and_config( + config: datadog::Configuration, + client: reqwest_middleware::ClientWithMiddleware, + ) -> Self { + Self { config, client } + } + + /// Retrieve a pruned, hierarchical view of an APM trace by its trace ID. + /// The trace is summarized as a tree of spans rooted at the trace root and reduced in size + /// to keep rendering large traces in the UI practical. + /// This endpoint is rate limited to `60` requests per minute per organization. + pub async fn get_pruned_trace_by_id( + &self, + trace_id: String, + params: GetPrunedTraceByIDOptionalParams, + ) -> Result> + { + match self + .get_pruned_trace_by_id_with_http_info(trace_id, params) + .await + { + Ok(response_content) => { + if let Some(e) = response_content.entity { + Ok(e) + } else { + Err(datadog::Error::Serde(serde::de::Error::custom( + "response content was None", + ))) + } + } + Err(err) => Err(err), + } + } + + /// Retrieve a pruned, hierarchical view of an APM trace by its trace ID. + /// The trace is summarized as a tree of spans rooted at the trace root and reduced in size + /// to keep rendering large traces in the UI practical. + /// This endpoint is rate limited to `60` requests per minute per organization. + pub async fn get_pruned_trace_by_id_with_http_info( + &self, + trace_id: String, + params: GetPrunedTraceByIDOptionalParams, + ) -> Result< + datadog::ResponseContent, + datadog::Error, + > { + let local_configuration = &self.config; + let operation_id = "v2.get_pruned_trace_by_id"; + if local_configuration.is_unstable_operation_enabled(operation_id) { + warn!("Using unstable operation {operation_id}"); + } else { + let local_error = datadog::UnstableOperationDisabledError { + msg: "Operation 'v2.get_pruned_trace_by_id' is not enabled".to_string(), + }; + return Err(datadog::Error::UnstableOperationDisabledError(local_error)); + } + + // unbox and build optional parameters + let expand_span_id = params.expand_span_id; + let time_hint = params.time_hint; + let force_source = params.force_source; + let include_path = params.include_path; + let tag_include = params.tag_include; + let tag_exclude = params.tag_exclude; + let only_service_entry_spans = params.only_service_entry_spans; + + let local_client = &self.client; + + let local_uri_str = format!( + "{}/api/v2/pruned_trace/{trace_id}", + local_configuration.get_operation_host(operation_id), + trace_id = datadog::urlencode(trace_id) + ); + let mut local_req_builder = + local_client.request(reqwest::Method::GET, local_uri_str.as_str()); + + if let Some(ref local_query_param) = expand_span_id { + local_req_builder = + local_req_builder.query(&[("expand_span_id", &local_query_param.to_string())]); + }; + if let Some(ref local_query_param) = time_hint { + local_req_builder = + local_req_builder.query(&[("time_hint", &local_query_param.to_string())]); + }; + if let Some(ref local_query_param) = force_source { + local_req_builder = + local_req_builder.query(&[("force_source", &local_query_param.to_string())]); + }; + if let Some(ref local) = include_path { + for param in local { + local_req_builder = + local_req_builder.query(&[("include_path", ¶m.to_string())]); + } + }; + if let Some(ref local) = tag_include { + for param in local { + local_req_builder = local_req_builder.query(&[("tag_include", ¶m.to_string())]); + } + }; + if let Some(ref local) = tag_exclude { + for param in local { + local_req_builder = local_req_builder.query(&[("tag_exclude", ¶m.to_string())]); + } + }; + if let Some(ref local_query_param) = only_service_entry_spans { + local_req_builder = local_req_builder + .query(&[("only_service_entry_spans", &local_query_param.to_string())]); + }; + + // build headers + let mut headers = HeaderMap::new(); + headers.insert("Accept", HeaderValue::from_static("application/json")); + + // build user agent + match HeaderValue::from_str(local_configuration.user_agent.as_str()) { + Ok(user_agent) => headers.insert(reqwest::header::USER_AGENT, user_agent), + Err(e) => { + log::warn!("Failed to parse user agent header: {e}, falling back to default"); + headers.insert( + reqwest::header::USER_AGENT, + HeaderValue::from_static(datadog::DEFAULT_USER_AGENT.as_str()), + ) + } + }; + + // build auth + if let Some(local_key) = local_configuration.auth_keys.get("apiKeyAuth") { + headers.insert( + "DD-API-KEY", + HeaderValue::from_str(local_key.key.as_str()) + .expect("failed to parse DD-API-KEY header"), + ); + }; + if let Some(local_key) = local_configuration.auth_keys.get("appKeyAuth") { + headers.insert( + "DD-APPLICATION-KEY", + HeaderValue::from_str(local_key.key.as_str()) + .expect("failed to parse DD-APPLICATION-KEY header"), + ); + }; + + local_req_builder = local_req_builder.headers(headers); + let local_req = local_req_builder.build()?; + log::debug!("request content: {:?}", local_req.body()); + let local_resp = local_client.execute(local_req).await?; + + let local_status = local_resp.status(); + let local_content = local_resp.text().await?; + log::debug!("response content: {}", local_content); + + if !local_status.is_client_error() && !local_status.is_server_error() { + match serde_json::from_str::( + &local_content, + ) { + Ok(e) => { + return Ok(datadog::ResponseContent { + status: local_status, + content: local_content, + entity: Some(e), + }) + } + Err(e) => return Err(datadog::Error::Serde(e)), + }; + } else { + let local_entity: Option = + serde_json::from_str(&local_content).ok(); + let local_error = datadog::ResponseContent { + status: local_status, + content: local_content, + entity: local_entity, + }; + Err(datadog::Error::ResponseError(local_error)) + } + } + + /// Retrieve a full APM trace by its trace ID, including every span in the trace. + /// Traces are returned from live storage when available and fall back to longer-term storage. + /// This endpoint is rate limited to `60` requests per minute per organization. + pub async fn get_trace_by_id( + &self, + trace_id: String, + params: GetTraceByIDOptionalParams, + ) -> Result> { + match self.get_trace_by_id_with_http_info(trace_id, params).await { + Ok(response_content) => { + if let Some(e) = response_content.entity { + Ok(e) + } else { + Err(datadog::Error::Serde(serde::de::Error::custom( + "response content was None", + ))) + } + } + Err(err) => Err(err), + } + } + + /// Retrieve a full APM trace by its trace ID, including every span in the trace. + /// Traces are returned from live storage when available and fall back to longer-term storage. + /// This endpoint is rate limited to `60` requests per minute per organization. + pub async fn get_trace_by_id_with_http_info( + &self, + trace_id: String, + params: GetTraceByIDOptionalParams, + ) -> Result< + datadog::ResponseContent, + datadog::Error, + > { + let local_configuration = &self.config; + let operation_id = "v2.get_trace_by_id"; + if local_configuration.is_unstable_operation_enabled(operation_id) { + warn!("Using unstable operation {operation_id}"); + } else { + let local_error = datadog::UnstableOperationDisabledError { + msg: "Operation 'v2.get_trace_by_id' is not enabled".to_string(), + }; + return Err(datadog::Error::UnstableOperationDisabledError(local_error)); + } + + // unbox and build optional parameters + let include_fields = params.include_fields; + + let local_client = &self.client; + + let local_uri_str = format!( + "{}/api/v2/trace/{trace_id}", + local_configuration.get_operation_host(operation_id), + trace_id = datadog::urlencode(trace_id) + ); + let mut local_req_builder = + local_client.request(reqwest::Method::GET, local_uri_str.as_str()); + + if let Some(ref local) = include_fields { + for param in local { + local_req_builder = + local_req_builder.query(&[("include_fields", ¶m.to_string())]); + } + }; + + // build headers + let mut headers = HeaderMap::new(); + headers.insert("Accept", HeaderValue::from_static("application/json")); + + // build user agent + match HeaderValue::from_str(local_configuration.user_agent.as_str()) { + Ok(user_agent) => headers.insert(reqwest::header::USER_AGENT, user_agent), + Err(e) => { + log::warn!("Failed to parse user agent header: {e}, falling back to default"); + headers.insert( + reqwest::header::USER_AGENT, + HeaderValue::from_static(datadog::DEFAULT_USER_AGENT.as_str()), + ) + } + }; + + // build auth + if let Some(local_key) = local_configuration.auth_keys.get("apiKeyAuth") { + headers.insert( + "DD-API-KEY", + HeaderValue::from_str(local_key.key.as_str()) + .expect("failed to parse DD-API-KEY header"), + ); + }; + if let Some(local_key) = local_configuration.auth_keys.get("appKeyAuth") { + headers.insert( + "DD-APPLICATION-KEY", + HeaderValue::from_str(local_key.key.as_str()) + .expect("failed to parse DD-APPLICATION-KEY header"), + ); + }; + + local_req_builder = local_req_builder.headers(headers); + let local_req = local_req_builder.build()?; + log::debug!("request content: {:?}", local_req.body()); + let local_resp = local_client.execute(local_req).await?; + + let local_status = local_resp.status(); + let local_content = local_resp.text().await?; + log::debug!("response content: {}", local_content); + + if !local_status.is_client_error() && !local_status.is_server_error() { + match serde_json::from_str::(&local_content) { + Ok(e) => { + return Ok(datadog::ResponseContent { + status: local_status, + content: local_content, + entity: Some(e), + }) + } + Err(e) => return Err(datadog::Error::Serde(e)), + }; + } else { + let local_entity: Option = serde_json::from_str(&local_content).ok(); + let local_error = datadog::ResponseContent { + status: local_status, + content: local_content, + entity: local_entity, + }; + Err(datadog::Error::ResponseError(local_error)) + } + } +} diff --git a/src/datadogV2/api/mod.rs b/src/datadogV2/api/mod.rs index bc2661dc38..b5b471d77e 100644 --- a/src/datadogV2/api/mod.rs +++ b/src/datadogV2/api/mod.rs @@ -8,6 +8,7 @@ pub mod api_agentless_scanning; pub mod api_api_management; pub mod api_apm; pub mod api_apm_retention_filters; +pub mod api_apm_trace; pub mod api_app_builder; pub mod api_application_security; pub mod api_audit; diff --git a/src/datadogV2/mod.rs b/src/datadogV2/mod.rs index ecaff62f33..4ffd4cd13b 100644 --- a/src/datadogV2/mod.rs +++ b/src/datadogV2/mod.rs @@ -9,6 +9,7 @@ pub use self::api::api_agentless_scanning; pub use self::api::api_api_management; pub use self::api::api_apm; pub use self::api::api_apm_retention_filters; +pub use self::api::api_apm_trace; pub use self::api::api_app_builder; pub use self::api::api_application_security; pub use self::api::api_audit; diff --git a/src/datadogV2/model/mod.rs b/src/datadogV2/model/mod.rs index 241d03d01e..c307d73f3a 100644 --- a/src/datadogV2/model/mod.rs +++ b/src/datadogV2/model/mod.rs @@ -7808,6 +7808,20 @@ pub mod model_list_connections_response_data_attributes_connections_items_join; pub use self::model_list_connections_response_data_attributes_connections_items_join::ListConnectionsResponseDataAttributesConnectionsItemsJoin; pub mod model_list_connections_response_data_type; pub use self::model_list_connections_response_data_type::ListConnectionsResponseDataType; +pub mod model_pruned_trace_response; +pub use self::model_pruned_trace_response::PrunedTraceResponse; +pub mod model_pruned_trace_data; +pub use self::model_pruned_trace_data::PrunedTraceData; +pub mod model_pruned_trace_attributes; +pub use self::model_pruned_trace_attributes::PrunedTraceAttributes; +pub mod model_summarized_trace; +pub use self::model_summarized_trace::SummarizedTrace; +pub mod model_summarized_span; +pub use self::model_summarized_span::SummarizedSpan; +pub mod model_apm_span_error_flag; +pub use self::model_apm_span_error_flag::APMSpanErrorFlag; +pub mod model_pruned_trace_type; +pub use self::model_pruned_trace_type::PrunedTraceType; pub mod model_scalar_formula_query_request; pub use self::model_scalar_formula_query_request::ScalarFormulaQueryRequest; pub mod model_scalar_formula_request; @@ -11476,6 +11490,16 @@ pub mod model_flaky_tests_search_response_meta; pub use self::model_flaky_tests_search_response_meta::FlakyTestsSearchResponseMeta; pub mod model_flaky_tests_pagination; pub use self::model_flaky_tests_pagination::FlakyTestsPagination; +pub mod model_trace_response; +pub use self::model_trace_response::TraceResponse; +pub mod model_trace_data; +pub use self::model_trace_data::TraceData; +pub mod model_trace_attributes; +pub use self::model_trace_attributes::TraceAttributes; +pub mod model_apm_trace_span; +pub use self::model_apm_trace_span::APMTraceSpan; +pub mod model_trace_type; +pub use self::model_trace_type::TraceType; pub mod model_usage_application_security_monitoring_response; pub use self::model_usage_application_security_monitoring_response::UsageApplicationSecurityMonitoringResponse; pub mod model_usage_data_object; diff --git a/src/datadogV2/model/model_apm_span_error_flag.rs b/src/datadogV2/model/model_apm_span_error_flag.rs new file mode 100644 index 0000000000..2faf9ce28a --- /dev/null +++ b/src/datadogV2/model/model_apm_span_error_flag.rs @@ -0,0 +1,42 @@ +// Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2019-Present Datadog, Inc. + +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +#[non_exhaustive] +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum APMSpanErrorFlag { + NO_ERROR, + ERROR, + UnparsedObject(crate::datadog::UnparsedObject), +} + +impl Serialize for APMSpanErrorFlag { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match self { + Self::UnparsedObject(v) => v.serialize(serializer), + Self::NO_ERROR => serializer.serialize_i32(0), + Self::ERROR => serializer.serialize_i32(1), + } + } +} + +impl<'de> Deserialize<'de> for APMSpanErrorFlag { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s: i32 = i32::deserialize(deserializer)?; + Ok(match s { + 0 => Self::NO_ERROR, + 1 => Self::ERROR, + _ => Self::UnparsedObject(crate::datadog::UnparsedObject { + value: serde_json::Value::Number(s.into()), + }), + }) + } +} diff --git a/src/datadogV2/model/model_apm_trace_span.rs b/src/datadogV2/model/model_apm_trace_span.rs new file mode 100644 index 0000000000..1847df9d40 --- /dev/null +++ b/src/datadogV2/model/model_apm_trace_span.rs @@ -0,0 +1,303 @@ +// Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2019-Present Datadog, Inc. +use serde::de::{Error, MapAccess, Visitor}; +use serde::{Deserialize, Deserializer, Serialize}; +use serde_with::skip_serializing_none; +use std::fmt::{self, Formatter}; + +/// A single APM span returned as part of a trace. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct APMTraceSpan { + /// The duration of the span, in nanoseconds. + #[serde(rename = "duration")] + pub duration: i64, + /// The end time of the span, in Unix nanoseconds. + #[serde(rename = "endTime")] + pub end_time: i64, + /// Error flag for a span. `1` when the span is in error, `0` otherwise. + #[serde(rename = "error")] + pub error: crate::datadogV2::model::APMSpanErrorFlag, + /// String-valued tags attached to the span. Tag keys starting with `_` are + /// filtered out of the response. + #[serde(rename = "meta")] + pub meta: std::collections::BTreeMap, + /// Numeric metrics attached to the span. Metric keys starting with `_` are + /// filtered out of the response. + #[serde(rename = "metrics")] + pub metrics: std::collections::BTreeMap, + /// The operation name of the span. + #[serde(rename = "name")] + pub name: String, + /// The ID of the parent span, or `0` when the span is a trace root. + #[serde(rename = "parentID")] + pub parent_id: i64, + /// The resource that the span describes. + #[serde(rename = "resource")] + pub resource: String, + /// A hash of the resource field. + #[serde(rename = "resourceHash")] + pub resource_hash: Option, + /// Whether access to the span is restricted by the organization's data access policies. + #[serde(rename = "restricted")] + pub restricted: Option, + /// The time spent in the span itself, excluding time spent in child spans, in nanoseconds. + #[serde(rename = "self_time")] + pub self_time: Option, + /// The name of the service that emitted the span. + #[serde(rename = "service")] + pub service: String, + /// The span ID, as an unsigned 64-bit integer. + #[serde(rename = "spanID")] + pub span_id: i64, + /// The start time of the span, in Unix nanoseconds. + #[serde(rename = "startTime")] + pub start_time: i64, + /// The lower 64 bits of the trace ID, as an unsigned 64-bit integer. + #[serde(rename = "traceID")] + pub trace_id: i64, + /// The full 128-bit trace ID, encoded as a 32-character hexadecimal string. + #[serde(rename = "traceIDFull")] + pub trace_id_full: String, + /// The type of the span (for example, `web`, `db`, or `rpc`). + #[serde(rename = "type")] + pub type_: String, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl APMTraceSpan { + pub fn new( + duration: i64, + end_time: i64, + error: crate::datadogV2::model::APMSpanErrorFlag, + meta: std::collections::BTreeMap, + metrics: std::collections::BTreeMap, + name: String, + parent_id: i64, + resource: String, + service: String, + span_id: i64, + start_time: i64, + trace_id: i64, + trace_id_full: String, + type_: String, + ) -> APMTraceSpan { + APMTraceSpan { + duration, + end_time, + error, + meta, + metrics, + name, + parent_id, + resource, + resource_hash: None, + restricted: None, + self_time: None, + service, + span_id, + start_time, + trace_id, + trace_id_full, + type_, + additional_properties: std::collections::BTreeMap::new(), + _unparsed: false, + } + } + + pub fn resource_hash(mut self, value: String) -> Self { + self.resource_hash = Some(value); + self + } + + pub fn restricted(mut self, value: bool) -> Self { + self.restricted = Some(value); + self + } + + pub fn self_time(mut self, value: f64) -> Self { + self.self_time = Some(value); + self + } + + pub fn additional_properties( + mut self, + value: std::collections::BTreeMap, + ) -> Self { + self.additional_properties = value; + self + } +} + +impl<'de> Deserialize<'de> for APMTraceSpan { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct APMTraceSpanVisitor; + impl<'a> Visitor<'a> for APMTraceSpanVisitor { + type Value = APMTraceSpan; + + fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_str("a mapping") + } + + fn visit_map(self, mut map: M) -> Result + where + M: MapAccess<'a>, + { + let mut duration: Option = None; + let mut end_time: Option = None; + let mut error: Option = None; + let mut meta: Option> = None; + let mut metrics: Option> = None; + let mut name: Option = None; + let mut parent_id: Option = None; + let mut resource: Option = None; + let mut resource_hash: Option = None; + let mut restricted: Option = None; + let mut self_time: Option = None; + let mut service: Option = None; + let mut span_id: Option = None; + let mut start_time: Option = None; + let mut trace_id: Option = None; + let mut trace_id_full: Option = None; + let mut type_: Option = None; + let mut additional_properties: std::collections::BTreeMap< + String, + serde_json::Value, + > = std::collections::BTreeMap::new(); + let mut _unparsed = false; + + while let Some((k, v)) = map.next_entry::()? { + match k.as_str() { + "duration" => { + duration = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "endTime" => { + end_time = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "error" => { + error = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + if let Some(ref _error) = error { + match _error { + crate::datadogV2::model::APMSpanErrorFlag::UnparsedObject( + _error, + ) => { + _unparsed = true; + } + _ => {} + } + } + } + "meta" => { + meta = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "metrics" => { + metrics = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "name" => { + name = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "parentID" => { + parent_id = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "resource" => { + resource = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "resourceHash" => { + if v.is_null() { + continue; + } + resource_hash = + Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "restricted" => { + if v.is_null() { + continue; + } + restricted = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "self_time" => { + if v.is_null() || v.as_str() == Some("") { + continue; + } + self_time = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "service" => { + service = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "spanID" => { + span_id = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "startTime" => { + start_time = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "traceID" => { + trace_id = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "traceIDFull" => { + trace_id_full = + Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "type" => { + type_ = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + &_ => { + if let Ok(value) = serde_json::from_value(v.clone()) { + additional_properties.insert(k, value); + } + } + } + } + let duration = duration.ok_or_else(|| M::Error::missing_field("duration"))?; + let end_time = end_time.ok_or_else(|| M::Error::missing_field("end_time"))?; + let error = error.ok_or_else(|| M::Error::missing_field("error"))?; + let meta = meta.ok_or_else(|| M::Error::missing_field("meta"))?; + let metrics = metrics.ok_or_else(|| M::Error::missing_field("metrics"))?; + let name = name.ok_or_else(|| M::Error::missing_field("name"))?; + let parent_id = parent_id.ok_or_else(|| M::Error::missing_field("parent_id"))?; + let resource = resource.ok_or_else(|| M::Error::missing_field("resource"))?; + let service = service.ok_or_else(|| M::Error::missing_field("service"))?; + let span_id = span_id.ok_or_else(|| M::Error::missing_field("span_id"))?; + let start_time = start_time.ok_or_else(|| M::Error::missing_field("start_time"))?; + let trace_id = trace_id.ok_or_else(|| M::Error::missing_field("trace_id"))?; + let trace_id_full = + trace_id_full.ok_or_else(|| M::Error::missing_field("trace_id_full"))?; + let type_ = type_.ok_or_else(|| M::Error::missing_field("type_"))?; + + let content = APMTraceSpan { + duration, + end_time, + error, + meta, + metrics, + name, + parent_id, + resource, + resource_hash, + restricted, + self_time, + service, + span_id, + start_time, + trace_id, + trace_id_full, + type_, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(APMTraceSpanVisitor) + } +} diff --git a/src/datadogV2/model/model_pruned_trace_attributes.rs b/src/datadogV2/model/model_pruned_trace_attributes.rs new file mode 100644 index 0000000000..5d70339e16 --- /dev/null +++ b/src/datadogV2/model/model_pruned_trace_attributes.rs @@ -0,0 +1,121 @@ +// Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2019-Present Datadog, Inc. +use serde::de::{Error, MapAccess, Visitor}; +use serde::{Deserialize, Deserializer, Serialize}; +use serde_with::skip_serializing_none; +use std::fmt::{self, Formatter}; + +/// The attributes of a pruned trace returned by the Get pruned trace by ID endpoint. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct PrunedTraceAttributes { + /// Indicates whether the underlying trace was truncated because its size + /// exceeded the maximum that can be retrieved from storage. + #[serde(rename = "is_truncated")] + pub is_truncated: bool, + /// The size, in bytes, of the original (non-pruned) trace before summarization. + #[serde(rename = "size_bytes")] + pub size_bytes: i32, + /// A summarized, hierarchical view of a trace. + #[serde(rename = "summarized_trace")] + pub summarized_trace: crate::datadogV2::model::SummarizedTrace, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl PrunedTraceAttributes { + pub fn new( + is_truncated: bool, + size_bytes: i32, + summarized_trace: crate::datadogV2::model::SummarizedTrace, + ) -> PrunedTraceAttributes { + PrunedTraceAttributes { + is_truncated, + size_bytes, + summarized_trace, + additional_properties: std::collections::BTreeMap::new(), + _unparsed: false, + } + } + + pub fn additional_properties( + mut self, + value: std::collections::BTreeMap, + ) -> Self { + self.additional_properties = value; + self + } +} + +impl<'de> Deserialize<'de> for PrunedTraceAttributes { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct PrunedTraceAttributesVisitor; + impl<'a> Visitor<'a> for PrunedTraceAttributesVisitor { + type Value = PrunedTraceAttributes; + + fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_str("a mapping") + } + + fn visit_map(self, mut map: M) -> Result + where + M: MapAccess<'a>, + { + let mut is_truncated: Option = None; + let mut size_bytes: Option = None; + let mut summarized_trace: Option = None; + let mut additional_properties: std::collections::BTreeMap< + String, + serde_json::Value, + > = std::collections::BTreeMap::new(); + let mut _unparsed = false; + + while let Some((k, v)) = map.next_entry::()? { + match k.as_str() { + "is_truncated" => { + is_truncated = + Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "size_bytes" => { + size_bytes = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "summarized_trace" => { + summarized_trace = + Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + &_ => { + if let Ok(value) = serde_json::from_value(v.clone()) { + additional_properties.insert(k, value); + } + } + } + } + let is_truncated = + is_truncated.ok_or_else(|| M::Error::missing_field("is_truncated"))?; + let size_bytes = size_bytes.ok_or_else(|| M::Error::missing_field("size_bytes"))?; + let summarized_trace = + summarized_trace.ok_or_else(|| M::Error::missing_field("summarized_trace"))?; + + let content = PrunedTraceAttributes { + is_truncated, + size_bytes, + summarized_trace, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(PrunedTraceAttributesVisitor) + } +} diff --git a/src/datadogV2/model/model_pruned_trace_data.rs b/src/datadogV2/model/model_pruned_trace_data.rs new file mode 100644 index 0000000000..14bb9600f6 --- /dev/null +++ b/src/datadogV2/model/model_pruned_trace_data.rs @@ -0,0 +1,126 @@ +// Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2019-Present Datadog, Inc. +use serde::de::{Error, MapAccess, Visitor}; +use serde::{Deserialize, Deserializer, Serialize}; +use serde_with::skip_serializing_none; +use std::fmt::{self, Formatter}; + +/// A pruned trace resource document. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct PrunedTraceData { + /// The attributes of a pruned trace returned by the Get pruned trace by ID endpoint. + #[serde(rename = "attributes")] + pub attributes: crate::datadogV2::model::PrunedTraceAttributes, + /// The full 128-bit trace ID, encoded as a 32-character hexadecimal string. + #[serde(rename = "id")] + pub id: String, + /// The type of the pruned trace resource. The value is always `pruned_trace`. + #[serde(rename = "type")] + pub type_: crate::datadogV2::model::PrunedTraceType, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl PrunedTraceData { + pub fn new( + attributes: crate::datadogV2::model::PrunedTraceAttributes, + id: String, + type_: crate::datadogV2::model::PrunedTraceType, + ) -> PrunedTraceData { + PrunedTraceData { + attributes, + id, + type_, + additional_properties: std::collections::BTreeMap::new(), + _unparsed: false, + } + } + + pub fn additional_properties( + mut self, + value: std::collections::BTreeMap, + ) -> Self { + self.additional_properties = value; + self + } +} + +impl<'de> Deserialize<'de> for PrunedTraceData { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct PrunedTraceDataVisitor; + impl<'a> Visitor<'a> for PrunedTraceDataVisitor { + type Value = PrunedTraceData; + + fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_str("a mapping") + } + + fn visit_map(self, mut map: M) -> Result + where + M: MapAccess<'a>, + { + let mut attributes: Option = None; + let mut id: Option = None; + let mut type_: Option = None; + let mut additional_properties: std::collections::BTreeMap< + String, + serde_json::Value, + > = std::collections::BTreeMap::new(); + let mut _unparsed = false; + + while let Some((k, v)) = map.next_entry::()? { + match k.as_str() { + "attributes" => { + attributes = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "id" => { + id = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "type" => { + type_ = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + if let Some(ref _type_) = type_ { + match _type_ { + crate::datadogV2::model::PrunedTraceType::UnparsedObject( + _type_, + ) => { + _unparsed = true; + } + _ => {} + } + } + } + &_ => { + if let Ok(value) = serde_json::from_value(v.clone()) { + additional_properties.insert(k, value); + } + } + } + } + let attributes = attributes.ok_or_else(|| M::Error::missing_field("attributes"))?; + let id = id.ok_or_else(|| M::Error::missing_field("id"))?; + let type_ = type_.ok_or_else(|| M::Error::missing_field("type_"))?; + + let content = PrunedTraceData { + attributes, + id, + type_, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(PrunedTraceDataVisitor) + } +} diff --git a/src/datadogV2/model/model_pruned_trace_response.rs b/src/datadogV2/model/model_pruned_trace_response.rs new file mode 100644 index 0000000000..ba8be38516 --- /dev/null +++ b/src/datadogV2/model/model_pruned_trace_response.rs @@ -0,0 +1,92 @@ +// Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2019-Present Datadog, Inc. +use serde::de::{Error, MapAccess, Visitor}; +use serde::{Deserialize, Deserializer, Serialize}; +use serde_with::skip_serializing_none; +use std::fmt::{self, Formatter}; + +/// Response containing a single pruned trace. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct PrunedTraceResponse { + /// A pruned trace resource document. + #[serde(rename = "data")] + pub data: crate::datadogV2::model::PrunedTraceData, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl PrunedTraceResponse { + pub fn new(data: crate::datadogV2::model::PrunedTraceData) -> PrunedTraceResponse { + PrunedTraceResponse { + data, + additional_properties: std::collections::BTreeMap::new(), + _unparsed: false, + } + } + + pub fn additional_properties( + mut self, + value: std::collections::BTreeMap, + ) -> Self { + self.additional_properties = value; + self + } +} + +impl<'de> Deserialize<'de> for PrunedTraceResponse { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct PrunedTraceResponseVisitor; + impl<'a> Visitor<'a> for PrunedTraceResponseVisitor { + type Value = PrunedTraceResponse; + + fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_str("a mapping") + } + + fn visit_map(self, mut map: M) -> Result + where + M: MapAccess<'a>, + { + let mut data: Option = None; + let mut additional_properties: std::collections::BTreeMap< + String, + serde_json::Value, + > = std::collections::BTreeMap::new(); + let mut _unparsed = false; + + while let Some((k, v)) = map.next_entry::()? { + match k.as_str() { + "data" => { + data = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + &_ => { + if let Ok(value) = serde_json::from_value(v.clone()) { + additional_properties.insert(k, value); + } + } + } + } + let data = data.ok_or_else(|| M::Error::missing_field("data"))?; + + let content = PrunedTraceResponse { + data, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(PrunedTraceResponseVisitor) + } +} diff --git a/src/datadogV2/model/model_pruned_trace_type.rs b/src/datadogV2/model/model_pruned_trace_type.rs new file mode 100644 index 0000000000..b47eb84251 --- /dev/null +++ b/src/datadogV2/model/model_pruned_trace_type.rs @@ -0,0 +1,48 @@ +// Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2019-Present Datadog, Inc. + +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +#[non_exhaustive] +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum PrunedTraceType { + PRUNED_TRACE, + UnparsedObject(crate::datadog::UnparsedObject), +} + +impl ToString for PrunedTraceType { + fn to_string(&self) -> String { + match self { + Self::PRUNED_TRACE => String::from("pruned_trace"), + Self::UnparsedObject(v) => v.value.to_string(), + } + } +} + +impl Serialize for PrunedTraceType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match self { + Self::UnparsedObject(v) => v.serialize(serializer), + _ => serializer.serialize_str(self.to_string().as_str()), + } + } +} + +impl<'de> Deserialize<'de> for PrunedTraceType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s: String = String::deserialize(deserializer)?; + Ok(match s.as_str() { + "pruned_trace" => Self::PRUNED_TRACE, + _ => Self::UnparsedObject(crate::datadog::UnparsedObject { + value: serde_json::Value::String(s.into()), + }), + }) + } +} diff --git a/src/datadogV2/model/model_summarized_span.rs b/src/datadogV2/model/model_summarized_span.rs new file mode 100644 index 0000000000..92da2cf48e --- /dev/null +++ b/src/datadogV2/model/model_summarized_span.rs @@ -0,0 +1,252 @@ +// Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2019-Present Datadog, Inc. +use serde::de::{Error, MapAccess, Visitor}; +use serde::{Deserialize, Deserializer, Serialize}; +use serde_with::skip_serializing_none; +use std::fmt::{self, Formatter}; + +/// A node in the pruned trace tree. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct SummarizedSpan { + /// The child spans of this node in the pruned tree. + #[serde(rename = "children")] + pub children: Vec, + /// The duration of the span, in seconds. + #[serde(rename = "durationSeconds")] + pub duration_seconds: f64, + /// The end time of the span, in RFC3339 format. + #[serde(rename = "endTime")] + pub end_time: chrono::DateTime, + /// Error flag for a span. `1` when the span is in error, `0` otherwise. + #[serde(rename = "error")] + pub error: crate::datadogV2::model::APMSpanErrorFlag, + /// The number of child spans that were pruned from this node when summarizing the trace. + #[serde(rename = "hidden_child_spans_count")] + pub hidden_child_spans_count: i32, + /// String-valued tags attached to the span. + #[serde(rename = "meta")] + pub meta: std::collections::BTreeMap, + /// Numeric metrics attached to the span. + #[serde(rename = "metrics")] + pub metrics: std::collections::BTreeMap, + /// The operation name of the span. + #[serde(rename = "name")] + pub name: String, + /// The ID of the parent span, or `0` when the span is the trace root. + #[serde(rename = "parentID")] + pub parent_id: i64, + /// The resource that the span describes. + #[serde(rename = "resource")] + pub resource: String, + /// The name of the service that emitted the span. + #[serde(rename = "service")] + pub service: String, + /// The span ID, as an unsigned 64-bit integer. + #[serde(rename = "spanID")] + pub span_id: i64, + /// The OpenTelemetry span kind, for example `INTERNAL`, `SERVER`, `CLIENT`, + /// `PRODUCER`, or `CONSUMER`. + #[serde(rename = "span_kind")] + pub span_kind: String, + /// The start time of the span, in RFC3339 format. + #[serde(rename = "startTime")] + pub start_time: chrono::DateTime, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl SummarizedSpan { + pub fn new( + children: Vec, + duration_seconds: f64, + end_time: chrono::DateTime, + error: crate::datadogV2::model::APMSpanErrorFlag, + hidden_child_spans_count: i32, + meta: std::collections::BTreeMap, + metrics: std::collections::BTreeMap, + name: String, + parent_id: i64, + resource: String, + service: String, + span_id: i64, + span_kind: String, + start_time: chrono::DateTime, + ) -> SummarizedSpan { + SummarizedSpan { + children, + duration_seconds, + end_time, + error, + hidden_child_spans_count, + meta, + metrics, + name, + parent_id, + resource, + service, + span_id, + span_kind, + start_time, + additional_properties: std::collections::BTreeMap::new(), + _unparsed: false, + } + } + + pub fn additional_properties( + mut self, + value: std::collections::BTreeMap, + ) -> Self { + self.additional_properties = value; + self + } +} + +impl<'de> Deserialize<'de> for SummarizedSpan { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct SummarizedSpanVisitor; + impl<'a> Visitor<'a> for SummarizedSpanVisitor { + type Value = SummarizedSpan; + + fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_str("a mapping") + } + + fn visit_map(self, mut map: M) -> Result + where + M: MapAccess<'a>, + { + let mut children: Option> = None; + let mut duration_seconds: Option = None; + let mut end_time: Option> = None; + let mut error: Option = None; + let mut hidden_child_spans_count: Option = None; + let mut meta: Option> = None; + let mut metrics: Option> = None; + let mut name: Option = None; + let mut parent_id: Option = None; + let mut resource: Option = None; + let mut service: Option = None; + let mut span_id: Option = None; + let mut span_kind: Option = None; + let mut start_time: Option> = None; + let mut additional_properties: std::collections::BTreeMap< + String, + serde_json::Value, + > = std::collections::BTreeMap::new(); + let mut _unparsed = false; + + while let Some((k, v)) = map.next_entry::()? { + match k.as_str() { + "children" => { + children = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "durationSeconds" => { + duration_seconds = + Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "endTime" => { + end_time = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "error" => { + error = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + if let Some(ref _error) = error { + match _error { + crate::datadogV2::model::APMSpanErrorFlag::UnparsedObject( + _error, + ) => { + _unparsed = true; + } + _ => {} + } + } + } + "hidden_child_spans_count" => { + hidden_child_spans_count = + Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "meta" => { + meta = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "metrics" => { + metrics = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "name" => { + name = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "parentID" => { + parent_id = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "resource" => { + resource = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "service" => { + service = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "spanID" => { + span_id = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "span_kind" => { + span_kind = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "startTime" => { + start_time = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + &_ => { + if let Ok(value) = serde_json::from_value(v.clone()) { + additional_properties.insert(k, value); + } + } + } + } + let children = children.ok_or_else(|| M::Error::missing_field("children"))?; + let duration_seconds = + duration_seconds.ok_or_else(|| M::Error::missing_field("duration_seconds"))?; + let end_time = end_time.ok_or_else(|| M::Error::missing_field("end_time"))?; + let error = error.ok_or_else(|| M::Error::missing_field("error"))?; + let hidden_child_spans_count = hidden_child_spans_count + .ok_or_else(|| M::Error::missing_field("hidden_child_spans_count"))?; + let meta = meta.ok_or_else(|| M::Error::missing_field("meta"))?; + let metrics = metrics.ok_or_else(|| M::Error::missing_field("metrics"))?; + let name = name.ok_or_else(|| M::Error::missing_field("name"))?; + let parent_id = parent_id.ok_or_else(|| M::Error::missing_field("parent_id"))?; + let resource = resource.ok_or_else(|| M::Error::missing_field("resource"))?; + let service = service.ok_or_else(|| M::Error::missing_field("service"))?; + let span_id = span_id.ok_or_else(|| M::Error::missing_field("span_id"))?; + let span_kind = span_kind.ok_or_else(|| M::Error::missing_field("span_kind"))?; + let start_time = start_time.ok_or_else(|| M::Error::missing_field("start_time"))?; + + let content = SummarizedSpan { + children, + duration_seconds, + end_time, + error, + hidden_child_spans_count, + meta, + metrics, + name, + parent_id, + resource, + service, + span_id, + span_kind, + start_time, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(SummarizedSpanVisitor) + } +} diff --git a/src/datadogV2/model/model_summarized_trace.rs b/src/datadogV2/model/model_summarized_trace.rs new file mode 100644 index 0000000000..1589b9632c --- /dev/null +++ b/src/datadogV2/model/model_summarized_trace.rs @@ -0,0 +1,102 @@ +// Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2019-Present Datadog, Inc. +use serde::de::{Error, MapAccess, Visitor}; +use serde::{Deserialize, Deserializer, Serialize}; +use serde_with::skip_serializing_none; +use std::fmt::{self, Formatter}; + +/// A summarized, hierarchical view of a trace. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct SummarizedTrace { + /// A node in the pruned trace tree. + #[serde(rename = "root")] + pub root: crate::datadogV2::model::SummarizedSpan, + /// The full 128-bit trace ID, encoded as a 32-character hexadecimal string. + #[serde(rename = "traceId")] + pub trace_id: String, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl SummarizedTrace { + pub fn new(root: crate::datadogV2::model::SummarizedSpan, trace_id: String) -> SummarizedTrace { + SummarizedTrace { + root, + trace_id, + additional_properties: std::collections::BTreeMap::new(), + _unparsed: false, + } + } + + pub fn additional_properties( + mut self, + value: std::collections::BTreeMap, + ) -> Self { + self.additional_properties = value; + self + } +} + +impl<'de> Deserialize<'de> for SummarizedTrace { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct SummarizedTraceVisitor; + impl<'a> Visitor<'a> for SummarizedTraceVisitor { + type Value = SummarizedTrace; + + fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_str("a mapping") + } + + fn visit_map(self, mut map: M) -> Result + where + M: MapAccess<'a>, + { + let mut root: Option = None; + let mut trace_id: Option = None; + let mut additional_properties: std::collections::BTreeMap< + String, + serde_json::Value, + > = std::collections::BTreeMap::new(); + let mut _unparsed = false; + + while let Some((k, v)) = map.next_entry::()? { + match k.as_str() { + "root" => { + root = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "traceId" => { + trace_id = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + &_ => { + if let Ok(value) = serde_json::from_value(v.clone()) { + additional_properties.insert(k, value); + } + } + } + } + let root = root.ok_or_else(|| M::Error::missing_field("root"))?; + let trace_id = trace_id.ok_or_else(|| M::Error::missing_field("trace_id"))?; + + let content = SummarizedTrace { + root, + trace_id, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(SummarizedTraceVisitor) + } +} diff --git a/src/datadogV2/model/model_trace_attributes.rs b/src/datadogV2/model/model_trace_attributes.rs new file mode 100644 index 0000000000..2dbd9cd5d4 --- /dev/null +++ b/src/datadogV2/model/model_trace_attributes.rs @@ -0,0 +1,107 @@ +// Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2019-Present Datadog, Inc. +use serde::de::{Error, MapAccess, Visitor}; +use serde::{Deserialize, Deserializer, Serialize}; +use serde_with::skip_serializing_none; +use std::fmt::{self, Formatter}; + +/// The attributes of a trace returned by the Get trace by ID endpoint. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct TraceAttributes { + /// Indicates whether the trace was truncated because its size exceeded the maximum response payload. + #[serde(rename = "is_truncated")] + pub is_truncated: bool, + /// The list of spans that compose the trace. + #[serde(rename = "spans")] + pub spans: Vec, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl TraceAttributes { + pub fn new( + is_truncated: bool, + spans: Vec, + ) -> TraceAttributes { + TraceAttributes { + is_truncated, + spans, + additional_properties: std::collections::BTreeMap::new(), + _unparsed: false, + } + } + + pub fn additional_properties( + mut self, + value: std::collections::BTreeMap, + ) -> Self { + self.additional_properties = value; + self + } +} + +impl<'de> Deserialize<'de> for TraceAttributes { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct TraceAttributesVisitor; + impl<'a> Visitor<'a> for TraceAttributesVisitor { + type Value = TraceAttributes; + + fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_str("a mapping") + } + + fn visit_map(self, mut map: M) -> Result + where + M: MapAccess<'a>, + { + let mut is_truncated: Option = None; + let mut spans: Option> = None; + let mut additional_properties: std::collections::BTreeMap< + String, + serde_json::Value, + > = std::collections::BTreeMap::new(); + let mut _unparsed = false; + + while let Some((k, v)) = map.next_entry::()? { + match k.as_str() { + "is_truncated" => { + is_truncated = + Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "spans" => { + spans = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + &_ => { + if let Ok(value) = serde_json::from_value(v.clone()) { + additional_properties.insert(k, value); + } + } + } + } + let is_truncated = + is_truncated.ok_or_else(|| M::Error::missing_field("is_truncated"))?; + let spans = spans.ok_or_else(|| M::Error::missing_field("spans"))?; + + let content = TraceAttributes { + is_truncated, + spans, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(TraceAttributesVisitor) + } +} diff --git a/src/datadogV2/model/model_trace_data.rs b/src/datadogV2/model/model_trace_data.rs new file mode 100644 index 0000000000..69f1d3b246 --- /dev/null +++ b/src/datadogV2/model/model_trace_data.rs @@ -0,0 +1,124 @@ +// Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2019-Present Datadog, Inc. +use serde::de::{Error, MapAccess, Visitor}; +use serde::{Deserialize, Deserializer, Serialize}; +use serde_with::skip_serializing_none; +use std::fmt::{self, Formatter}; + +/// A trace resource document. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct TraceData { + /// The attributes of a trace returned by the Get trace by ID endpoint. + #[serde(rename = "attributes")] + pub attributes: crate::datadogV2::model::TraceAttributes, + /// The full 128-bit trace ID, encoded as a 32-character hexadecimal string. + #[serde(rename = "id")] + pub id: String, + /// The type of the trace resource. The value is always `trace`. + #[serde(rename = "type")] + pub type_: crate::datadogV2::model::TraceType, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl TraceData { + pub fn new( + attributes: crate::datadogV2::model::TraceAttributes, + id: String, + type_: crate::datadogV2::model::TraceType, + ) -> TraceData { + TraceData { + attributes, + id, + type_, + additional_properties: std::collections::BTreeMap::new(), + _unparsed: false, + } + } + + pub fn additional_properties( + mut self, + value: std::collections::BTreeMap, + ) -> Self { + self.additional_properties = value; + self + } +} + +impl<'de> Deserialize<'de> for TraceData { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct TraceDataVisitor; + impl<'a> Visitor<'a> for TraceDataVisitor { + type Value = TraceData; + + fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_str("a mapping") + } + + fn visit_map(self, mut map: M) -> Result + where + M: MapAccess<'a>, + { + let mut attributes: Option = None; + let mut id: Option = None; + let mut type_: Option = None; + let mut additional_properties: std::collections::BTreeMap< + String, + serde_json::Value, + > = std::collections::BTreeMap::new(); + let mut _unparsed = false; + + while let Some((k, v)) = map.next_entry::()? { + match k.as_str() { + "attributes" => { + attributes = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "id" => { + id = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "type" => { + type_ = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + if let Some(ref _type_) = type_ { + match _type_ { + crate::datadogV2::model::TraceType::UnparsedObject(_type_) => { + _unparsed = true; + } + _ => {} + } + } + } + &_ => { + if let Ok(value) = serde_json::from_value(v.clone()) { + additional_properties.insert(k, value); + } + } + } + } + let attributes = attributes.ok_or_else(|| M::Error::missing_field("attributes"))?; + let id = id.ok_or_else(|| M::Error::missing_field("id"))?; + let type_ = type_.ok_or_else(|| M::Error::missing_field("type_"))?; + + let content = TraceData { + attributes, + id, + type_, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(TraceDataVisitor) + } +} diff --git a/src/datadogV2/model/model_trace_response.rs b/src/datadogV2/model/model_trace_response.rs new file mode 100644 index 0000000000..8596dc3d71 --- /dev/null +++ b/src/datadogV2/model/model_trace_response.rs @@ -0,0 +1,92 @@ +// Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2019-Present Datadog, Inc. +use serde::de::{Error, MapAccess, Visitor}; +use serde::{Deserialize, Deserializer, Serialize}; +use serde_with::skip_serializing_none; +use std::fmt::{self, Formatter}; + +/// Response containing a single trace. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct TraceResponse { + /// A trace resource document. + #[serde(rename = "data")] + pub data: crate::datadogV2::model::TraceData, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl TraceResponse { + pub fn new(data: crate::datadogV2::model::TraceData) -> TraceResponse { + TraceResponse { + data, + additional_properties: std::collections::BTreeMap::new(), + _unparsed: false, + } + } + + pub fn additional_properties( + mut self, + value: std::collections::BTreeMap, + ) -> Self { + self.additional_properties = value; + self + } +} + +impl<'de> Deserialize<'de> for TraceResponse { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct TraceResponseVisitor; + impl<'a> Visitor<'a> for TraceResponseVisitor { + type Value = TraceResponse; + + fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_str("a mapping") + } + + fn visit_map(self, mut map: M) -> Result + where + M: MapAccess<'a>, + { + let mut data: Option = None; + let mut additional_properties: std::collections::BTreeMap< + String, + serde_json::Value, + > = std::collections::BTreeMap::new(); + let mut _unparsed = false; + + while let Some((k, v)) = map.next_entry::()? { + match k.as_str() { + "data" => { + data = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + &_ => { + if let Ok(value) = serde_json::from_value(v.clone()) { + additional_properties.insert(k, value); + } + } + } + } + let data = data.ok_or_else(|| M::Error::missing_field("data"))?; + + let content = TraceResponse { + data, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(TraceResponseVisitor) + } +} diff --git a/src/datadogV2/model/model_trace_type.rs b/src/datadogV2/model/model_trace_type.rs new file mode 100644 index 0000000000..5d65362470 --- /dev/null +++ b/src/datadogV2/model/model_trace_type.rs @@ -0,0 +1,48 @@ +// Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2019-Present Datadog, Inc. + +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +#[non_exhaustive] +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum TraceType { + TRACE, + UnparsedObject(crate::datadog::UnparsedObject), +} + +impl ToString for TraceType { + fn to_string(&self) -> String { + match self { + Self::TRACE => String::from("trace"), + Self::UnparsedObject(v) => v.value.to_string(), + } + } +} + +impl Serialize for TraceType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match self { + Self::UnparsedObject(v) => v.serialize(serializer), + _ => serializer.serialize_str(self.to_string().as_str()), + } + } +} + +impl<'de> Deserialize<'de> for TraceType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s: String = String::deserialize(deserializer)?; + Ok(match s.as_str() { + "trace" => Self::TRACE, + _ => Self::UnparsedObject(crate::datadog::UnparsedObject { + value: serde_json::Value::String(s.into()), + }), + }) + } +} diff --git a/tests/scenarios/features/v2/apm_trace.feature b/tests/scenarios/features/v2/apm_trace.feature new file mode 100644 index 0000000000..e5b706b191 --- /dev/null +++ b/tests/scenarios/features/v2/apm_trace.feature @@ -0,0 +1,48 @@ +@endpoint(apm-trace) @endpoint(apm-trace-v2) +Feature: APM Trace + Retrieve full or pruned APM traces by trace ID. + + Background: + Given a valid "apiKeyAuth" key in the system + And a valid "appKeyAuth" key in the system + And an instance of "APMTrace" API + + @generated @skip @team:DataDog/apm-reliability + Scenario: Get a pruned trace by ID returns "Not Found" response + Given operation "GetPrunedTraceByID" enabled + And new "GetPrunedTraceByID" request + And request contains "trace_id" parameter from "REPLACE.ME" + When the request is sent + Then the response status is 404 Not Found + + @generated @skip @team:DataDog/apm-reliability + Scenario: Get a pruned trace by ID returns "OK" response + Given operation "GetPrunedTraceByID" enabled + And new "GetPrunedTraceByID" request + And request contains "trace_id" parameter from "REPLACE.ME" + When the request is sent + Then the response status is 200 OK + + @generated @skip @team:DataDog/apm-reliability + Scenario: Get a trace by ID returns "Not Found" response + Given operation "GetTraceByID" enabled + And new "GetTraceByID" request + And request contains "trace_id" parameter from "REPLACE.ME" + When the request is sent + Then the response status is 404 Not Found + + @generated @skip @team:DataDog/apm-reliability + Scenario: Get a trace by ID returns "OK" response + Given operation "GetTraceByID" enabled + And new "GetTraceByID" request + And request contains "trace_id" parameter from "REPLACE.ME" + When the request is sent + Then the response status is 200 OK + + @generated @skip @team:DataDog/apm-reliability + Scenario: Get a trace by ID returns "Payload Too Large" response + Given operation "GetTraceByID" enabled + And new "GetTraceByID" request + And request contains "trace_id" parameter from "REPLACE.ME" + When the request is sent + Then the response status is 413 Payload Too Large diff --git a/tests/scenarios/features/v2/undo.json b/tests/scenarios/features/v2/undo.json index 30001c2fcc..6b6146033b 100644 --- a/tests/scenarios/features/v2/undo.json +++ b/tests/scenarios/features/v2/undo.json @@ -5344,6 +5344,12 @@ "type": "safe" } }, + "GetPrunedTraceByID": { + "tag": "APM Trace", + "undo": { + "type": "safe" + } + }, "QueryScalarData": { "tag": "Metrics", "undo": { @@ -8139,6 +8145,12 @@ "type": "safe" } }, + "GetTraceByID": { + "tag": "APM Trace", + "undo": { + "type": "safe" + } + }, "GetUsageApplicationSecurityMonitoring": { "tag": "Usage Metering", "undo": { diff --git a/tests/scenarios/function_mappings.rs b/tests/scenarios/function_mappings.rs index 102cefa91b..dab36ba869 100644 --- a/tests/scenarios/function_mappings.rs +++ b/tests/scenarios/function_mappings.rs @@ -160,6 +160,7 @@ pub struct ApiInstances { pub v2_api_product_analytics: Option, pub v2_api_rum_audience_management: Option, + pub v2_api_apm_trace: Option, pub v2_api_reference_tables: Option, pub v2_api_application_security: Option, @@ -1061,6 +1062,14 @@ pub fn initialize_api_instance(world: &mut DatadogWorld, api: String) { world.http_client.as_ref().unwrap().clone() )); } + "APMTrace" => { + world.api_instances.v2_api_apm_trace = Some( + datadogV2::api_apm_trace::APMTraceAPI::with_client_and_config( + world.config.clone(), + world.http_client.as_ref().unwrap().clone(), + ), + ); + } "ReferenceTables" => { world.api_instances.v2_api_reference_tables = Some( datadogV2::api_reference_tables::ReferenceTablesAPI::with_client_and_config( @@ -5642,6 +5651,13 @@ pub fn collect_function_calls(world: &mut DatadogWorld) { world .function_mappings .insert("v2.ListConnections".into(), test_v2_list_connections); + world.function_mappings.insert( + "v2.GetPrunedTraceByID".into(), + test_v2_get_pruned_trace_by_id, + ); + world + .function_mappings + .insert("v2.GetTraceByID".into(), test_v2_get_trace_by_id); world .function_mappings .insert("v2.BatchRowsQuery".into(), test_v2_batch_rows_query); @@ -44348,6 +44364,90 @@ fn test_v2_list_connections(world: &mut DatadogWorld, _parameters: &HashMap) { + let api = world + .api_instances + .v2_api_apm_trace + .as_ref() + .expect("api instance not found"); + let trace_id = serde_json::from_value(_parameters.get("trace_id").unwrap().clone()).unwrap(); + let expand_span_id = _parameters + .get("expand_span_id") + .and_then(|param| Some(serde_json::from_value(param.clone()).unwrap())); + let time_hint = _parameters + .get("time_hint") + .and_then(|param| Some(serde_json::from_value(param.clone()).unwrap())); + let force_source = _parameters + .get("force_source") + .and_then(|param| Some(serde_json::from_value(param.clone()).unwrap())); + let include_path = _parameters + .get("include_path") + .and_then(|param| Some(serde_json::from_value(param.clone()).unwrap())); + let tag_include = _parameters + .get("tag_include") + .and_then(|param| Some(serde_json::from_value(param.clone()).unwrap())); + let tag_exclude = _parameters + .get("tag_exclude") + .and_then(|param| Some(serde_json::from_value(param.clone()).unwrap())); + let only_service_entry_spans = _parameters + .get("only_service_entry_spans") + .and_then(|param| Some(serde_json::from_value(param.clone()).unwrap())); + let mut params = datadogV2::api_apm_trace::GetPrunedTraceByIDOptionalParams::default(); + params.expand_span_id = expand_span_id; + params.time_hint = time_hint; + params.force_source = force_source; + params.include_path = include_path; + params.tag_include = tag_include; + params.tag_exclude = tag_exclude; + params.only_service_entry_spans = only_service_entry_spans; + let response = match block_on(api.get_pruned_trace_by_id_with_http_info(trace_id, params)) { + Ok(response) => response, + Err(error) => { + return match error { + Error::ResponseError(e) => { + world.response.code = e.status.as_u16(); + if let Some(entity) = e.entity { + world.response.object = serde_json::to_value(entity).unwrap(); + } + } + _ => panic!("error parsing response: {error}"), + }; + } + }; + world.response.object = serde_json::to_value(response.entity).unwrap(); + world.response.code = response.status.as_u16(); +} + +fn test_v2_get_trace_by_id(world: &mut DatadogWorld, _parameters: &HashMap) { + let api = world + .api_instances + .v2_api_apm_trace + .as_ref() + .expect("api instance not found"); + let trace_id = serde_json::from_value(_parameters.get("trace_id").unwrap().clone()).unwrap(); + let include_fields = _parameters + .get("include_fields") + .and_then(|param| Some(serde_json::from_value(param.clone()).unwrap())); + let mut params = datadogV2::api_apm_trace::GetTraceByIDOptionalParams::default(); + params.include_fields = include_fields; + let response = match block_on(api.get_trace_by_id_with_http_info(trace_id, params)) { + Ok(response) => response, + Err(error) => { + return match error { + Error::ResponseError(e) => { + world.response.code = e.status.as_u16(); + if let Some(entity) = e.entity { + world.response.object = serde_json::to_value(entity).unwrap(); + } + } + _ => panic!("error parsing response: {error}"), + }; + } + }; + world.response.object = serde_json::to_value(response.entity).unwrap(); + world.response.code = response.status.as_u16(); +} + fn test_v2_batch_rows_query(world: &mut DatadogWorld, _parameters: &HashMap) { let api = world .api_instances