async_inspect/instrument/
mod.rs1use crate::inspector::Inspector;
6use crate::task::TaskId;
7use std::time::Instant;
8
9pub struct InspectContext {
11 pub task_id: TaskId,
13 pub start_time: Instant,
15}
16
17impl InspectContext {
18 #[must_use]
20 pub fn new(task_id: TaskId) -> Self {
21 Self {
22 task_id,
23 start_time: Instant::now(),
24 }
25 }
26
27 #[must_use]
29 pub fn elapsed(&self) -> std::time::Duration {
30 self.start_time.elapsed()
31 }
32}
33
34pub struct PollGuard {
36 task_id: TaskId,
37 start: Instant,
38}
39
40impl PollGuard {
41 #[must_use]
43 pub fn new(task_id: TaskId) -> Self {
44 Inspector::global().poll_started(task_id);
45 Self {
46 task_id,
47 start: Instant::now(),
48 }
49 }
50}
51
52impl Drop for PollGuard {
53 fn drop(&mut self) {
54 let duration = self.start.elapsed();
55 Inspector::global().poll_ended(self.task_id, duration);
56 }
57}
58
59pub struct AwaitGuard {
61 task_id: TaskId,
62 await_point: String,
63 start: Instant,
64}
65
66impl AwaitGuard {
67 #[must_use]
69 pub fn new(task_id: TaskId, await_point: String) -> Self {
70 Inspector::global().await_started(task_id, await_point.clone(), None);
71 Self {
72 task_id,
73 await_point,
74 start: Instant::now(),
75 }
76 }
77}
78
79impl Drop for AwaitGuard {
80 fn drop(&mut self) {
81 let duration = self.start.elapsed();
82 Inspector::global().await_ended(self.task_id, self.await_point.clone(), duration);
83 }
84}
85
86#[macro_export]
106macro_rules! inspect_point {
107 ($label:expr) => {{
108 if let Some(task_id) = $crate::instrument::current_task_id() {
109 $crate::inspector::Inspector::global().inspection_point(
110 task_id,
111 $label.to_string(),
112 None,
113 );
114 }
115 }};
116 ($label:expr, $message:expr) => {{
117 if let Some(task_id) = $crate::instrument::current_task_id() {
118 $crate::inspector::Inspector::global().inspection_point(
119 task_id,
120 $label.to_string(),
121 Some($message.to_string()),
122 );
123 }
124 }};
125}
126
127#[macro_export]
143macro_rules! inspect_task_start {
144 ($name:expr) => {{
145 let task_id = $crate::inspector::Inspector::global().register_task($name.to_string());
146 $crate::instrument::set_current_task_id(task_id);
147 task_id
148 }};
149}
150
151#[macro_export]
153macro_rules! inspect_task_complete {
154 ($task_id:expr) => {{
155 $crate::inspector::Inspector::global().task_completed($task_id);
156 }};
157}
158
159#[macro_export]
161macro_rules! inspect_task_failed {
162 ($task_id:expr) => {{
163 $crate::inspector::Inspector::global().task_failed($task_id, None);
164 }};
165 ($task_id:expr, $error:expr) => {{
166 $crate::inspector::Inspector::global().task_failed($task_id, Some($error.to_string()));
167 }};
168}
169
170thread_local! {
172 static CURRENT_TASK_ID: std::cell::RefCell<Option<TaskId>> = const { std::cell::RefCell::new(None) };
173}
174
175#[must_use]
177pub fn current_task_id() -> Option<TaskId> {
178 CURRENT_TASK_ID.with(|id| *id.borrow())
179}
180
181pub fn set_current_task_id(task_id: TaskId) {
183 CURRENT_TASK_ID.with(|id| *id.borrow_mut() = Some(task_id));
184}
185
186pub fn clear_current_task_id() {
188 CURRENT_TASK_ID.with(|id| *id.borrow_mut() = None);
189}
190
191pub struct TaskGuard {
193 task_id: TaskId,
194}
195
196impl TaskGuard {
197 #[must_use]
199 pub fn new(name: String) -> Self {
200 let task_id = Inspector::global().register_task(name);
201 set_current_task_id(task_id);
202 Self { task_id }
203 }
204
205 #[must_use]
207 pub fn task_id(&self) -> TaskId {
208 self.task_id
209 }
210}
211
212impl Drop for TaskGuard {
213 fn drop(&mut self) {
214 Inspector::global().task_completed(self.task_id);
215 clear_current_task_id();
216 }
217}
218
219pub fn inspect_await_start(label: impl Into<String>, location: Option<String>) {
221 if let Some(task_id) = current_task_id() {
222 Inspector::global().add_event(
223 task_id,
224 crate::timeline::EventKind::AwaitStarted {
225 await_point: label.into(),
226 location,
227 },
228 );
229 }
230}
231
232pub fn inspect_await_end(label: impl Into<String>) {
234 if let Some(task_id) = current_task_id() {
235 Inspector::global().add_event(
238 task_id,
239 crate::timeline::EventKind::AwaitEnded {
240 await_point: label.into(),
241 duration: std::time::Duration::from_micros(0), },
243 );
244 }
245}
246
247#[cfg(test)]
248mod tests {
249 use super::*;
250
251 #[test]
252 fn test_current_task_id() {
253 let task_id = TaskId::new();
254 set_current_task_id(task_id);
255 assert_eq!(current_task_id(), Some(task_id));
256 clear_current_task_id();
257 assert_eq!(current_task_id(), None);
258 }
259
260 #[test]
261 fn test_task_guard() {
262 let guard = TaskGuard::new("test".to_string());
263 let task_id = guard.task_id();
264 assert_eq!(current_task_id(), Some(task_id));
265 drop(guard);
266 assert_eq!(current_task_id(), None);
267 }
268}