tracing_mock::subscriber

Struct MockSubscriber

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

A subscriber which can validate received traces.

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

Implementations§

Source§

impl<F> MockSubscriber<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 subscriber’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 subscriber, this is sufficient. However, some tests may include multiple subscribers, in order to test interactions between multiple subscribers. In that case, it can be helpful to give each subscriber a separate name to distinguish where the debugging output comes from.

§Examples

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

use tracing_mock::{expect, subscriber};

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

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

let _guard = tracing::subscriber::set_default(subscriber_2);

tracing::subscriber::with_default(subscriber_1, || {
    tracing::info!("a");
});

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

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

[subscriber-2] more notifications expected: [
    Event(
        MockEvent,
    ),
]', tracing-mock/src/subscriber.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::{expect, subscriber};

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

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

handle.assert_finished();

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

use tracing_mock::{expect, subscriber};

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

tracing::subscriber::with_default(subscriber, || {
    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 subscriber 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::{expect, subscriber};

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

tracing::subscriber::with_default(subscriber, || {
    _ = 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::{expect, subscriber};

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

tracing::subscriber::with_default(subscriber, || {
    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::{expect, subscriber};

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

tracing::subscriber::with_default(subscriber, || {
    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::{expect, subscriber};

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

tracing::subscriber::with_default(subscriber, || {
    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::{expect, subscriber};

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

tracing::subscriber::with_default(subscriber, || {
    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::{expect, subscriber};

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

tracing::subscriber::with_default(subscriber, || {
    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::{expect, subscriber};

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

tracing::subscriber::with_default(subscriber, || {
    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::{expect, subscriber};

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

tracing::subscriber::with_default(subscriber, || {
    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 Subscriber::drop_span will be recorded next.

Instead Subscriber::try_close should be used on the subscriber 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::{expect, subscriber};

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

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

tracing::subscriber::with_default(subscriber, || {
    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::{expect, subscriber};

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

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

tracing::subscriber::with_default(subscriber, || {
    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::{expect, subscriber};

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

tracing::subscriber::with_default(subscriber, || {
    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::{expect, subscriber};

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

tracing::subscriber::with_default(subscriber, || {
    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) -> MockSubscriber<G>
where G: Fn(&Metadata<'_>) -> bool + 'static,

Filter the traces evaluated by the MockSubscriber.

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::{expect, subscriber};

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

tracing::subscriber::with_default(subscriber, || {
    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 subscribers, the global filter will be the least restrictive of all subscribers. To filter the events evaluated by a specific MockSubscriber, use with_filter instead.

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

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

tracing::subscriber::with_default(subscriber, || {
    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::{expect, subscriber};

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

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

handle.assert_finished();

After including only, the test will fail:

use tracing_mock::{expect, subscriber};

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

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

handle.assert_finished();
Source

pub fn run(self) -> impl Subscriber

Consume the receiver and return an impl Subscriber which can be set as the default subscriber.

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 subscriber.

§Examples

The following test is used within the tracing codebase:

use tracing_mock::subscriber;

tracing::subscriber::with_default(subscriber::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 Subscriber, MockHandle)

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

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

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

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

handle.assert_finished();

Trait Implementations§

Source§

impl<F: Debug + Fn(&Metadata<'_>) -> bool> Debug for MockSubscriber<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 MockSubscriber<F>
where F: Freeze,

§

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

§

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

§

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

§

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

§

impl<F> UnwindSafe for MockSubscriber<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> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

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

fn with_current_subscriber(self) -> WithDispatch<Self>

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