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}