use aws_smithy_runtime_api::{
box_error::BoxError,
client::{
interceptors::{
Intercept,
context::{
BeforeDeserializationInterceptorContextRef,
BeforeSerializationInterceptorContextRef, BeforeTransmitInterceptorContextRef,
FinalizerInterceptorContextRef,
},
},
runtime_components::RuntimeComponents,
},
};
use aws_smithy_types::config_bag::ConfigBag;
use tracing::Span;
use super::{
DefaultExtractor,
utils::{SpanPauser, StorableOption},
};
#[derive(Debug)]
#[non_exhaustive]
pub struct TracingInterceptor {
pub extractor: DefaultExtractor<Span>,
}
impl Default for TracingInterceptor {
fn default() -> Self {
Self::new()
}
}
impl TracingInterceptor {
pub fn new() -> Self {
Self {
extractor: DefaultExtractor::new(),
}
}
}
impl Intercept for TracingInterceptor {
fn name(&self) -> &'static str {
"TracingInterceptor"
}
fn read_before_execution(
&self,
context: &BeforeSerializationInterceptorContextRef<'_>,
cfg: &mut ConfigBag,
) -> Result<(), BoxError> {
if let Some((_guard, mut span)) = SpanPauser::pause_until(|span| {
span.metadata()
.map(|metadata| metadata.target().contains("::operation::"))
.unwrap_or_default()
}) {
span.record("otel.kind", "client");
self.extractor
.read_before_execution(context, cfg, &mut span)?;
cfg.interceptor_state().store_put(StorableOption::new(span));
Ok(())
} else {
Err("No operation span found")?
}
}
fn read_after_serialization(
&self,
context: &BeforeTransmitInterceptorContextRef<'_>,
_runtime_components: &RuntimeComponents,
cfg: &mut ConfigBag,
) -> Result<(), BoxError> {
let mut so_span = std::mem::take(
cfg.get_mut_from_interceptor_state::<StorableOption<Span>>()
.ok_or("No StorableOption<Span> in the ConfigBag")?,
);
if let Some(span) = so_span.as_mut() {
self.extractor
.read_after_serialization(context, cfg, span)?;
}
cfg.interceptor_state().store_put(so_span);
Ok(())
}
fn read_before_deserialization(
&self,
context: &BeforeDeserializationInterceptorContextRef<'_>,
_runtime_components: &RuntimeComponents,
cfg: &mut ConfigBag,
) -> Result<(), BoxError> {
let mut so_span = std::mem::take(
cfg.get_mut_from_interceptor_state::<StorableOption<Span>>()
.ok_or("No StorableOption<Span> in the ConfigBag")?,
);
if let Some(span) = so_span.as_mut() {
self.extractor
.read_before_deserialization(context, cfg, span)?;
}
cfg.interceptor_state().store_put(so_span);
Ok(())
}
fn read_after_execution(
&self,
context: &FinalizerInterceptorContextRef<'_>,
_runtime_components: &RuntimeComponents,
cfg: &mut ConfigBag,
) -> Result<(), BoxError> {
let mut so_span = std::mem::take(
cfg.get_mut_from_interceptor_state::<StorableOption<Span>>()
.ok_or("No StorableOption<Span> in the ConfigBag")?,
);
if let Some(span) = so_span.as_mut() {
self.extractor.read_after_execution(context, cfg, span)?;
}
Ok(())
}
}