telemetry_rust/middleware/aws/instrumentation/future.rs
1use aws_types::request_id::RequestId;
2use std::{error::Error, future::Future};
3
4use crate::{
5 future::{InstrumentedFuture, InstrumentedFutureContext},
6 middleware::aws::{AwsSpan, AwsSpanBuilder},
7};
8
9impl<T, E> InstrumentedFutureContext<Result<T, E>> for AwsSpan
10where
11 T: RequestId,
12 E: RequestId + Error,
13{
14 fn on_result(self, result: &Result<T, E>) {
15 self.end(result);
16 }
17}
18
19/// Trait for instrumenting AWS futures with automatic span management.
20///
21/// This trait provides a convenient way to wrap AWS SDK futures with OpenTelemetry
22/// instrumentation, automatically handling span creation, error recording, and cleanup.
23///
24/// For automatic span attributes extraction, use [`AwsBuilderInstrument`][`super::AwsBuilderInstrument`] trait.
25///
26/// # Example
27///
28/// ```rust
29/// use aws_sdk_dynamodb::{Client as DynamoClient, types::AttributeValue};
30/// use telemetry_rust::{
31/// KeyValue,
32/// middleware::aws::{AwsInstrument, DynamodbSpanBuilder},
33/// semconv,
34/// };
35///
36/// async fn query_table() -> Result<i32, Box<dyn std::error::Error>> {
37/// let config = aws_config::load_from_env().await;
38/// let dynamo_client = DynamoClient::new(&config);
39/// let resp =
40/// dynamo_client
41/// .query()
42/// .table_name("table_name")
43/// .index_name("my_index")
44/// .key_condition_expression("PK = :pk")
45/// .expression_attribute_values(":pk", AttributeValue::S("Test".to_string()))
46/// .send()
47/// .instrument(DynamodbSpanBuilder::query("table_name").attribute(
48/// KeyValue::new(semconv::AWS_DYNAMODB_INDEX_NAME, "my_index"),
49/// ))
50/// .await?;
51/// println!("DynamoDB items: {:#?}", resp.items());
52/// Ok(resp.count())
53/// }
54/// ```
55pub trait AwsInstrument<T, E, F>
56where
57 T: RequestId,
58 E: RequestId + Error,
59 F: Future<Output = Result<T, E>>,
60{
61 /// Instruments the future with an AWS span.
62 ///
63 /// Creates an instrumented future that will automatically start a span when polled
64 /// and properly handle the result when the future completes.
65 ///
66 /// # Arguments
67 ///
68 /// * `span` - A span builder or span to use for instrumentation
69 ///
70 /// # Returns
71 ///
72 /// An instrumented future that will record AWS operation details
73 fn instrument<'a>(
74 self,
75 span: impl Into<AwsSpanBuilder<'a>>,
76 ) -> InstrumentedFuture<F, AwsSpan>;
77}
78
79impl<T, E, F> AwsInstrument<T, E, F> for F
80where
81 T: RequestId,
82 E: RequestId + Error,
83 F: Future<Output = Result<T, E>>,
84{
85 fn instrument<'a>(
86 self,
87 span: impl Into<AwsSpanBuilder<'a>>,
88 ) -> InstrumentedFuture<F, AwsSpan> {
89 let span = span.into().start();
90 InstrumentedFuture::new(self, span)
91 }
92}