test_span/lib.rs
1//! the test span library provides you with two functions:
2//!
3//! `get_logs()` that returns [`prelude::Records`]
4//!
5//! `get_span()` that returns a [`prelude::Span`],
6//! Which can be serialized and used with [insta](https://crates.io/crates/insta) for snapshot tests.
7//! Refer to the tests.rs file to see how it behaves.
8//!
9//! Example:
10//! ```ignore
11//! #[test_span]
12//! async fn test_it_works() {
13//! futures::join!(do_stuff(), do_stuff())
14//! }
15//!
16//! #[tracing::instrument(name = "do_stuff", level = "info")]
17//! async fn do_stuff() -> u8 {
18//! // ...
19//! do_stuff2().await;
20//! }
21//!
22//! #[tracing::instrument(
23//! name = "do_stuff2",
24//! target = "my_crate::an_other_target",
25//! level = "info"
26//! )]
27//! async fn do_stuff_2(number: u8) -> u8 {
28//! // ...
29//! }
30//! ```
31//! ```text
32//! `get_span()` will provide you with:
33//!
34//! ┌──────┐
35//! │ root │
36//! └──┬───┘
37//! │
38//! ┌───────┴───────┐
39//! ▼ ▼
40//! ┌──────────┐ ┌──────────┐
41//! │ do_stuff │ │ do_stuff │
42//! └────┬─────┘ └─────┬────┘
43//! │ │
44//! │ │
45//! ▼ ▼
46//! ┌───────────┐ ┌───────────┐
47//! │ do_stuff2 │ │ do_stuff2 │
48//! └───────────┘ └───────────┘
49//! ```
50
51use once_cell::sync::Lazy;
52use std::sync::{Arc, Mutex};
53use tracing::Id;
54use tracing_core::dispatcher;
55use tracing_subscriber::{prelude::__tracing_subscriber_SubscriberExt, util::SubscriberInitExt};
56type LazyMutex<T> = Lazy<Arc<Mutex<T>>>;
57
58mod attribute;
59mod layer;
60mod log;
61mod record;
62mod report;
63
64pub use layer::Layer;
65pub use record::{Record, RecordValue};
66pub use report::{Filter, Records, Report, Span};
67
68static INIT: Lazy<()> = Lazy::new(|| {
69 if dispatcher::has_been_set() {
70 dispatcher::get_default(|dispatcher| {
71 assert!(dispatcher.is::<Layer>(), "A tracing global subscriber has already been set by an other crate than test-span, cannot proceed");
72 })
73 } else {
74 let dispatcher = tracing_subscriber::registry().with(Layer {});
75 dispatcher
76 .try_init()
77 .expect("couldn't set test-span subscriber as a default")
78 }
79});
80
81/// `init_default` is the default way to call `with_targets`,
82/// it sets up `Level::INFO` and looks for environment variables to filter spans.
83pub fn init() {
84 Lazy::force(&INIT);
85}
86
87/// Unlike its `get_logs` counterpart provided by the trace_span macro,
88/// `get_all_logs` will return all of the module's tests logs.
89pub fn get_all_logs(filter: &Filter) -> Records {
90 let logs = layer::ALL_LOGS.lock().unwrap().clone();
91
92 Records::new(logs.all_records_for_filter(filter))
93}
94
95/// Returns both the output of `get_spans_for_root` and `get_logs_for_root`
96pub fn get_telemetry_for_root(root_id: &Id, filter: &Filter) -> (Span, Records) {
97 let report = Report::from_root(root_id.into_u64());
98
99 (report.spans(filter), report.logs(filter))
100}
101
102/// Returns a `Span`, a Tree containing all the spans that are children of `root_id`.
103///
104/// This function filters the `Span` children and `Records`,
105/// to only return the ones that match the set verbosity level
106pub fn get_spans_for_root(root_id: &Id, filter: &Filter) -> Span {
107 Report::from_root(root_id.into_u64()).spans(filter)
108}
109
110/// Returns Records, which is a Vec, containing all entries recorded by children of `root_id`.
111///
112/// This function filters the `Records`to only return the ones that match the set verbosity level.
113///
114/// / ! \ Logs recorded in spawned threads won't appear here / ! \ use `get_all_logs` instead.
115pub fn get_logs_for_root(root_id: &Id, filter: &Filter) -> Records {
116 Report::from_root(root_id.into_u64()).logs(filter)
117}
118
119pub mod prelude {
120 pub use crate::{get_all_logs, get_logs_for_root, get_spans_for_root, get_telemetry_for_root};
121 pub use test_span_macro::test_span;
122}
123
124pub mod reexports {
125 pub use daggy;
126 pub use serde;
127 pub use tracing;
128 pub use tracing_futures;
129 pub use tracing_subscriber;
130}
131
132#[cfg(test)]
133mod test_span_doesnt_panic_tests {
134 use super::*;
135
136 #[test]
137 fn init_with_already_set_test_span_global_subscriber_doesnt_panic() {
138 tracing_subscriber::registry()
139 .with(Layer {})
140 .try_init()
141 .unwrap();
142 init();
143 }
144}