kairoi 0.2.3

Another application-level tracing library
Documentation
use crate::{Event, Node};
use lazy_static::lazy_static;
use std::sync::{Arc, Weak};
use std::time::SystemTime;
use tokio::task_local;

#[derive(Debug, Copy, Clone)]
pub struct Progress {
    total: u64,
    progress: u64,
}

impl Progress {
    pub fn new(total: u64, progress: u64) -> Self {
        Self { total, progress }
    }

    pub fn total(&self) -> u64 {
        self.total
    }

    pub fn progress(&self) -> u64 {
        self.progress
    }
}

#[derive(Debug, Clone)]
pub struct Span {
    timestamp: SystemTime,
    name: String,
    progress: Option<Progress>,
}

pub type SpanRef = Arc<Node<Span>>;

impl Span {
    pub fn with_name(&self, name: String) -> Self {
        let mut clone = self.clone();
        clone.name = name;
        clone
    }

    pub fn with_progress(&self, progress: Progress) -> Self {
        let mut clone = self.clone();
        clone.progress = Some(progress);
        clone
    }

    pub fn timestamp(&self) -> SystemTime {
        self.timestamp
    }

    pub fn name(&self) -> &str {
        &self.name
    }

    pub fn progress(&self) -> Option<Progress> {
        self.progress
    }
}

impl Default for Span {
    fn default() -> Self {
        Self {
            timestamp: SystemTime::now(),
            name: String::default(),
            progress: None,
        }
    }
}

lazy_static! {
    static ref ROOT: SpanRef = Arc::new(Node::new(Span::default()));
}

task_local! {
    static CURRENT: Weak<Node<Span >>;
}

impl Span {
    pub async fn scope<T, F: AsyncFnOnce(Scope) -> T>(f: F) -> T {
        let new = Self::current().add(Node::new(Self::default()));

        Event::span_begin(new.clone()).submit();

        let new_clone = new.clone();
        let v = CURRENT
            .scope(Arc::downgrade(&new_clone), async move {
                f(Scope::new(new_clone)).await
            })
            .await;

        new.delete();
        Event::span_end(new).submit();

        v
    }

    pub fn current() -> SpanRef {
        CURRENT
            .try_with(|v| v.upgrade())
            .ok()
            .flatten()
            .unwrap_or_else(|| ROOT.clone())
    }

    pub fn root() -> SpanRef {
        ROOT.clone()
    }
}

pub struct Scope {
    node: SpanRef,
}

impl Scope {
    fn new(node: SpanRef) -> Self {
        Self { node }
    }

    pub fn update(&self, data: Span) {
        self.node.update(data);
    }
}