tracing_actix/
lib.rs

1//! Actix ActorFuture instrumentation for use with [`tracing`]
2//!
3//! # Example
4//!
5//! ```rust
6//! use actix::prelude::*;
7//! use actix::fut::{ready, ActorFuture};
8//! use tracing::{span, event, Level};
9//! use tracing_actix::ActorInstrument;
10//! #
11//! # // The response type returned by the actor future
12//! # type OriginalActorResponse = ();
13//! # // The error type returned by the actor future
14//! # type MessageError = ();
15//! # // This is the needed result for the DeferredWork message
16//! # // It's a result that combine both Response and Error from the future response.
17//! # type DeferredWorkResult = Result<OriginalActorResponse, MessageError>;
18//! #
19//! # struct ActorState {}
20//! #
21//! # impl ActorState {
22//! #    fn update_from(&mut self, _result: ()) {}
23//! # }
24//! #
25//! # struct OtherActor {}
26//! #
27//! # impl Actor for OtherActor {
28//! #    type Context = Context<Self>;
29//! # }
30//! #
31//! # impl Handler<OtherMessage> for OtherActor {
32//! #    type Result = ();
33//! #
34//! #    fn handle(&mut self, _msg: OtherMessage, _ctx: &mut Context<Self>) -> Self::Result {
35//! #    }
36//! # }
37//! #
38//! # struct OriginalActor{
39//! #     other_actor: Addr<OtherActor>,
40//! #     inner_state: ActorState
41//! # }
42//! #
43//! # impl Actor for OriginalActor{
44//! #     type Context = Context<Self>;
45//! # }
46//! #
47//! # #[derive(Message)]
48//! # #[rtype(result = "Result<(), MessageError>")]
49//! # struct DeferredWork{}
50//! #
51//! # #[derive(Message)]
52//! # #[rtype(result = "()")]
53//! # struct OtherMessage{}
54//!
55//! /// This example is modified from the actix::fut module and intended to show how
56//! /// the `ActorInstrument` trait may be used to integrate tracing `Span`s within
57//! /// asynchronous message handlers.
58//! impl Handler<DeferredWork> for OriginalActor {
59//!     type Result = ResponseActFuture<Self, Result<OriginalActorResponse, MessageError>>;
60//!
61//!     fn handle(
62//!         &mut self,
63//!         _msg: DeferredWork,
64//!         _ctx: &mut Context<Self>,
65//!     ) -> Self::Result {
66//!         // this creates a `Future` representing the `.send` and subsequent `Result` from
67//!         // `other_actor`
68//!         let span = span!(Level::INFO, "deferred work context");
69//!         // Addr<A>::send returns `actix::prelude::Request`, which implements Unpin, so we can wrap
70//!         // into_actor within an ActorInstrument.
71//!         Box::pin(
72//!             self.other_actor
73//!                 .send(OtherMessage {})
74//!                 .into_actor(self)
75//!                 .actor_instrument(span)
76//!                 .map(|result, actor, _ctx| {
77//!                     // Actor's state updated here
78//!                     match result {
79//!                         Ok(v) => {
80//!                             event!(Level::INFO, "I'm within deferred work context");
81//!                             actor.inner_state.update_from(v);
82//!                             Ok(())
83//!                         }
84//!                         // Failed to send message to other_actor
85//!                         Err(e) => {
86//!                             event!(Level::ERROR, "Error from deferred work: {:?}", e);
87//!                             Err(())
88//!                         }
89//!                     }
90//!                 }),
91//!         )
92//!     }
93//! }
94//! #
95//! # #[derive(Message)]
96//! # #[rtype(result = "Pong")]
97//! # struct Ping;
98//! #
99//! # struct Pong;
100//!
101//! /// In this example, there isn't an `actix::prelude::Request` in our `ActorFuture`.
102//! /// Since `ActorInstrument` needs to wrap `ActorFuture + Unpin`, we can't use
103//! /// `async {}.into_actor(self)` because `async {}` doesn't implement `Unpin`.
104//! impl Handler<Ping> for OriginalActor {
105//!     type Result = ResponseActFuture<Self, Pong>;
106//!
107//!     fn handle(
108//!         &mut self,
109//!         _msg: Ping,
110//!         _ctx: &mut Context<Self>,
111//!     ) -> Self::Result {
112//!         // `async {}` doesn't implement Unpin, so it can't be used.
113//!         // `actix::fut::Ready` ActorFutures work fine though.
114//!         let span = span!(Level::INFO, "ping");
115//!         Box::pin(
116//!             ready::<Pong>(Pong {})
117//!                 .actor_instrument(span)
118//!                 .map(|pong, _this, _ctx| {
119//!                     // the pong event occurs in the ping span, even though this is async.
120//!                     event!(Level::INFO, "pong");
121//!                     pong
122//!                 }),
123//!         )
124//!     }
125//! }
126//! ```
127use actix::{Actor, ActorFuture};
128use pin_project_lite::pin_project;
129use std::{
130    pin::Pin,
131    task::{Context, Poll},
132};
133use tracing::Span;
134
135/// Extension trait allowing actor futures to be instrumented with
136/// a `tracing` `Span`.
137pub trait ActorInstrument: Sized {
138    /// Instruments this type with the provided `Span`, returning an
139    /// `ActorInstrumented` wrapper.
140    ///
141    /// When the wrapped actor future is polled, the attached `Span`
142    /// will be entered for the duration of the poll.
143    fn actor_instrument(self, span: Span) -> ActorInstrumented<Self> {
144        ActorInstrumented { inner: self, span }
145    }
146
147    #[inline]
148    fn in_current_actor_span(self) -> ActorInstrumented<Self> {
149        self.actor_instrument(Span::current())
150    }
151}
152
153impl<T: Sized> ActorInstrument for T {}
154
155pin_project! {
156    /// An actor future that has been instrumented with a `tracing` span.
157    #[derive(Debug, Clone)]
158    pub struct ActorInstrumented<T>
159    {
160        #[pin]
161        inner: T,
162        span: Span,
163    }
164}
165
166impl<T: ActorFuture<U>, U: Actor> ActorFuture<U> for ActorInstrumented<T> {
167    type Output = <T as ActorFuture<U>>::Output;
168
169    fn poll(
170        self: Pin<&mut Self>,
171        srv: &mut U,
172        ctx: &mut U::Context,
173        task: &mut Context<'_>,
174    ) -> Poll<Self::Output> {
175        let this = self.project();
176        let _enter = this.span.enter();
177        this.inner.poll(srv, ctx, task)
178    }
179}
180
181impl<T> ActorInstrumented<T> {
182    /// Borrows the `Span` that this type is instrumented by.
183    pub fn span(&self) -> &Span {
184        &self.span
185    }
186
187    /// Mutably borrows the `Span` that this type is instrumented by.
188    pub fn span_mut(&mut self) -> &mut Span {
189        &mut self.span
190    }
191
192    /// Borrows the wrapped type.
193    pub fn inner(&self) -> &T {
194        &self.inner
195    }
196
197    /// Mutably borrows the wrapped type.
198    pub fn inner_mut(&mut self) -> &mut T {
199        &mut self.inner
200    }
201
202    /// Get a pinned reference to the wrapped type.
203    pub fn inner_pin_ref(self: Pin<&Self>) -> Pin<&T> {
204        self.project_ref().inner
205    }
206
207    /// Get a pinned mutable reference to the wrapped type.
208    pub fn inner_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> {
209        self.project().inner
210    }
211
212    /// Consumes the `Instrumented`, returning the wrapped type.
213    ///
214    /// Note that this drops the span.
215    pub fn into_inner(self) -> T {
216        self.inner
217    }
218}