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}