🛈 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

Struct MockCollector

Source
pub struct MockCollector<F: Fn(&Metadata<'_>) -> bool> { /* private fields */ }
Expand description

A collector which can validate received traces.

For a detailed description and examples see the documentation for the methods and the collector module.

Implementations§

Source§

impl<F> MockCollector<F>
where F: Fn(&Metadata<'_>) -> bool + 'static,

Source

pub fn named(self, name: impl ToString) -> Self

Overrides the name printed by the mock subscriber’s debugging output.

The debugging output is displayed if the test panics, or if the test is run with --nocapture.

By default, the mock collector’s name is the name of the test (technically, the name of the thread where it was created, which is the name of the test unless tests are run with --test-threads=1). When a test has only one mock collector, this is sufficient. However, some tests may include multiple collectors, in order to test interactions between multiple collectors. In that case, it can be helpful to give each collector a separate name to distinguish where the debugging output comes from.

§Examples

In the following example, we create 2 collectors, both expecting to receive an event. As we only record a single event, the test will fail:

use tracing_mock::{collector, expect};

let (collector_1, handle_1) = collector::mock()
    .named("collector-1")
    .event(expect::event())
    .run_with_handle();

let (collector_2, handle_2) = collector::mock()
    .named("collector-2")
    .event(expect::event())
    .run_with_handle();

let _guard = tracing::collect::set_default(collector_2);

tracing::collect::with_default(collector_1, || {
    tracing::info!("a");
});

handle_1.assert_finished();
handle_2.assert_finished();

In the test output, we see that the collector which didn’t received the event was the one named collector-2, which is correct as the collector named collector-1 was the default when the event was recorded:

[collector-2] more notifications expected: [
    Event(
        MockEvent,
    ),
]', tracing-mock/src/collector.rs:1276:13
Source

pub fn event(self, event: ExpectedEvent) -> Self

Adds an expectation that an event matching the ExpectedEvent will be recorded next.

The event can be a default mock which will match any event (expect::event()) or can include additional expectations. See the ExpectedEvent documentation for more details.

If an event is recorded that doesn’t match the ExpectedEvent, or if something else (such as entering a span) is recorded first, then the expectation will fail.

§Examples
use tracing_mock::{collector, expect};

let (collector, handle) = collector::mock()
    .event(expect::event())
    .run_with_handle();

tracing::collect::with_default(collector, || {
    tracing::info!("a");
});

handle.assert_finished();

A span is entered before the event, causing the test to fail:

use tracing_mock::{collector, expect};

let (collector, handle) = collector::mock()
    .event(expect::event())
    .run_with_handle();

tracing::collect::with_default(collector, || {
    let span = tracing::info_span!("span");
    let _guard = span.enter();
    tracing::info!("a");
});

handle.assert_finished();
Source

pub fn new_span<I>(self, new_span: I) -> Self
where I: Into<NewSpan>,

Adds an expectation that the creation of a span will be recorded next.

This function accepts Into<NewSpan> instead of ExpectedSpan directly, so it can be used to test span fields and the span parent. This is because a collector only receives the span fields and parent when a span is created, not when it is entered.

The new span doesn’t need to be entered for this expectation to succeed.

If a span is recorded that doesn’t match the ExpectedSpan, or if something else (such as an event) is recorded first, then the expectation will fail.

§Examples
use tracing_mock::{collector, expect};

let span = expect::span()
    .at_level(tracing::Level::INFO)
    .named("the span we're testing")
    .with_fields(expect::field("testing").with_value(&"yes"));
let (collector, handle) = collector::mock()
    .new_span(span)
    .run_with_handle();

tracing::collect::with_default(collector, || {
    _ = tracing::info_span!("the span we're testing", testing = "yes");
});

handle.assert_finished();

An event is recorded before the span is created, causing the test to fail:

use tracing_mock::{collector, expect};

let span = expect::span()
    .at_level(tracing::Level::INFO)
    .named("the span we're testing")
    .with_fields(expect::field("testing").with_value(&"yes"));
let (collector, handle) = collector::mock()
    .new_span(span)
    .run_with_handle();

tracing::collect::with_default(collector, || {
    tracing::info!("an event");
    _ = tracing::info_span!("the span we're testing", testing = "yes");
});

handle.assert_finished();
Source

pub fn enter<S>(self, span: S) -> Self
where S: Into<ExpectedSpan>,

Adds an expectation that entering a span matching the ExpectedSpan will be recorded next.

This expectation is generally accompanied by a call to exit as well. If used together with only, this is necessary.

If the span that is entered doesn’t match the ExpectedSpan, or if something else (such as an event) is recorded first, then the expectation will fail.

§Examples
use tracing_mock::{collector, expect};

let span = expect::span()
    .at_level(tracing::Level::INFO)
    .named("the span we're testing");
let (collector, handle) = collector::mock()
    .enter(&span)
    .exit(&span)
    .only()
    .run_with_handle();

tracing::collect::with_default(collector, || {
    let span = tracing::info_span!("the span we're testing");
    let _entered = span.enter();
});

handle.assert_finished();

An event is recorded before the span is entered, causing the test to fail:

use tracing_mock::{collector, expect};

let span = expect::span()
    .at_level(tracing::Level::INFO)
    .named("the span we're testing");
let (collector, handle) = collector::mock()
    .enter(&span)
    .exit(&span)
    .only()
    .run_with_handle();

tracing::collect::with_default(collector, || {
    tracing::info!("an event");
    let span = tracing::info_span!("the span we're testing");
    let _entered = span.enter();
});

handle.assert_finished();
Source

pub fn exit<S>(self, span: S) -> Self
where S: Into<ExpectedSpan>,

Adds ab expectation that exiting a span matching the ExpectedSpan will be recorded next.

As a span may be entered and exited multiple times, this is different from the span being closed. In general enter and exit should be paired.

If the span that is exited doesn’t match the ExpectedSpan, or if something else (such as an event) is recorded first, then the expectation will fail.

§Examples
use tracing_mock::{collector, expect};

let span = expect::span()
    .at_level(tracing::Level::INFO)
    .named("the span we're testing");
let (collector, handle) = collector::mock()
    .enter(&span)
    .exit(&span)
    .run_with_handle();

tracing::collect::with_default(collector, || {
    let span = tracing::info_span!("the span we're testing");
    let _entered = span.enter();
});

handle.assert_finished();

An event is recorded before the span is exited, causing the test to fail:

use tracing_mock::{collector, expect};

let span = expect::span()
    .at_level(tracing::Level::INFO)
    .named("the span we're testing");
let (collector, handle) = collector::mock()
    .enter(&span)
    .exit(&span)
    .run_with_handle();

tracing::collect::with_default(collector, || {
    let span = tracing::info_span!("the span we're testing");
    let _entered = span.enter();
    tracing::info!("an event");
});

handle.assert_finished();
Source

pub fn clone_span<S>(self, span: S) -> Self
where S: Into<ExpectedSpan>,

Adds an expectation that cloning a span matching the ExpectedSpan will be recorded next.

The cloned span does need to be entered.

If the span that is cloned doesn’t match the ExpectedSpan, or if something else (such as an event) is recorded first, then the expectation will fail.

§Examples
use tracing_mock::{collector, expect};

let span = expect::span()
    .at_level(tracing::Level::INFO)
    .named("the span we're testing");
let (collector, handle) = collector::mock()
    .clone_span(span)
    .run_with_handle();

tracing::collect::with_default(collector, || {
    let span = tracing::info_span!("the span we're testing");
    _ = span.clone();
});

handle.assert_finished();

An event is recorded before the span is cloned, causing the test to fail:

use tracing_mock::{collector, expect};

let span = expect::span()
    .at_level(tracing::Level::INFO)
    .named("the span we're testing");
let (collector, handle) = collector::mock()
    .clone_span(span)
    .run_with_handle();

tracing::collect::with_default(collector, || {
    let span = tracing::info_span!("the span we're testing");
    tracing::info!("an event");
    _ = span.clone();
});

handle.assert_finished();
Source

pub fn drop_span<S>(self, span: S) -> Self
where S: Into<ExpectedSpan>,

This method is deprecated.

Adds an expectation that a span matching the ExpectedSpan getting dropped via the deprecated function Collect::drop_span will be recorded next.

Instead Collect::try_close should be used on the collector and should be asserted with close_span (which hasn’t been implemented yet, but will be done as part of #539).

Source

pub fn follows_from<S1, S2>(self, consequence: S1, cause: S2) -> Self

Adds an expectation that a follows_from relationship will be recorded next. Specifically that a span matching consequence follows from a span matching cause.

For further details on what this causal relationship means, see Span::follows_from.

If either of the 2 spans don’t match their respective ExpectedSpan or if something else (such as an event) is recorded first, then the expectation will fail.

Note: The 2 spans, consequence and cause are matched by name only.

§Examples
use tracing_mock::{collector, expect};

let cause = expect::span().named("cause");
let consequence = expect::span().named("consequence");

let (collector, handle) = collector::mock()
    .follows_from(consequence, cause)
    .run_with_handle();

tracing::collect::with_default(collector, || {
    let cause = tracing::info_span!("cause");
    let consequence = tracing::info_span!("consequence");

    consequence.follows_from(&cause);
});

handle.assert_finished();

The cause span doesn’t match, it is actually recorded at Level::WARN instead of the expected Level::INFO, causing this test to fail:

use tracing_mock::{collector, expect};

let cause = expect::span().named("cause");
let consequence = expect::span().named("consequence");

let (collector, handle) = collector::mock()
    .follows_from(consequence, cause)
    .run_with_handle();

tracing::collect::with_default(collector, || {
    let cause = tracing::info_span!("another cause");
    let consequence = tracing::info_span!("consequence");

    consequence.follows_from(&cause);
});

handle.assert_finished();
Source

pub fn record<S, I>(self, span: S, fields: I) -> Self

Adds an expectation that fields are recorded on a span matching the ExpectedSpan will be recorded next.

For further information on how to specify the expected fields, see the documentation on the field module.

If either the span doesn’t match the ExpectedSpan, the fields don’t match the expected fields, or if something else (such as an event) is recorded first, then the expectation will fail.

§Examples
use tracing_mock::{collector, expect};

let span = expect::span()
    .named("my_span");
let (collector, handle) = collector::mock()
    .record(span, expect::field("parting").with_value(&"goodbye world!"))
    .run_with_handle();

tracing::collect::with_default(collector, || {
    let span = tracing::trace_span!(
        "my_span",
        greeting = "hello world",
        parting = tracing::field::Empty
    );
    span.record("parting", "goodbye world!");
});

handle.assert_finished();

The value of the recorded field doesn’t match the expectation, causing the test to fail:

use tracing_mock::{collector, expect};

let span = expect::span()
    .named("my_span");
let (collector, handle) = collector::mock()
    .record(span, expect::field("parting").with_value(&"goodbye world!"))
    .run_with_handle();

tracing::collect::with_default(collector, || {
    let span = tracing::trace_span!(
        "my_span",
        greeting = "hello world",
        parting = tracing::field::Empty
    );
    span.record("parting", "goodbye universe!");
});

handle.assert_finished();
Source

pub fn with_filter<G>(self, filter: G) -> MockCollector<G>
where G: Fn(&Metadata<'_>) -> bool + 'static,

Filter the traces evaluated by the MockCollector.

The filter will be applied to all traces received before any validation occurs - so its position in the call chain is not important. The filter does not perform any validation itself.

§Examples
use tracing_mock::{collector, expect};

let (collector, handle) = collector::mock()
    .with_filter(|meta| meta.level() <= &tracing::Level::WARN)
    .event(expect::event())
    .only()
    .run_with_handle();

tracing::collect::with_default(collector, || {
    tracing::info!("a");
    tracing::warn!("b");
});

handle.assert_finished();
Source

pub fn with_max_level_hint(self, hint: impl Into<LevelFilter>) -> Self

Sets the max level that will be provided to the tracing system.

This method can be used to test the internals of tracing, but it is also useful to filter out traces on more verbose levels if you only want to verify above a certain level.

Note: this value determines a global filter, if with_max_level_hint is called on multiple collectors, the global filter will be the least restrictive of all collectors. To filter the events evaluated by a specific MockCollector, use with_filter instead.

§Examples
use tracing_mock::{collector, expect};

let (collector, handle) = collector::mock()
    .with_max_level_hint(tracing::Level::INFO)
    .event(expect::event().at_level(tracing::Level::INFO))
    .only()
    .run_with_handle();

tracing::collect::with_default(collector, || {
    tracing::debug!("a message we don't care about");
    tracing::info!("a message we want to validate");
});

handle.assert_finished();
Source

pub fn only(self) -> Self

Expects that no further traces are received.

The call to only should appear immediately before the final call to run or run_with_handle, as any expectations which are added after only will not be considered.

§Examples

Consider this simple test. It passes even though we only expect a single event, but receive three:

use tracing_mock::{collector, expect};

let (collector, handle) = collector::mock()
    .event(expect::event())
    .run_with_handle();

tracing::collect::with_default(collector, || {
    tracing::info!("a");
    tracing::info!("b");
    tracing::info!("c");
});

handle.assert_finished();

After including only, the test will fail:

use tracing_mock::{collector, expect};

let (collector, handle) = collector::mock()
    .event(expect::event())
    .only()
    .run_with_handle();

tracing::collect::with_default(collector, || {
    tracing::info!("a");
    tracing::info!("b");
    tracing::info!("c");
});

handle.assert_finished();
Source

pub fn run(self) -> impl Collect

Consume the receiver and return an impl Collect which can be set as the default collector.

This function is similar to run_with_handle, but it doesn’t return a MockHandle. This is useful if the desired assertions can be checked externally to the collector.

§Examples

The following test is used within the tracing codebase:

use tracing_mock::collector;

tracing::collect::with_default(collector::mock().run(), || {
    let foo1 = tracing::span!(tracing::Level::TRACE, "foo");
    let foo2 = foo1.clone();
    // Two handles that point to the same span are equal.
    assert_eq!(foo1, foo2);
});
Source

pub fn run_with_handle(self) -> (impl Collect, MockHandle)

Consume the receiver and return an impl Collect which can be set as the default collector and a MockHandle which can be used to validate the provided expectations.

§Examples
use tracing_mock::{collector, expect};

// collector and handle are returned from `run_with_handle()`
let (collector, handle) = collector::mock()
    .event(expect::event())
    .run_with_handle();

tracing::collect::with_default(collector, || {
    tracing::info!("a");
});

handle.assert_finished();

Trait Implementations§

Source§

impl<F: Debug + Fn(&Metadata<'_>) -> bool> Debug for MockCollector<F>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<F> Freeze for MockCollector<F>
where F: Freeze,

§

impl<F> RefUnwindSafe for MockCollector<F>
where F: RefUnwindSafe,

§

impl<F> Send for MockCollector<F>
where F: Send,

§

impl<F> Sync for MockCollector<F>
where F: Sync,

§

impl<F> Unpin for MockCollector<F>
where F: Unpin,

§

impl<F> UnwindSafe for MockCollector<F>
where F: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithCollector for T

Source§

fn with_collector<C>(self, collector: C) -> WithDispatch<Self>
where C: Into<Dispatch>,

Attaches the provided collector to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_collector(self) -> WithDispatch<Self>

Attaches the current default collector to this type, returning a WithDispatch wrapper. Read more