use crate::inspector::Inspector;
use crate::task::TaskId;
use std::time::Instant;
pub struct InspectContext {
pub task_id: TaskId,
pub start_time: Instant,
}
impl InspectContext {
#[must_use]
pub fn new(task_id: TaskId) -> Self {
Self {
task_id,
start_time: Instant::now(),
}
}
#[must_use]
pub fn elapsed(&self) -> std::time::Duration {
self.start_time.elapsed()
}
}
pub struct PollGuard {
task_id: TaskId,
start: Instant,
}
impl PollGuard {
#[must_use]
pub fn new(task_id: TaskId) -> Self {
Inspector::global().poll_started(task_id);
Self {
task_id,
start: Instant::now(),
}
}
}
impl Drop for PollGuard {
fn drop(&mut self) {
let duration = self.start.elapsed();
Inspector::global().poll_ended(self.task_id, duration);
}
}
pub struct AwaitGuard {
task_id: TaskId,
await_point: String,
start: Instant,
}
impl AwaitGuard {
#[must_use]
pub fn new(task_id: TaskId, await_point: String) -> Self {
Inspector::global().await_started(task_id, await_point.clone(), None);
Self {
task_id,
await_point,
start: Instant::now(),
}
}
}
impl Drop for AwaitGuard {
fn drop(&mut self) {
let duration = self.start.elapsed();
Inspector::global().await_ended(self.task_id, self.await_point.clone(), duration);
}
}
#[macro_export]
macro_rules! inspect_point {
($label:expr) => {{
if let Some(task_id) = $crate::instrument::current_task_id() {
$crate::inspector::Inspector::global().inspection_point(
task_id,
$label.to_string(),
None,
);
}
}};
($label:expr, $message:expr) => {{
if let Some(task_id) = $crate::instrument::current_task_id() {
$crate::inspector::Inspector::global().inspection_point(
task_id,
$label.to_string(),
Some($message.to_string()),
);
}
}};
}
#[macro_export]
macro_rules! inspect_task_start {
($name:expr) => {{
let task_id = $crate::inspector::Inspector::global().register_task($name.to_string());
$crate::instrument::set_current_task_id(task_id);
task_id
}};
}
#[macro_export]
macro_rules! inspect_task_complete {
($task_id:expr) => {{
$crate::inspector::Inspector::global().task_completed($task_id);
}};
}
#[macro_export]
macro_rules! inspect_task_failed {
($task_id:expr) => {{
$crate::inspector::Inspector::global().task_failed($task_id, None);
}};
($task_id:expr, $error:expr) => {{
$crate::inspector::Inspector::global().task_failed($task_id, Some($error.to_string()));
}};
}
thread_local! {
static CURRENT_TASK_ID: std::cell::RefCell<Option<TaskId>> = const { std::cell::RefCell::new(None) };
}
#[must_use]
pub fn current_task_id() -> Option<TaskId> {
CURRENT_TASK_ID.with(|id| *id.borrow())
}
pub fn set_current_task_id(task_id: TaskId) {
CURRENT_TASK_ID.with(|id| *id.borrow_mut() = Some(task_id));
}
pub fn clear_current_task_id() {
CURRENT_TASK_ID.with(|id| *id.borrow_mut() = None);
}
pub struct TaskGuard {
task_id: TaskId,
}
impl TaskGuard {
#[must_use]
pub fn new(name: String) -> Self {
let task_id = Inspector::global().register_task(name);
set_current_task_id(task_id);
Self { task_id }
}
#[must_use]
pub fn task_id(&self) -> TaskId {
self.task_id
}
}
impl Drop for TaskGuard {
fn drop(&mut self) {
Inspector::global().task_completed(self.task_id);
clear_current_task_id();
}
}
pub fn inspect_await_start(label: impl Into<String>, location: Option<String>) {
if let Some(task_id) = current_task_id() {
Inspector::global().add_event(
task_id,
crate::timeline::EventKind::AwaitStarted {
await_point: label.into(),
location,
},
);
}
}
pub fn inspect_await_end(label: impl Into<String>) {
if let Some(task_id) = current_task_id() {
Inspector::global().add_event(
task_id,
crate::timeline::EventKind::AwaitEnded {
await_point: label.into(),
duration: std::time::Duration::from_micros(0), },
);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_current_task_id() {
let task_id = TaskId::new();
set_current_task_id(task_id);
assert_eq!(current_task_id(), Some(task_id));
clear_current_task_id();
assert_eq!(current_task_id(), None);
}
#[test]
fn test_task_guard() {
let guard = TaskGuard::new("test".to_string());
let task_id = guard.task_id();
assert_eq!(current_task_id(), Some(task_id));
drop(guard);
assert_eq!(current_task_id(), None);
}
}