Skip to content

Commit 86bc45c

Browse files
committed
subscriber: Add MakeWriter impl for Option
This adds a `MakeWriter` impl for `Option<M>` where `M: MakeWriter`. This makes it possible to use `Option<MakeWriter>` in combination with other `MakeWriter` implementations (e.g. `Tee`). An example is found in #776, where depending on the configuration, the user might want to use any or all of `File`, `Stdout`, and `Stderr` writers. ```rust let stdout = if enable_stdout { Some(std::io::stdout) } else { None }; let stderr = if enable_stderr { Some(std::io::stderr) } else { None }; let file = if let Some(path) { Some(File::create(path)?) } else { None }; let multi_make_writer = stdout.and(stderr).and(file); ```
1 parent b486867 commit 86bc45c

File tree

1 file changed

+107
-0
lines changed

1 file changed

+107
-0
lines changed

Diff for: tracing-subscriber/src/fmt/writer.rs

+107
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,16 @@ use tracing_core::Metadata;
5757
/// # drop(subscriber);
5858
/// ```
5959
///
60+
/// `MakeWriter` is implemented for `Option<M>` when `M` implements `MakeWriter`.
61+
///
62+
/// ```
63+
/// # let enable_stdout = true;
64+
/// let subscriber = tracing_subscriber::fmt()
65+
/// .with_writer(enable_stdout.then_some(std::io::stdout))
66+
/// .finish();
67+
/// # drop(subscriber);
68+
/// ```
69+
///
6070
/// A closure can be used to introduce arbitrary logic into how the writer is
6171
/// created. Consider the (admittedly rather silly) example of sending every 5th
6272
/// event to stderr, and all other events to stdout:
@@ -1095,6 +1105,27 @@ where
10951105
}
10961106
}
10971107

1108+
impl<'a, M> MakeWriter<'a> for Option<M>
1109+
where
1110+
M: MakeWriter<'a> + 'static,
1111+
{
1112+
type Writer = OptionalWriter<M::Writer>;
1113+
1114+
fn make_writer(&'a self) -> Self::Writer {
1115+
match self {
1116+
Some(inner) => OptionalWriter::some(inner.make_writer()),
1117+
None => OptionalWriter::none(),
1118+
}
1119+
}
1120+
1121+
fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer {
1122+
match self {
1123+
Some(inner) => OptionalWriter::some(inner.make_writer_for(meta)),
1124+
None => OptionalWriter::none(),
1125+
}
1126+
}
1127+
}
1128+
10981129
// === impl WriteAdaptor ===
10991130

11001131
#[cfg(any(feature = "json", feature = "time"))]
@@ -1391,4 +1422,80 @@ mod test {
13911422
has_lines(&a_buf, &lines[..]);
13921423
has_lines(&b_buf, &lines[..]);
13931424
}
1425+
1426+
#[test]
1427+
fn option_some_makewriter() {
1428+
let buf = Arc::new(Mutex::new(Vec::new()));
1429+
let make_writer = Some(MockMakeWriter::new(buf.clone()));
1430+
1431+
let lines = &[(Level::INFO, "hello"), (Level::INFO, "world")];
1432+
let c = {
1433+
#[cfg(feature = "ansi")]
1434+
let f = Format::default().without_time().with_ansi(false);
1435+
#[cfg(not(feature = "ansi"))]
1436+
let f = Format::default().without_time();
1437+
Collector::builder()
1438+
.event_format(f)
1439+
.with_writer(make_writer)
1440+
.with_max_level(Level::TRACE)
1441+
.finish()
1442+
};
1443+
let _s = tracing::collect::set_default(c);
1444+
info!("hello");
1445+
info!("world");
1446+
has_lines(&buf, &lines[..]);
1447+
}
1448+
1449+
#[test]
1450+
fn option_none_makewriter() {
1451+
let make_writer = Option::<MockMakeWriter>::None;
1452+
1453+
let c = {
1454+
#[cfg(feature = "ansi")]
1455+
let f = Format::default().without_time().with_ansi(false);
1456+
#[cfg(not(feature = "ansi"))]
1457+
let f = Format::default().without_time();
1458+
Collector::builder()
1459+
.event_format(f)
1460+
.with_writer(make_writer)
1461+
.with_max_level(Level::TRACE)
1462+
.finish()
1463+
};
1464+
let _s = tracing::collect::set_default(c);
1465+
info!("hello");
1466+
info!("world");
1467+
}
1468+
1469+
#[test]
1470+
fn multi_tee() {
1471+
let always_buf = Arc::new(Mutex::new(Vec::new()));
1472+
let some_buf = Arc::new(Mutex::new(Vec::new()));
1473+
1474+
let always_make_writer = MockMakeWriter::new(always_buf.clone());
1475+
let some_make_writer = Some(MockMakeWriter::new(some_buf.clone()));
1476+
let none_make_writer = Option::<MockMakeWriter>::None;
1477+
1478+
let make_writer = always_make_writer
1479+
.and(some_make_writer)
1480+
.and(none_make_writer);
1481+
1482+
let lines = &[(Level::INFO, "hello"), (Level::INFO, "world")];
1483+
let c = {
1484+
#[cfg(feature = "ansi")]
1485+
let f = Format::default().without_time().with_ansi(false);
1486+
#[cfg(not(feature = "ansi"))]
1487+
let f = Format::default().without_time();
1488+
Collector::builder()
1489+
.event_format(f)
1490+
.with_writer(make_writer)
1491+
.with_max_level(Level::TRACE)
1492+
.finish()
1493+
};
1494+
let _s = tracing::collect::set_default(c);
1495+
info!("hello");
1496+
info!("world");
1497+
1498+
has_lines(&always_buf, &lines[..]);
1499+
has_lines(&some_buf, &lines[..]);
1500+
}
13941501
}

0 commit comments

Comments
 (0)