trace_tally/lib.rs
1#![cfg_attr(feature = "tracing", doc = include_str!("../README.md"))]
2
3pub(crate) mod runner;
4pub(crate) mod task;
5#[cfg(feature = "tracing")]
6pub(crate) mod tracing;
7pub(crate) mod view;
8pub(crate) mod writer;
9
10pub mod widgets;
11
12#[cfg(test)]
13mod test;
14
15/// Re-exports of all public types and traits.
16pub mod prelude {
17 pub use crate::runner::{ActionSource, RenderLoop};
18 pub use crate::task::TaskId;
19 #[cfg(feature = "tracing")]
20 pub use crate::tracing::*;
21 pub use crate::view::{EventView, FrameWriter, TaskView};
22 pub use crate::widgets::*;
23 pub use crate::writer::TaskRenderer;
24 pub use crate::{Action, Renderer};
25}
26
27pub use crate::prelude::*;
28
29/// Defines how tasks and events are rendered to the terminal.
30///
31/// Implement this trait to control the visual output of the task tree.
32/// Each frame, the writer walks the task hierarchy and calls the render
33/// methods in order: [`render_task_line`], [`render_event_line`] for each
34/// buffered event, then recurses into child tasks. Override [`render_task`]
35/// to change this traversal.
36///
37/// [`render_task`]: Renderer::render_task
38/// [`render_task_line`]: Renderer::render_task_line
39/// [`render_event_line`]: Renderer::render_event_line
40///
41/// # Example
42///
43/// ```rust
44/// use trace_tally::*;
45/// use std::io::Write;
46///
47/// struct MyRenderer;
48///
49/// impl Renderer for MyRenderer {
50/// type EventData = String;
51/// type TaskData = String;
52///
53/// fn render_task_line(
54/// &mut self, f: &mut FrameWriter<'_>, task: &TaskView<'_, Self>,
55/// ) -> std::io::Result<()> {
56/// writeln!(f, "{}{}", " ".repeat(task.depth()), task.data())
57/// }
58///
59/// fn render_event_line(
60/// &mut self, f: &mut FrameWriter<'_>, event: &EventView<'_, Self>,
61/// ) -> std::io::Result<()> {
62/// writeln!(f, "{} {}", " ".repeat(event.depth()), event.data())
63/// }
64/// }
65/// ```
66pub trait Renderer: Sized {
67 /// Data stored per event (e.g. a log message or span field snapshot).
68 type EventData: Send + 'static;
69 /// Data stored per task (e.g. a task name or metadata).
70 type TaskData: Send + 'static;
71
72 /// Called once at the start of each render frame, before any tasks are visited.
73 fn on_render_start(&mut self) {}
74
75 /// Called once at the end of each render frame, after all tasks have been visited.
76 fn on_render_end(&mut self) {}
77
78 /// Renders a complete task and its descendants.
79 ///
80 /// The default implementation renders the task line, then the last 3
81 /// buffered events (skipped for completed tasks), then recurses into
82 /// subtasks. Override this to change traversal order or the event cap.
83 #[allow(unused_variables)]
84 fn render_task(
85 &mut self,
86 f: &mut FrameWriter<'_>,
87 task: &TaskView<'_, Self>,
88 ) -> Result<(), std::io::Error> {
89 self.render_task_line(f, task)?;
90 if task.active() {
91 for event in task.events().rev().take(3).rev() {
92 self.render_event_line(f, &event)?;
93 }
94 }
95 for subtask in task.subtasks() {
96 self.render_task(f, &subtask)?;
97 }
98 Ok(())
99 }
100
101 /// Renders the task header on task start.
102 #[allow(unused_variables)]
103 fn render_task_line(
104 &mut self,
105 f: &mut FrameWriter<'_>,
106 task: &TaskView<'_, Self>,
107 ) -> Result<(), std::io::Error> {
108 Ok(())
109 }
110
111 /// Renders a single buffered event within a task.
112 #[allow(unused_variables)]
113 fn render_event_line(
114 &mut self,
115 f: &mut FrameWriter<'_>,
116 event: &EventView<'_, Self>,
117 ) -> Result<(), std::io::Error> {
118 Ok(())
119 }
120}
121
122/// A state change in the task tree.
123///
124/// # Example
125///
126/// ```rust
127/// use trace_tally::*;
128///
129/// struct MyRenderer;
130/// impl Renderer for MyRenderer {
131/// type EventData = String;
132/// type TaskData = String;
133/// }
134///
135/// let mut renderer = TaskRenderer::new(MyRenderer);
136/// renderer.update(Action::TaskStart {
137/// id: TaskId::from(2),
138/// parent: None,
139/// data: "my task".into(),
140/// });
141/// renderer.render(&mut std::io::stderr()).unwrap();
142/// ```
143#[derive(Debug, Clone)]
144pub enum Action<R: Renderer> {
145 /// A new event on an existing task (or the root if `parent` is `None`).
146 Event {
147 parent: Option<TaskId>,
148 data: R::EventData,
149 },
150 /// A new task has started.
151 ///
152 /// If `parent` is `None` or refers to an unknown ID, the task is
153 /// attached to the virtual root.
154 TaskStart {
155 id: TaskId,
156 parent: Option<TaskId>,
157 data: R::TaskData,
158 },
159 /// A task has completed.
160 TaskEnd { id: TaskId },
161 /// Mark all pending tasks as cancelled.
162 ///
163 /// Walks every task reachable from root and sets them as cancelled.
164 /// Cancelled tasks still render (via [`TaskView::cancelled`]) but are
165 /// flushed from the active frame on the next render, like completed tasks.
166 CancelAll,
167}