🛈 Note: This is pre-release documentation for the upcoming tracing 0.2.0 ecosystem.

For the release documentation, please see docs.rs, instead.

tracing_mock/
collector.rs

1//! An implementation of the [`Collect`] trait to receive and validate
2//! `tracing` data.
3//!
4//! The [`MockCollector`] is the central component of this crate. The
5//! `MockCollector` has expectations set on it which are later
6//! validated as the code under test is run.
7//!
8//! # Examples
9//!
10//! ```
11//! use tracing_mock::{collector, expect, field};
12//!
13//! let (collector, handle) = collector::mock()
14//!     // Expect a single event with a specified message
15//!     .event(expect::event().with_fields(expect::msg("droids")))
16//!     .only()
17//!     .run_with_handle();
18//!
19//! // Use `with_default` to apply the `MockCollector` for the duration
20//! // of the closure - this is what we are testing.
21//! tracing::collect::with_default(collector, || {
22//!     // These *are* the droids we are looking for
23//!     tracing::info!("droids");
24//! });
25//!
26//! // Use the handle to check the assertions. This line will panic if an
27//! // assertion is not met.
28//! handle.assert_finished();
29//! ```
30//!
31//! A more complex example may consider multiple spans and events with
32//! their respective fields:
33//!
34//! ```
35//! use tracing_mock::{collector, expect, field};
36//!
37//! let span = expect::span()
38//!     .named("my_span");
39//! let (collector, handle) = collector::mock()
40//!     // Enter a matching span
41//!     .enter(&span)
42//!     // Record an event with message "collect parting message"
43//!     .event(expect::event().with_fields(expect::msg("collect parting message")))
44//!     // Record a value for the field `parting` on a matching span
45//!     .record(&span, expect::field("parting").with_value(&"goodbye world!"))
46//!     // Exit a matching span
47//!     .exit(span)
48//!     // Expect no further messages to be recorded
49//!     .only()
50//!     // Return the collector and handle
51//!     .run_with_handle();
52//!
53//! // Use `with_default` to apply the `MockCollector` for the duration
54//! // of the closure - this is what we are testing.
55//! tracing::collect::with_default(collector, || {
56//!     let span = tracing::trace_span!(
57//!         "my_span",
58//!         greeting = "hello world",
59//!         parting = tracing::field::Empty
60//!     );
61//!
62//!     let _guard = span.enter();
63//!     tracing::info!("collect parting message");
64//!     let parting = "goodbye world!";
65//!
66//!     span.record("parting", &parting);
67//! });
68//!
69//! // Use the handle to check the assertions. This line will panic if an
70//! // assertion is not met.
71//! handle.assert_finished();
72//! ```
73//!
74//! If we modify the previous example so that we **don't** enter the
75//! span before recording an event, the test will fail:
76//!
77//! ```should_panic
78//! use tracing_mock::{collector, expect, field};
79//!
80//! let span = expect::span()
81//!     .named("my_span");
82//! let (collector, handle) = collector::mock()
83//!     .enter(&span)
84//!     .event(expect::event().with_fields(expect::msg("collect parting message")))
85//!     .record(&span, expect::field("parting").with_value(&"goodbye world!"))
86//!     .exit(span)
87//!     .only()
88//!     .run_with_handle();
89//!
90//! // Use `with_default` to apply the `MockCollector` for the duration
91//! // of the closure - this is what we are testing.
92//! tracing::collect::with_default(collector, || {
93//!     let span = tracing::trace_span!(
94//!         "my_span",
95//!         greeting = "hello world",
96//!         parting = tracing::field::Empty
97//!     );
98//!
99//!     // Don't enter the span.
100//!     // let _guard = span.enter();
101//!     tracing::info!("collect parting message");
102//!     let parting = "goodbye world!";
103//!
104//!     span.record("parting", &parting);
105//! });
106//!
107//! // Use the handle to check the assertions. This line will panic if an
108//! // assertion is not met.
109//! handle.assert_finished();
110//! ```
111//!
112//! This will result in an error message such as the following:
113//!
114//! ```text
115//! thread 'main' panicked at '
116//! [main] expected to enter a span named `my_span`
117//! [main] but instead observed event Event {
118//!     fields: ValueSet {
119//!         message: collect parting message,
120//!         callsite: Identifier(0x10eda3278),
121//!     },
122//!     metadata: Metadata {
123//!         name: "event src/collector.rs:27",
124//!         target: "rust_out",
125//!         level: Level(
126//!             Info,
127//!         ),
128//!         module_path: "rust_out",
129//!         location: src/collector.rs:27,
130//!         fields: {message},
131//!         callsite: Identifier(0x10eda3278),
132//!         kind: Kind(EVENT),
133//!     },
134//!     parent: Current,
135//! }', tracing/tracing-mock/src/expect.rs:59:33
136//! ```
137//!
138//! [`Collect`]: trait@tracing::Collect
139//! [`MockCollector`]: struct@crate::collector::MockCollector
140use std::{
141    collections::{HashMap, VecDeque},
142    sync::{
143        atomic::{AtomicUsize, Ordering},
144        Arc, Mutex,
145    },
146    thread,
147};
148
149use tracing::{
150    collect::Interest,
151    level_filters::LevelFilter,
152    span::{self, Attributes, Id},
153    Collect, Event, Metadata,
154};
155
156use crate::{
157    ancestry::get_ancestry,
158    event::ExpectedEvent,
159    expect::Expect,
160    field::ExpectedFields,
161    span::{ActualSpan, ExpectedSpan, NewSpan},
162};
163
164pub(crate) struct SpanState {
165    id: Id,
166    name: &'static str,
167    refs: usize,
168    meta: &'static Metadata<'static>,
169}
170
171impl From<&SpanState> for ActualSpan {
172    fn from(span_state: &SpanState) -> Self {
173        Self::new(span_state.id.clone(), Some(span_state.meta))
174    }
175}
176
177struct Running<F: Fn(&Metadata<'_>) -> bool> {
178    spans: Mutex<HashMap<Id, SpanState>>,
179    expected: Arc<Mutex<VecDeque<Expect>>>,
180    current: Mutex<Vec<Id>>,
181    ids: AtomicUsize,
182    max_level: Option<LevelFilter>,
183    filter: F,
184    name: String,
185}
186
187/// A collector which can validate received traces.
188///
189/// For a detailed description and examples see the documentation
190/// for the methods and the [`collector`] module.
191///
192/// [`collector`]: mod@crate::collector
193#[derive(Debug)]
194pub struct MockCollector<F: Fn(&Metadata<'_>) -> bool> {
195    expected: VecDeque<Expect>,
196    max_level: Option<LevelFilter>,
197    filter: F,
198    name: String,
199}
200
201/// A handle which is used to invoke validation of expectations.
202///
203/// The handle is currently only used to assert that all the expected
204/// events and spans were seen.
205///
206/// For additional information and examples, see the [`collector`]
207/// module documentation.
208///
209/// [`collector`]: mod@crate::collector
210#[derive(Debug)]
211pub struct MockHandle(Arc<Mutex<VecDeque<Expect>>>, String);
212
213/// Create a new [`MockCollector`].
214///
215/// For additional information and examples, see the [`collector`]
216/// module and [`MockCollector`] documentation.
217///
218/// # Examples
219///
220///
221/// ```
222/// use tracing_mock::{collector, expect, field};
223///
224/// let span = expect::span()
225///     .named("my_span");
226/// let (collector, handle) = collector::mock()
227///     // Enter a matching span
228///     .enter(&span)
229///     // Record an event with message "collect parting message"
230///     .event(expect::event().with_fields(expect::msg("collect parting message")))
231///     // Record a value for the field `parting` on a matching span
232///     .record(&span, expect::field("parting").with_value(&"goodbye world!"))
233///     // Exit a matching span
234///     .exit(span)
235///     // Expect no further messages to be recorded
236///     .only()
237///     // Return the collector and handle
238///     .run_with_handle();
239///
240/// // Use `with_default` to apply the `MockCollector` for the duration
241/// // of the closure - this is what we are testing.
242/// tracing::collect::with_default(collector, || {
243///     let span = tracing::trace_span!(
244///         "my_span",
245///         greeting = "hello world",
246///         parting = tracing::field::Empty
247///     );
248///
249///     let _guard = span.enter();
250///     tracing::info!("collect parting message");
251///     let parting = "goodbye world!";
252///
253///     span.record("parting", &parting);
254/// });
255///
256/// // Use the handle to check the assertions. This line will panic if an
257/// // assertion is not met.
258/// handle.assert_finished();
259/// ```
260///
261/// [`collector`]: mod@crate::collector
262#[must_use]
263pub fn mock() -> MockCollector<fn(&Metadata<'_>) -> bool> {
264    MockCollector {
265        expected: VecDeque::new(),
266        filter: (|_: &Metadata<'_>| true) as for<'r, 's> fn(&'r Metadata<'s>) -> _,
267        max_level: None,
268        name: thread::current()
269            .name()
270            .unwrap_or("mock_subscriber")
271            .to_string(),
272    }
273}
274
275impl<F> MockCollector<F>
276where
277    F: Fn(&Metadata<'_>) -> bool + 'static,
278{
279    /// Overrides the name printed by the mock subscriber's debugging output.
280    ///
281    /// The debugging output is displayed if the test panics, or if the test is
282    /// run with `--nocapture`.
283    ///
284    /// By default, the mock collector's name is the  name of the test
285    /// (*technically*, the name of the thread where it was created, which is
286    /// the name of the test unless tests are run with `--test-threads=1`).
287    /// When a test has only one mock collector, this is sufficient. However,
288    /// some tests may include multiple collectors, in order to test
289    /// interactions between multiple collectors. In that case, it can be
290    /// helpful to give each collector a separate name to distinguish where the
291    /// debugging output comes from.
292    ///
293    /// # Examples
294    ///
295    /// In the following example, we create 2 collectors, both
296    /// expecting to receive an event. As we only record a single
297    /// event, the test will fail:
298    ///
299    /// ```should_panic
300    /// use tracing_mock::{collector, expect};
301    ///
302    /// let (collector_1, handle_1) = collector::mock()
303    ///     .named("collector-1")
304    ///     .event(expect::event())
305    ///     .run_with_handle();
306    ///
307    /// let (collector_2, handle_2) = collector::mock()
308    ///     .named("collector-2")
309    ///     .event(expect::event())
310    ///     .run_with_handle();
311    ///
312    /// let _guard = tracing::collect::set_default(collector_2);
313    ///
314    /// tracing::collect::with_default(collector_1, || {
315    ///     tracing::info!("a");
316    /// });
317    ///
318    /// handle_1.assert_finished();
319    /// handle_2.assert_finished();
320    /// ```
321    ///
322    /// In the test output, we see that the collector which didn't
323    /// received the event was the one named `collector-2`, which is
324    /// correct as the collector named `collector-1` was the default
325    /// when the event was recorded:
326    ///
327    /// ```text
328    /// [collector-2] more notifications expected: [
329    ///     Event(
330    ///         MockEvent,
331    ///     ),
332    /// ]', tracing-mock/src/collector.rs:1276:13
333    /// ```
334    pub fn named(self, name: impl ToString) -> Self {
335        Self {
336            name: name.to_string(),
337            ..self
338        }
339    }
340
341    /// Adds an expectation that an event matching the [`ExpectedEvent`]
342    /// will be recorded next.
343    ///
344    /// The `event` can be a default mock which will match any event
345    /// (`expect::event()`) or can include additional expectations.
346    /// See the [`ExpectedEvent`] documentation for more details.
347    ///
348    /// If an event is recorded that doesn't match the `ExpectedEvent`,
349    /// or if something else (such as entering a span) is recorded
350    /// first, then the expectation will fail.
351    ///
352    /// # Examples
353    ///
354    /// ```
355    /// use tracing_mock::{collector, expect};
356    ///
357    /// let (collector, handle) = collector::mock()
358    ///     .event(expect::event())
359    ///     .run_with_handle();
360    ///
361    /// tracing::collect::with_default(collector, || {
362    ///     tracing::info!("a");
363    /// });
364    ///
365    /// handle.assert_finished();
366    /// ```
367    ///
368    /// A span is entered before the event, causing the test to fail:
369    ///
370    /// ```should_panic
371    /// use tracing_mock::{collector, expect};
372    ///
373    /// let (collector, handle) = collector::mock()
374    ///     .event(expect::event())
375    ///     .run_with_handle();
376    ///
377    /// tracing::collect::with_default(collector, || {
378    ///     let span = tracing::info_span!("span");
379    ///     let _guard = span.enter();
380    ///     tracing::info!("a");
381    /// });
382    ///
383    /// handle.assert_finished();
384    /// ```
385    pub fn event(mut self, event: ExpectedEvent) -> Self {
386        self.expected.push_back(Expect::Event(event));
387        self
388    }
389
390    /// Adds an expectation that the creation of a span will be
391    /// recorded next.
392    ///
393    /// This function accepts `Into<NewSpan>` instead of
394    /// [`ExpectedSpan`] directly, so it can be used to test
395    /// span fields and the span parent. This is because a
396    /// collector only receives the span fields and parent when
397    /// a span is created, not when it is entered.
398    ///
399    /// The new span doesn't need to be entered for this expectation
400    /// to succeed.
401    ///
402    /// If a span is recorded that doesn't match the `ExpectedSpan`,
403    /// or if something else (such as an event) is recorded first,
404    /// then the expectation will fail.
405    ///
406    /// # Examples
407    ///
408    /// ```
409    /// use tracing_mock::{collector, expect};
410    ///
411    /// let span = expect::span()
412    ///     .at_level(tracing::Level::INFO)
413    ///     .named("the span we're testing")
414    ///     .with_fields(expect::field("testing").with_value(&"yes"));
415    /// let (collector, handle) = collector::mock()
416    ///     .new_span(span)
417    ///     .run_with_handle();
418    ///
419    /// tracing::collect::with_default(collector, || {
420    ///     _ = tracing::info_span!("the span we're testing", testing = "yes");
421    /// });
422    ///
423    /// handle.assert_finished();
424    /// ```
425    ///
426    /// An event is recorded before the span is created, causing the
427    /// test to fail:
428    ///
429    /// ```should_panic
430    /// use tracing_mock::{collector, expect};
431    ///
432    /// let span = expect::span()
433    ///     .at_level(tracing::Level::INFO)
434    ///     .named("the span we're testing")
435    ///     .with_fields(expect::field("testing").with_value(&"yes"));
436    /// let (collector, handle) = collector::mock()
437    ///     .new_span(span)
438    ///     .run_with_handle();
439    ///
440    /// tracing::collect::with_default(collector, || {
441    ///     tracing::info!("an event");
442    ///     _ = tracing::info_span!("the span we're testing", testing = "yes");
443    /// });
444    ///
445    /// handle.assert_finished();
446    /// ```
447    pub fn new_span<I>(mut self, new_span: I) -> Self
448    where
449        I: Into<NewSpan>,
450    {
451        self.expected.push_back(Expect::NewSpan(new_span.into()));
452        self
453    }
454
455    /// Adds an expectation that entering a span matching the
456    /// [`ExpectedSpan`] will be recorded next.
457    ///
458    /// This expectation is generally accompanied by a call to
459    /// [`exit`] as well. If used together with [`only`], this
460    /// is necessary.
461    ///
462    /// If the span that is entered doesn't match the [`ExpectedSpan`],
463    /// or if something else (such as an event) is recorded first,
464    /// then the expectation will fail.
465    ///
466    /// # Examples
467    ///
468    /// ```
469    /// use tracing_mock::{collector, expect};
470    ///
471    /// let span = expect::span()
472    ///     .at_level(tracing::Level::INFO)
473    ///     .named("the span we're testing");
474    /// let (collector, handle) = collector::mock()
475    ///     .enter(&span)
476    ///     .exit(&span)
477    ///     .only()
478    ///     .run_with_handle();
479    ///
480    /// tracing::collect::with_default(collector, || {
481    ///     let span = tracing::info_span!("the span we're testing");
482    ///     let _entered = span.enter();
483    /// });
484    ///
485    /// handle.assert_finished();
486    /// ```
487    ///
488    /// An event is recorded before the span is entered, causing the
489    /// test to fail:
490    ///
491    /// ```should_panic
492    /// use tracing_mock::{collector, expect};
493    ///
494    /// let span = expect::span()
495    ///     .at_level(tracing::Level::INFO)
496    ///     .named("the span we're testing");
497    /// let (collector, handle) = collector::mock()
498    ///     .enter(&span)
499    ///     .exit(&span)
500    ///     .only()
501    ///     .run_with_handle();
502    ///
503    /// tracing::collect::with_default(collector, || {
504    ///     tracing::info!("an event");
505    ///     let span = tracing::info_span!("the span we're testing");
506    ///     let _entered = span.enter();
507    /// });
508    ///
509    /// handle.assert_finished();
510    /// ```
511    ///
512    /// [`exit`]: fn@Self::exit
513    /// [`only`]: fn@Self::only
514    pub fn enter<S>(mut self, span: S) -> Self
515    where
516        S: Into<ExpectedSpan>,
517    {
518        self.expected.push_back(Expect::Enter(span.into()));
519        self
520    }
521
522    /// Adds ab expectation that exiting a span matching the
523    /// [`ExpectedSpan`] will be recorded next.
524    ///
525    /// As a span may be entered and exited multiple times,
526    /// this is different from the span being closed. In
527    /// general [`enter`] and `exit` should be paired.
528    ///
529    /// If the span that is exited doesn't match the [`ExpectedSpan`],
530    /// or if something else (such as an event) is recorded first,
531    /// then the expectation will fail.
532    ///
533    /// # Examples
534    ///
535    /// ```
536    /// use tracing_mock::{collector, expect};
537    ///
538    /// let span = expect::span()
539    ///     .at_level(tracing::Level::INFO)
540    ///     .named("the span we're testing");
541    /// let (collector, handle) = collector::mock()
542    ///     .enter(&span)
543    ///     .exit(&span)
544    ///     .run_with_handle();
545    ///
546    /// tracing::collect::with_default(collector, || {
547    ///     let span = tracing::info_span!("the span we're testing");
548    ///     let _entered = span.enter();
549    /// });
550    ///
551    /// handle.assert_finished();
552    /// ```
553    ///
554    /// An event is recorded before the span is exited, causing the
555    /// test to fail:
556    ///
557    /// ```should_panic
558    /// use tracing_mock::{collector, expect};
559    ///
560    /// let span = expect::span()
561    ///     .at_level(tracing::Level::INFO)
562    ///     .named("the span we're testing");
563    /// let (collector, handle) = collector::mock()
564    ///     .enter(&span)
565    ///     .exit(&span)
566    ///     .run_with_handle();
567    ///
568    /// tracing::collect::with_default(collector, || {
569    ///     let span = tracing::info_span!("the span we're testing");
570    ///     let _entered = span.enter();
571    ///     tracing::info!("an event");
572    /// });
573    ///
574    /// handle.assert_finished();
575    /// ```
576    ///
577    /// [`enter`]: fn@Self::enter
578    pub fn exit<S>(mut self, span: S) -> Self
579    where
580        S: Into<ExpectedSpan>,
581    {
582        self.expected.push_back(Expect::Exit(span.into()));
583        self
584    }
585
586    /// Adds an expectation that cloning a span matching the
587    /// [`ExpectedSpan`] will be recorded next.
588    ///
589    /// The cloned span does need to be entered.
590    ///
591    /// If the span that is cloned doesn't match the [`ExpectedSpan`],
592    /// or if something else (such as an event) is recorded first,
593    /// then the expectation will fail.
594    ///
595    /// # Examples
596    ///
597    /// ```
598    /// use tracing_mock::{collector, expect};
599    ///
600    /// let span = expect::span()
601    ///     .at_level(tracing::Level::INFO)
602    ///     .named("the span we're testing");
603    /// let (collector, handle) = collector::mock()
604    ///     .clone_span(span)
605    ///     .run_with_handle();
606    ///
607    /// tracing::collect::with_default(collector, || {
608    ///     let span = tracing::info_span!("the span we're testing");
609    ///     _ = span.clone();
610    /// });
611    ///
612    /// handle.assert_finished();
613    /// ```
614    ///
615    /// An event is recorded before the span is cloned, causing the
616    /// test to fail:
617    ///
618    /// ```should_panic
619    /// use tracing_mock::{collector, expect};
620    ///
621    /// let span = expect::span()
622    ///     .at_level(tracing::Level::INFO)
623    ///     .named("the span we're testing");
624    /// let (collector, handle) = collector::mock()
625    ///     .clone_span(span)
626    ///     .run_with_handle();
627    ///
628    /// tracing::collect::with_default(collector, || {
629    ///     let span = tracing::info_span!("the span we're testing");
630    ///     tracing::info!("an event");
631    ///     _ = span.clone();
632    /// });
633    ///
634    /// handle.assert_finished();
635    /// ```
636    pub fn clone_span<S>(mut self, span: S) -> Self
637    where
638        S: Into<ExpectedSpan>,
639    {
640        self.expected.push_back(Expect::CloneSpan(span.into()));
641        self
642    }
643
644    /// **This method is deprecated.**
645    ///
646    /// Adds an expectation that a span matching the [`ExpectedSpan`]
647    /// getting dropped via the deprecated function
648    /// [`Collect::drop_span`] will be recorded next.
649    ///
650    /// Instead [`Collect::try_close`] should be used on the collector
651    /// and should be asserted with `close_span` (which hasn't been
652    /// implemented yet, but will be done as part of #539).
653    ///
654    /// [`Collect::drop_span`]: fn@tracing::Collect::drop_span
655    #[allow(deprecated)]
656    pub fn drop_span<S>(mut self, span: S) -> Self
657    where
658        S: Into<ExpectedSpan>,
659    {
660        self.expected.push_back(Expect::DropSpan(span.into()));
661        self
662    }
663
664    /// Adds an expectation that a `follows_from` relationship will be
665    /// recorded next. Specifically that a span matching `consequence`
666    /// follows from a span matching `cause`.
667    ///
668    /// For further details on what this causal relationship means, see
669    /// [`Span::follows_from`].
670    ///
671    /// If either of the 2 spans don't match their respective
672    /// [`ExpectedSpan`] or if something else (such as an event) is
673    /// recorded first, then the expectation will fail.
674    ///
675    /// **Note**: The 2 spans, `consequence` and `cause` are matched
676    /// by `name` only.
677    ///
678    /// # Examples
679    ///
680    /// ```
681    /// use tracing_mock::{collector, expect};
682    ///
683    /// let cause = expect::span().named("cause");
684    /// let consequence = expect::span().named("consequence");
685    ///
686    /// let (collector, handle) = collector::mock()
687    ///     .follows_from(consequence, cause)
688    ///     .run_with_handle();
689    ///
690    /// tracing::collect::with_default(collector, || {
691    ///     let cause = tracing::info_span!("cause");
692    ///     let consequence = tracing::info_span!("consequence");
693    ///
694    ///     consequence.follows_from(&cause);
695    /// });
696    ///
697    /// handle.assert_finished();
698    /// ```
699    ///
700    /// The `cause` span doesn't match, it is actually recorded at
701    /// `Level::WARN` instead of the expected `Level::INFO`, causing
702    /// this test to fail:
703    ///
704    /// ```should_panic
705    /// use tracing_mock::{collector, expect};
706    ///
707    /// let cause = expect::span().named("cause");
708    /// let consequence = expect::span().named("consequence");
709    ///
710    /// let (collector, handle) = collector::mock()
711    ///     .follows_from(consequence, cause)
712    ///     .run_with_handle();
713    ///
714    /// tracing::collect::with_default(collector, || {
715    ///     let cause = tracing::info_span!("another cause");
716    ///     let consequence = tracing::info_span!("consequence");
717    ///
718    ///     consequence.follows_from(&cause);
719    /// });
720    ///
721    /// handle.assert_finished();
722    /// ```
723    ///
724    /// [`Span::follows_from`]: fn@tracing::Span::follows_from
725    pub fn follows_from<S1, S2>(mut self, consequence: S1, cause: S2) -> Self
726    where
727        S1: Into<ExpectedSpan>,
728        S2: Into<ExpectedSpan>,
729    {
730        self.expected.push_back(Expect::FollowsFrom {
731            consequence: consequence.into(),
732            cause: cause.into(),
733        });
734        self
735    }
736
737    /// Adds an expectation that `fields` are recorded on a span
738    /// matching the [`ExpectedSpan`] will be recorded next.
739    ///
740    /// For further information on how to specify the expected
741    /// fields, see the documentation on the [`field`] module.
742    ///
743    /// If either the span doesn't match the [`ExpectedSpan`], the
744    /// fields don't match the expected fields, or if something else
745    /// (such as an event) is recorded first, then the expectation
746    /// will fail.
747    ///
748    /// # Examples
749    ///
750    /// ```
751    /// use tracing_mock::{collector, expect};
752    ///
753    /// let span = expect::span()
754    ///     .named("my_span");
755    /// let (collector, handle) = collector::mock()
756    ///     .record(span, expect::field("parting").with_value(&"goodbye world!"))
757    ///     .run_with_handle();
758    ///
759    /// tracing::collect::with_default(collector, || {
760    ///     let span = tracing::trace_span!(
761    ///         "my_span",
762    ///         greeting = "hello world",
763    ///         parting = tracing::field::Empty
764    ///     );
765    ///     span.record("parting", "goodbye world!");
766    /// });
767    ///
768    /// handle.assert_finished();
769    /// ```
770    ///
771    /// The value of the recorded field doesn't match the expectation,
772    /// causing the test to fail:
773    ///
774    /// ```should_panic
775    /// use tracing_mock::{collector, expect};
776    ///
777    /// let span = expect::span()
778    ///     .named("my_span");
779    /// let (collector, handle) = collector::mock()
780    ///     .record(span, expect::field("parting").with_value(&"goodbye world!"))
781    ///     .run_with_handle();
782    ///
783    /// tracing::collect::with_default(collector, || {
784    ///     let span = tracing::trace_span!(
785    ///         "my_span",
786    ///         greeting = "hello world",
787    ///         parting = tracing::field::Empty
788    ///     );
789    ///     span.record("parting", "goodbye universe!");
790    /// });
791    ///
792    /// handle.assert_finished();
793    /// ```
794    ///
795    /// [`field`]: mod@crate::field
796    pub fn record<S, I>(mut self, span: S, fields: I) -> Self
797    where
798        S: Into<ExpectedSpan>,
799        I: Into<ExpectedFields>,
800    {
801        self.expected
802            .push_back(Expect::Visit(span.into(), fields.into()));
803        self
804    }
805
806    /// Filter the traces evaluated by the `MockCollector`.
807    ///
808    /// The filter will be applied to all traces received before
809    /// any validation occurs - so its position in the call chain
810    /// is not important. The filter does not perform any validation
811    /// itself.
812    ///
813    /// # Examples
814    ///
815    /// ```
816    /// use tracing_mock::{collector, expect};
817    ///
818    /// let (collector, handle) = collector::mock()
819    ///     .with_filter(|meta| meta.level() <= &tracing::Level::WARN)
820    ///     .event(expect::event())
821    ///     .only()
822    ///     .run_with_handle();
823    ///
824    /// tracing::collect::with_default(collector, || {
825    ///     tracing::info!("a");
826    ///     tracing::warn!("b");
827    /// });
828    ///
829    /// handle.assert_finished();
830    /// ```
831    pub fn with_filter<G>(self, filter: G) -> MockCollector<G>
832    where
833        G: Fn(&Metadata<'_>) -> bool + 'static,
834    {
835        MockCollector {
836            expected: self.expected,
837            filter,
838            max_level: self.max_level,
839            name: self.name,
840        }
841    }
842
843    /// Sets the max level that will be provided to the `tracing`
844    /// system.
845    ///
846    /// This method can be used to test the internals of `tracing`,
847    /// but it is also useful to filter out traces on more verbose
848    /// levels if you only want to verify above a certain level.
849    ///
850    /// **Note**: this value determines a global filter, if
851    /// `with_max_level_hint` is called on multiple collectors, the
852    /// global filter will be the least restrictive of all collectors.
853    /// To filter the events evaluated by a specific `MockCollector`,
854    /// use [`with_filter`] instead.
855    ///
856    /// # Examples
857    ///
858    /// ```
859    /// use tracing_mock::{collector, expect};
860    ///
861    /// let (collector, handle) = collector::mock()
862    ///     .with_max_level_hint(tracing::Level::INFO)
863    ///     .event(expect::event().at_level(tracing::Level::INFO))
864    ///     .only()
865    ///     .run_with_handle();
866    ///
867    /// tracing::collect::with_default(collector, || {
868    ///     tracing::debug!("a message we don't care about");
869    ///     tracing::info!("a message we want to validate");
870    /// });
871    ///
872    /// handle.assert_finished();
873    /// ```
874    ///
875    /// [`with_filter`]: fn@Self::with_filter
876    pub fn with_max_level_hint(self, hint: impl Into<LevelFilter>) -> Self {
877        Self {
878            max_level: Some(hint.into()),
879            ..self
880        }
881    }
882
883    /// Expects that no further traces are received.
884    ///
885    /// The call to `only` should appear immediately before the final
886    /// call to `run` or `run_with_handle`, as any expectations which
887    /// are added after `only` will not be considered.
888    ///
889    /// # Examples
890    ///
891    /// Consider this simple test. It passes even though we only
892    /// expect a single event, but receive three:
893    ///
894    /// ```
895    /// use tracing_mock::{collector, expect};
896    ///
897    /// let (collector, handle) = collector::mock()
898    ///     .event(expect::event())
899    ///     .run_with_handle();
900    ///
901    /// tracing::collect::with_default(collector, || {
902    ///     tracing::info!("a");
903    ///     tracing::info!("b");
904    ///     tracing::info!("c");
905    /// });
906    ///
907    /// handle.assert_finished();
908    /// ```
909    ///
910    /// After including `only`, the test will fail:
911    ///
912    /// ```should_panic
913    /// use tracing_mock::{collector, expect};
914    ///
915    /// let (collector, handle) = collector::mock()
916    ///     .event(expect::event())
917    ///     .only()
918    ///     .run_with_handle();
919    ///
920    /// tracing::collect::with_default(collector, || {
921    ///     tracing::info!("a");
922    ///     tracing::info!("b");
923    ///     tracing::info!("c");
924    /// });
925    ///
926    /// handle.assert_finished();
927    /// ```
928    pub fn only(mut self) -> Self {
929        self.expected.push_back(Expect::Nothing);
930        self
931    }
932
933    /// Consume the receiver and return an `impl` [`Collect`] which can
934    /// be set as the default collector.
935    ///
936    /// This function is similar to [`run_with_handle`], but it doesn't
937    /// return a [`MockHandle`]. This is useful if the desired
938    /// assertions can be checked externally to the collector.
939    ///
940    /// # Examples
941    ///
942    /// The following test is used within the `tracing`
943    /// codebase:
944    ///
945    /// ```
946    /// use tracing_mock::collector;
947    ///
948    /// tracing::collect::with_default(collector::mock().run(), || {
949    ///     let foo1 = tracing::span!(tracing::Level::TRACE, "foo");
950    ///     let foo2 = foo1.clone();
951    ///     // Two handles that point to the same span are equal.
952    ///     assert_eq!(foo1, foo2);
953    /// });
954    /// ```
955    ///
956    /// [`Collect`]: tracing::Collect
957    /// [`run_with_handle`]: fn@Self::run_with_handle
958    pub fn run(self) -> impl Collect {
959        let (collector, _) = self.run_with_handle();
960        collector
961    }
962
963    /// Consume the receiver and return an `impl` [`Collect`] which can
964    /// be set as the default collector and a [`MockHandle`] which can
965    /// be used to validate the provided expectations.
966    ///
967    /// # Examples
968    ///
969    /// ```
970    /// use tracing_mock::{collector, expect};
971    ///
972    /// // collector and handle are returned from `run_with_handle()`
973    /// let (collector, handle) = collector::mock()
974    ///     .event(expect::event())
975    ///     .run_with_handle();
976    ///
977    /// tracing::collect::with_default(collector, || {
978    ///     tracing::info!("a");
979    /// });
980    ///
981    /// handle.assert_finished();
982    /// ```
983    ///
984    /// [`Collect`]: tracing::Collect
985    pub fn run_with_handle(self) -> (impl Collect, MockHandle) {
986        let expected = Arc::new(Mutex::new(self.expected));
987        let handle = MockHandle(expected.clone(), self.name.clone());
988        let collector = Running {
989            spans: Mutex::new(HashMap::new()),
990            expected,
991            current: Mutex::new(Vec::new()),
992            ids: AtomicUsize::new(1),
993            filter: self.filter,
994            max_level: self.max_level,
995            name: self.name,
996        };
997        (collector, handle)
998    }
999}
1000
1001impl<F> Collect for Running<F>
1002where
1003    F: Fn(&Metadata<'_>) -> bool + 'static,
1004{
1005    fn enabled(&self, meta: &Metadata<'_>) -> bool {
1006        println!("[{}] enabled: {:#?}", self.name, meta);
1007        let enabled = (self.filter)(meta);
1008        println!("[{}] enabled -> {}", self.name, enabled);
1009        enabled
1010    }
1011
1012    fn register_callsite(&self, meta: &'static Metadata<'static>) -> Interest {
1013        println!("[{}] register_callsite: {:#?}", self.name, meta);
1014        if self.enabled(meta) {
1015            Interest::always()
1016        } else {
1017            Interest::never()
1018        }
1019    }
1020    fn max_level_hint(&self) -> Option<LevelFilter> {
1021        self.max_level
1022    }
1023
1024    fn record(&self, id: &Id, values: &span::Record<'_>) {
1025        let spans = self.spans.lock().unwrap();
1026        let mut expected = self.expected.lock().unwrap();
1027        let span = spans
1028            .get(id)
1029            .unwrap_or_else(|| panic!("[{}] no span for ID {:?}", self.name, id));
1030        println!(
1031            "[{}] record: {}; id={:?}; values={:?};",
1032            self.name, span.name, id, values
1033        );
1034        let was_expected = matches!(expected.front(), Some(Expect::Visit(_, _)));
1035        if was_expected {
1036            if let Expect::Visit(expected_span, mut expected_values) = expected.pop_front().unwrap()
1037            {
1038                if let Some(name) = expected_span.name() {
1039                    assert_eq!(name, span.name);
1040                }
1041                let context = format!("span {}: ", span.name);
1042                let mut checker = expected_values.checker(&context, &self.name);
1043                values.record(&mut checker);
1044                checker.finish();
1045            }
1046        }
1047    }
1048
1049    fn event(&self, event: &Event<'_>) {
1050        let name = event.metadata().name();
1051        println!("[{}] event: {};", self.name, name);
1052        match self.expected.lock().unwrap().pop_front() {
1053            None => {}
1054            Some(Expect::Event(mut expected)) => {
1055                #[cfg(feature = "tracing-subscriber")]
1056                {
1057                    if expected.scope_mut().is_some() {
1058                        unimplemented!(
1059                            "Expected scope for events is not supported with `MockCollector`."
1060                        )
1061                    }
1062                }
1063                let event_get_ancestry = || {
1064                    get_ancestry(
1065                        event,
1066                        || self.lookup_current(),
1067                        |span_id| {
1068                            self.spans
1069                                .lock()
1070                                .unwrap()
1071                                .get(span_id)
1072                                .map(|span| span.into())
1073                        },
1074                    )
1075                };
1076                expected.check(event, event_get_ancestry, &self.name);
1077            }
1078            Some(ex) => ex.bad(&self.name, format_args!("observed event {:#?}", event)),
1079        }
1080    }
1081
1082    fn record_follows_from(&self, consequence_id: &Id, cause_id: &Id) {
1083        let spans = self.spans.lock().unwrap();
1084        if let Some(consequence_span) = spans.get(consequence_id) {
1085            if let Some(cause_span) = spans.get(cause_id) {
1086                println!(
1087                    "[{}] record_follows_from: {} (id={:?}) follows {} (id={:?})",
1088                    self.name, consequence_span.name, consequence_id, cause_span.name, cause_id,
1089                );
1090                match self.expected.lock().unwrap().pop_front() {
1091                    None => {}
1092                    Some(Expect::FollowsFrom {
1093                        consequence: ref expected_consequence,
1094                        cause: ref expected_cause,
1095                    }) => {
1096                        if let Some(name) = expected_consequence.name() {
1097                            // TODO(hds): Write proper assertion text.
1098                            assert_eq!(name, consequence_span.name);
1099                        }
1100                        if let Some(name) = expected_cause.name() {
1101                            // TODO(hds): Write proper assertion text.
1102                            assert_eq!(name, cause_span.name);
1103                        }
1104                    }
1105                    Some(ex) => ex.bad(
1106                        &self.name,
1107                        format_args!(
1108                            "consequence {:?} followed cause {:?}",
1109                            consequence_span.name, cause_span.name
1110                        ),
1111                    ),
1112                }
1113            }
1114        };
1115    }
1116
1117    fn new_span(&self, span: &Attributes<'_>) -> Id {
1118        let meta = span.metadata();
1119        let id = self.ids.fetch_add(1, Ordering::SeqCst);
1120        let id = Id::from_u64(id as u64);
1121        println!(
1122            "[{}] new_span: name={:?}; target={:?}; id={:?};",
1123            self.name,
1124            meta.name(),
1125            meta.target(),
1126            id
1127        );
1128        let mut expected = self.expected.lock().unwrap();
1129        let was_expected = matches!(expected.front(), Some(Expect::NewSpan(_)));
1130        let mut spans = self.spans.lock().unwrap();
1131        if was_expected {
1132            if let Expect::NewSpan(mut expected) = expected.pop_front().unwrap() {
1133                if let Some(expected_id) = &expected.span.id {
1134                    expected_id.set(id.into_u64()).unwrap();
1135                }
1136
1137                expected.check(
1138                    span,
1139                    || {
1140                        get_ancestry(
1141                            span,
1142                            || self.lookup_current(),
1143                            |span_id| spans.get(span_id).map(|span| span.into()),
1144                        )
1145                    },
1146                    &self.name,
1147                );
1148            }
1149        }
1150        spans.insert(
1151            id.clone(),
1152            SpanState {
1153                id: id.clone(),
1154                name: meta.name(),
1155                refs: 1,
1156                meta,
1157            },
1158        );
1159        id
1160    }
1161
1162    fn enter(&self, id: &Id) {
1163        let spans = self.spans.lock().unwrap();
1164        if let Some(span) = spans.get(id) {
1165            println!("[{}] enter: {}; id={:?};", self.name, span.name, id);
1166            match self.expected.lock().unwrap().pop_front() {
1167                None => {}
1168                Some(Expect::Enter(ref expected_span)) => {
1169                    expected_span.check(&span.into(), "to enter a span", &self.name);
1170                }
1171                Some(ex) => ex.bad(&self.name, format_args!("entered span {:?}", span.name)),
1172            }
1173        };
1174        self.current.lock().unwrap().push(id.clone());
1175    }
1176
1177    fn exit(&self, id: &Id) {
1178        if std::thread::panicking() {
1179            // `exit()` can be called in `drop` impls, so we must guard against
1180            // double panics.
1181            println!("[{}] exit {:?} while panicking", self.name, id);
1182            return;
1183        }
1184        let spans = self.spans.lock().unwrap();
1185        let span = spans
1186            .get(id)
1187            .unwrap_or_else(|| panic!("[{}] no span for ID {:?}", self.name, id));
1188        println!("[{}] exit: {}; id={:?};", self.name, span.name, id);
1189        match self.expected.lock().unwrap().pop_front() {
1190            None => {}
1191            Some(Expect::Exit(ref expected_span)) => {
1192                expected_span.check(&span.into(), "to exit a span", &self.name);
1193                let curr = self.current.lock().unwrap().pop();
1194                assert_eq!(
1195                    Some(id),
1196                    curr.as_ref(),
1197                    "[{}] exited span {:?}, but the current span was {:?}",
1198                    self.name,
1199                    span.name,
1200                    curr.as_ref().and_then(|id| spans.get(id)).map(|s| s.name)
1201                );
1202            }
1203            Some(ex) => ex.bad(&self.name, format_args!("exited span {:?}", span.name)),
1204        };
1205    }
1206
1207    fn clone_span(&self, id: &Id) -> Id {
1208        let mut spans = self.spans.lock().unwrap();
1209        let mut span = spans.get_mut(id);
1210        match span.as_deref_mut() {
1211            Some(span) => {
1212                println!(
1213                    "[{}] clone_span: {}; id={:?}; refs={:?};",
1214                    self.name, span.name, id, span.refs,
1215                );
1216                span.refs += 1;
1217            }
1218            None => {
1219                println!(
1220                    "[{}] clone_span: id={:?} (not found in span list);",
1221                    self.name, id
1222                );
1223            }
1224        }
1225
1226        let mut expected = self.expected.lock().unwrap();
1227        let was_expected = if let Some(Expect::CloneSpan(ref expected_span)) = expected.front() {
1228            match span {
1229                Some(actual_span) => {
1230                    let actual_span: &_ = actual_span;
1231                    expected_span.check(&actual_span.into(), "to clone a span", &self.name);
1232                }
1233                // Check only by Id
1234                None => expected_span.check(&id.into(), "to clone a span", &self.name),
1235            }
1236            true
1237        } else {
1238            false
1239        };
1240        if was_expected {
1241            expected.pop_front();
1242        }
1243        id.clone()
1244    }
1245
1246    fn drop_span(&self, id: Id) {
1247        let mut is_event = false;
1248        let name = if let Ok(mut spans) = self.spans.try_lock() {
1249            spans.get_mut(&id).map(|span| {
1250                let name = span.name;
1251                if name.contains("event") {
1252                    is_event = true;
1253                }
1254                println!(
1255                    "[{}] drop_span: {}; id={:?}; refs={:?};",
1256                    self.name, name, id, span.refs
1257                );
1258                span.refs -= 1;
1259                name
1260            })
1261        } else {
1262            None
1263        };
1264        if name.is_none() {
1265            println!("[{}] drop_span: id={:?}", self.name, id);
1266        }
1267        if let Ok(mut expected) = self.expected.try_lock() {
1268            let was_expected = match expected.front() {
1269                Some(Expect::DropSpan(ref span)) => {
1270                    // Don't assert if this function was called while panicking,
1271                    // as failing the assertion can cause a double panic.
1272                    if !::std::thread::panicking() {
1273                        assert_eq!(name, span.name());
1274                    }
1275                    true
1276                }
1277                Some(Expect::Event(_)) => {
1278                    if !::std::thread::panicking() {
1279                        assert!(is_event, "[{}] expected an event", self.name);
1280                    }
1281                    true
1282                }
1283                _ => false,
1284            };
1285            if was_expected {
1286                expected.pop_front();
1287            }
1288        }
1289    }
1290
1291    fn current_span(&self) -> tracing_core::span::Current {
1292        let stack = self.current.lock().unwrap();
1293        match stack.last() {
1294            Some(id) => {
1295                let spans = self.spans.lock().unwrap();
1296                let state = spans.get(id).expect("state for current span");
1297                tracing_core::span::Current::new(id.clone(), state.meta)
1298            }
1299            None => tracing_core::span::Current::none(),
1300        }
1301    }
1302}
1303
1304impl<F> Running<F>
1305where
1306    F: Fn(&Metadata<'_>) -> bool,
1307{
1308    fn lookup_current(&self) -> Option<span::Id> {
1309        let stack = self.current.lock().unwrap();
1310        stack.last().cloned()
1311    }
1312}
1313
1314impl MockHandle {
1315    #[cfg(feature = "tracing-subscriber")]
1316    pub(crate) fn new(expected: Arc<Mutex<VecDeque<Expect>>>, name: String) -> Self {
1317        Self(expected, name)
1318    }
1319
1320    /// Checks the expectations which were set on the
1321    /// [`MockCollector`].
1322    ///
1323    /// Calling `assert_finished` is usually the final part of a test.
1324    ///
1325    /// # Panics
1326    ///
1327    /// This method will panic if any of the provided expectations are
1328    /// not met.
1329    ///
1330    /// # Examples
1331    ///
1332    /// ```
1333    /// use tracing_mock::{collector, expect};
1334    ///
1335    /// let (collector, handle) = collector::mock()
1336    ///     .event(expect::event())
1337    ///     .run_with_handle();
1338    ///
1339    /// tracing::collect::with_default(collector, || {
1340    ///     tracing::info!("a");
1341    /// });
1342    ///
1343    /// // Check assertions set on the mock collector
1344    /// handle.assert_finished();
1345    /// ```
1346    pub fn assert_finished(&self) {
1347        if let Ok(ref expected) = self.0.lock() {
1348            assert!(
1349                !expected.iter().any(|thing| thing != &Expect::Nothing),
1350                "\n[{}] more notifications expected: {:#?}",
1351                self.1,
1352                **expected
1353            );
1354        }
1355    }
1356}