tracing_indicatif/
filter.rs

1//! Provides a rudimentary filter layer that can be used to selectively enable progress bars on a
2//! per-span level.
3//!
4//! # Example Use
5//!
6//! ```
7//! use tracing_subscriber::layer::SubscriberExt;
8//! use tracing_subscriber::util::SubscriberInitExt;
9//! use tracing_indicatif::IndicatifLayer;
10//! use tracing_indicatif::filter::IndicatifFilter;
11//! use tracing_indicatif::filter::hide_indicatif_span_fields;
12//! use tracing_subscriber::fmt::format::DefaultFields;
13//! use tracing_subscriber::layer::Layer;
14//!
15//! let indicatif_layer = IndicatifLayer::new()
16//!     .with_span_field_formatter(hide_indicatif_span_fields(DefaultFields::new()));
17//!
18//! tracing_subscriber::registry()
19//!     .with(tracing_subscriber::fmt::layer().with_writer(indicatif_layer.get_stderr_writer()))
20//!     .with(indicatif_layer.with_filter(IndicatifFilter::new(false)))
21//!     .init();
22//! ```
23use std::fmt;
24use std::marker::PhantomData;
25
26use tracing_core::{Field, Subscriber};
27use tracing_subscriber::layer::Filter;
28use tracing_subscriber::{
29    field::{MakeVisitor, VisitFmt, VisitOutput},
30    fmt::format::Writer,
31};
32
33use crate::util::FilteredFormatFields;
34
35/// A filter that filters based on the presence of a field with the name of either
36/// "indicatif.pb_show" or "indicatif.pb_hide" on the span.
37///
38/// The value for this field is irrelevant and not factored in to the filtering (this is due to
39/// tracing not making field values available in the `on_new_span` method). To avoid confusion, it
40/// is recommended to set the value of this field to [`tracing::field::Empty`].
41///
42/// If both "indicatif.pb_show" and "indicatif.pb_hide" are present, the behavior is to show a
43/// progress bar.
44pub struct IndicatifFilter<S> {
45    show_progress_bars_by_default: bool,
46    subscriber: PhantomData<S>,
47}
48
49impl<S: Subscriber> IndicatifFilter<S> {
50    /// Constructs the filter.
51    ///
52    /// If "indicatif.pb_show" or "indicatif.pb_hide" are not present as a field on the span,
53    /// then the value of `show_progress_bars_by_default` is used; i.e. if
54    /// `show_progress_bars_by_default` is `false`, then progress bars are not shown for spans by
55    /// default.
56    pub fn new(show_progress_bars_by_default: bool) -> Self {
57        Self {
58            show_progress_bars_by_default,
59            subscriber: PhantomData,
60        }
61    }
62}
63
64impl<S: Subscriber> Filter<S> for IndicatifFilter<S> {
65    fn enabled(
66        &self,
67        meta: &tracing::Metadata<'_>,
68        _: &tracing_subscriber::layer::Context<'_, S>,
69    ) -> bool {
70        if !meta.is_span() {
71            return false;
72        }
73
74        if meta.fields().field("indicatif.pb_show").is_some() {
75            return true;
76        }
77
78        if meta.fields().field("indicatif.pb_hide").is_some() {
79            return false;
80        }
81
82        self.show_progress_bars_by_default
83    }
84}
85
86/// Returns a [`tracing_subscriber::fmt::FormatFields`] that ignores the "indicatif.pb_show" and "indicatif.pb_hide" fields.
87pub fn hide_indicatif_span_fields<'writer, Format>(
88    format: Format,
89) -> FilteredFormatFields<Format, impl Fn(&Field) -> bool + Clone>
90where
91    Format: MakeVisitor<Writer<'writer>>,
92    Format::Visitor: VisitFmt + VisitOutput<fmt::Result>,
93{
94    FilteredFormatFields::new(format, |field: &Field| {
95        field.name() != "indicatif.pb_show" && field.name() != "indicatif.pb_hide"
96    })
97}