Skip to main content

a2a_rs/adapter/
interceptor.rs

1//! Built-in [`CallInterceptor`](crate::port::CallInterceptor) adapters.
2//!
3//! Concrete interceptors live in the adapter layer (the port is just the trait).
4//! They attach to either transport via `with_interceptor`.
5
6#[cfg(feature = "tracing")]
7use async_trait::async_trait;
8
9#[cfg(feature = "tracing")]
10use crate::domain::A2AError;
11#[cfg(feature = "tracing")]
12use crate::port::{CallContext, CallInterceptor};
13
14/// A [`CallInterceptor`](crate::port::CallInterceptor) that logs each call's
15/// start and outcome via `tracing`.
16///
17/// Register it on a client or server transport to get one structured log line
18/// per call boundary (method, side) plus a success/failure line with the error.
19/// A drop-in for the official SDK's logging interceptor.
20#[cfg(feature = "tracing")]
21#[derive(Debug, Clone, Default)]
22pub struct LoggingInterceptor;
23
24#[cfg(feature = "tracing")]
25#[async_trait]
26impl CallInterceptor for LoggingInterceptor {
27    async fn before(&self, ctx: &CallContext) -> Result<(), A2AError> {
28        tracing::debug!(method = %ctx.method, side = ?ctx.side, "A2A call started");
29        Ok(())
30    }
31
32    async fn after(&self, ctx: &CallContext, outcome: Result<(), &A2AError>) {
33        match outcome {
34            Ok(()) => {
35                tracing::debug!(method = %ctx.method, side = ?ctx.side, "A2A call succeeded")
36            }
37            Err(e) => {
38                tracing::warn!(method = %ctx.method, side = ?ctx.side, error = %e, "A2A call failed")
39            }
40        }
41    }
42}