Skip to main content

guinea_trace/
point.rs

1use std::fmt;
2
3/// Which bus carried a publication.
4#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
5pub enum Bus {
6    /// Every window hears it.
7    Global,
8    /// One window's own.
9    Window,
10}
11
12/// How a stored value changed.
13#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
14pub enum StoreOp {
15    Set,
16    Delete,
17    /// Everything under the path went at once.
18    DeletePrefix,
19}
20
21/// An observable point, with what identifies it.
22///
23/// Names are short type names: `processes::Kill`, not a crate path.
24#[derive(Clone, Debug, PartialEq)]
25pub enum Point {
26    /// The UI asked a feature for something.
27    Action { message: &'static str },
28    /// A message was queued for an actor.
29    Send {
30        actor: &'static str,
31        message: &'static str,
32    },
33    /// An actor handled a message.
34    Handle {
35        actor: &'static str,
36        message: &'static str,
37    },
38    /// An actor started background work whose result will come back as
39    /// `output`. `actor` is the address it will come back to, by the id the
40    /// snapshot lists it under: what a task belongs to is what that actor
41    /// belongs to.
42    Spawn {
43        actor: &'static str,
44        actor_id: u64,
45        output: &'static str,
46    },
47    /// Background work finished, and its result is on its way to the actor.
48    Settled {
49        actor: &'static str,
50        actor_id: u64,
51        output: &'static str,
52        took_us: u64,
53    },
54    /// Background work was dropped where it last awaited, because the actor
55    /// that started it is gone. Nothing comes back.
56    Cancelled {
57        actor: &'static str,
58        actor_id: u64,
59        output: &'static str,
60        took_us: u64,
61    },
62    /// An actor opened a source whose items will come to it as `output`.
63    /// Recorded under what opened it, which is done with it once it is open:
64    /// the items are not its work.
65    Source {
66        actor: &'static str,
67        actor_id: u64,
68        output: &'static str,
69    },
70    /// An item came from a source, as `output`. A root, as a timer's tick
71    /// is; `source` is the id of the [`Point::Source`] it came from.
72    Arrived {
73        actor: &'static str,
74        actor_id: u64,
75        output: &'static str,
76        source: u64,
77    },
78    /// A source ended: it ran dry, or `gone` - the actor that opened it is
79    /// gone and the source was dropped where it last awaited.
80    Closed {
81        actor: &'static str,
82        actor_id: u64,
83        output: &'static str,
84        took_us: u64,
85        gone: bool,
86    },
87    /// An event went out.
88    Publish {
89        event: &'static str,
90        bus: Bus,
91        subscribers: usize,
92    },
93    /// An event reached a subscriber that is not an actor.
94    Deliver { event: &'static str, bus: Bus },
95    /// A reducer was changed.
96    Push { reducer: &'static str },
97    /// A router moved.
98    Navigate { root: String, to: String },
99    /// A timer fired; `timer` is its id, as the application's timers list
100    /// it.
101    Tick { timer: u64 },
102    /// A persisted value changed.
103    Store {
104        op: StoreOp,
105        path: String,
106        /// The declared field the path belongs to, `Settings.theme`, when
107        /// the store knows it.
108        field: Option<String>,
109        /// Whether the change came from outside the process, an edited file.
110        outside: bool,
111    },
112    /// A page or layout drew itself, and how long that took. Recorded only
113    /// for the frames worth looking at - see `devtools::rendering`.
114    Render {
115        segment: &'static str,
116        took_us: u64,
117    },
118    /// An ordinary `tracing` event the application wrote.
119    Log {
120        level: tracing::Level,
121        target: &'static str,
122        /// Where it was written, as the compiler named the file: relative to
123        /// the workspace root for the application's own crates.
124        file: Option<&'static str>,
125        line: Option<u32>,
126        module: Option<&'static str>,
127        /// The message, then the other fields as `name=value`.
128        text: String,
129    },
130    /// A `tracing` span the application opened - an `#[instrument]`ed
131    /// function, say. Open until the span closes, and current while it is
132    /// entered; what it took is the time it was entered, not the time it
133    /// waited in between.
134    Span {
135        name: &'static str,
136        /// The level it was opened at, as [`Point::Log`]'s.
137        level: tracing::Level,
138        target: &'static str,
139        /// Where it was written; see [`Point::Log`].
140        file: Option<&'static str>,
141        line: Option<u32>,
142        module: Option<&'static str>,
143        /// Its fields as `name=value`, as they were when it opened.
144        fields: String,
145    },
146    /// Anything else worth a line.
147    Note(String),
148}
149
150impl Point {
151    /// A short name for the kind of point, for filtering.
152    pub fn kind(&self) -> &'static str {
153        match self {
154            Point::Action { .. } => "action",
155            Point::Send { .. } => "send",
156            Point::Handle { .. } => "handle",
157            Point::Spawn { .. } => "spawn",
158            Point::Settled { .. } => "settled",
159            Point::Cancelled { .. } => "cancelled",
160            Point::Source { .. } => "source",
161            Point::Arrived { .. } => "arrived",
162            Point::Closed { .. } => "closed",
163            Point::Publish { .. } => "publish",
164            Point::Deliver { .. } => "deliver",
165            Point::Push { .. } => "push",
166            Point::Navigate { .. } => "navigate",
167            Point::Tick { .. } => "tick",
168            Point::Store { .. } => "store",
169            Point::Render { .. } => "render",
170            Point::Log { .. } => "log",
171            Point::Span { .. } => "span",
172            Point::Note(_) => "note",
173        }
174    }
175}
176
177impl fmt::Display for Bus {
178    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
179        f.write_str(match self {
180            Bus::Global => "global",
181            Bus::Window => "window",
182        })
183    }
184}
185
186impl fmt::Display for StoreOp {
187    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
188        f.write_str(match self {
189            StoreOp::Set => "set",
190            StoreOp::Delete => "delete",
191            StoreOp::DeletePrefix => "delete_prefix",
192        })
193    }
194}
195
196impl fmt::Display for Point {
197    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
198        match self {
199            Point::Action { message } => write!(f, "action {message}"),
200            Point::Send { actor, message } => write!(f, "send {message} → {actor}"),
201            Point::Handle { actor, message, .. } => write!(f, "{actor} handles {message}"),
202            Point::Spawn { actor, output, .. } => write!(f, "{actor} starts work for {output}"),
203            Point::Settled {
204                actor,
205                output,
206                took_us,
207                ..
208            } => write!(
209                f,
210                "{actor} has its {output} after {:.1} ms",
211                *took_us as f64 / 1000.0
212            ),
213            Point::Cancelled {
214                actor,
215                output,
216                took_us,
217                ..
218            } => write!(
219                f,
220                "{actor} is gone: {output} cancelled after {:.1} ms",
221                *took_us as f64 / 1000.0
222            ),
223            Point::Source { actor, output, .. } => write!(f, "{actor} opens a source of {output}"),
224            Point::Arrived { actor, output, .. } => write!(f, "{output} arrives at {actor}"),
225            Point::Closed {
226                actor,
227                output,
228                took_us,
229                gone: true,
230                ..
231            } => write!(
232                f,
233                "{actor} is gone: its source of {output} closed after {:.1} ms",
234                *took_us as f64 / 1000.0
235            ),
236            Point::Closed {
237                actor,
238                output,
239                took_us,
240                ..
241            } => write!(
242                f,
243                "{actor}'s source of {output} ran dry after {:.1} ms",
244                *took_us as f64 / 1000.0
245            ),
246            Point::Publish {
247                event,
248                bus,
249                subscribers,
250            } => write!(f, "publish {event} on the {bus} bus to {subscribers}"),
251            Point::Deliver { event, bus } => write!(f, "deliver {event} from the {bus} bus"),
252            Point::Push { reducer } => write!(f, "push into {reducer}"),
253            Point::Navigate { root, to } => write!(f, "{root} navigates to {to}"),
254            Point::Tick { timer } => write!(f, "timer #{timer}"),
255            Point::Render { segment, took_us } => {
256                write!(f, "{segment} drew itself in {:.1} ms", *took_us as f64 / 1000.0)
257            }
258            Point::Store {
259                op,
260                path,
261                field,
262                outside,
263            } => {
264                let who = if *outside { "disk" } else { "store" };
265                let verb = match op {
266                    StoreOp::Set => "sets",
267                    StoreOp::Delete => "deletes",
268                    StoreOp::DeletePrefix => "clears",
269                };
270                write!(f, "{who} {verb} {path}")?;
271                match field {
272                    Some(field) => write!(f, " ({field})"),
273                    None => Ok(()),
274                }
275            }
276            Point::Log {
277                level,
278                target,
279                text,
280                ..
281            } => write!(f, "{level} {target}: {text}"),
282            Point::Span { name, fields, .. } if fields.is_empty() => f.write_str(name),
283            Point::Span { name, fields, .. } => write!(f, "{name} {fields}"),
284            Point::Note(text) => f.write_str(text),
285        }
286    }
287}