Skip to content

Commit 4ac4e8c

Browse files
zicklaghawkw
authored andcommitted
subscriber: change FmtSpan to a combinable bitflag (#1277)
This backports #1277 from `master`. Fixes #1136. Allows arbitrarily combining different FmtSpan events to listen to. Motivation ---------- The idea is to allow any combination of `FmtSpan` options, such as the currently unachievable combination of `FmtSpan::NEW | FmtSpan::CLOSE`. Solution -------- Make `FmtSpan` behave like a bitflag that can be combined using the bitwise or operator ( `|` ) while maintaining backward compatibility by keeping the same names for all existing presets and keeping the implementation details hidden.
1 parent 73b472e commit 4ac4e8c

File tree

3 files changed

+145
-36
lines changed

3 files changed

+145
-36
lines changed

tracing-subscriber/src/fmt/fmt_layer.rs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -259,18 +259,33 @@ where
259259
/// - `FmtSpan::NONE`: No events will be synthesized when spans are
260260
/// created, entered, exited, or closed. Data from spans will still be
261261
/// included as the context for formatted events. This is the default.
262-
/// - `FmtSpan::ACTIVE`: Events will be synthesized when spans are entered
263-
/// or exited.
262+
/// - `FmtSpan::NEW`: An event will be synthesized when spans are created.
263+
/// - `FmtSpan::ENTER`: An event will be synthesized when spans are entered.
264+
/// - `FmtSpan::EXIT`: An event will be synthesized when spans are exited.
264265
/// - `FmtSpan::CLOSE`: An event will be synthesized when a span closes. If
265266
/// [timestamps are enabled][time] for this formatter, the generated
266267
/// event will contain fields with the span's _busy time_ (the total
267268
/// time for which it was entered) and _idle time_ (the total time that
268269
/// the span existed but was not entered).
270+
/// - `FmtSpan::ACTIVE`: Events will be synthesized when spans are entered
271+
/// or exited.
269272
/// - `FmtSpan::FULL`: Events will be synthesized whenever a span is
270273
/// created, entered, exited, or closed. If timestamps are enabled, the
271274
/// close event will contain the span's busy and idle time, as
272275
/// described above.
273276
///
277+
/// The options can be enabled in any combination. For instance, the following
278+
/// will synthesize events whenever spans are created and closed:
279+
///
280+
/// ```rust
281+
/// use tracing_subscriber::fmt;
282+
/// use tracing_subscriber::fmt::format::FmtSpan;
283+
///
284+
/// let subscriber = fmt()
285+
/// .with_span_events(FmtSpan::NEW | FmtSpan::CLOSE)
286+
/// .finish();
287+
/// ```
288+
///
274289
/// Note that the generated events will only be part of the log output by
275290
/// this formatter; they will not be recorded by other `Subscriber`s or by
276291
/// `Layer`s added to this subscriber.
@@ -627,7 +642,7 @@ where
627642
}
628643

629644
fn on_enter(&self, id: &Id, ctx: Context<'_, S>) {
630-
if self.fmt_span.trace_active() || self.fmt_span.trace_close() && self.fmt_span.fmt_timing {
645+
if self.fmt_span.trace_enter() || self.fmt_span.trace_close() && self.fmt_span.fmt_timing {
631646
let span = ctx.span(id).expect("Span not found, this is a bug");
632647
let mut extensions = span.extensions_mut();
633648
if let Some(timings) = extensions.get_mut::<Timings>() {
@@ -636,7 +651,7 @@ where
636651
timings.last = now;
637652
}
638653

639-
if self.fmt_span.trace_active() {
654+
if self.fmt_span.trace_enter() {
640655
with_event_from_span!(id, span, "message" = "enter", |event| {
641656
drop(extensions);
642657
drop(span);
@@ -647,7 +662,7 @@ where
647662
}
648663

649664
fn on_exit(&self, id: &Id, ctx: Context<'_, S>) {
650-
if self.fmt_span.trace_active() || self.fmt_span.trace_close() && self.fmt_span.fmt_timing {
665+
if self.fmt_span.trace_exit() || self.fmt_span.trace_close() && self.fmt_span.fmt_timing {
651666
let span = ctx.span(id).expect("Span not found, this is a bug");
652667
let mut extensions = span.extensions_mut();
653668
if let Some(timings) = extensions.get_mut::<Timings>() {
@@ -656,7 +671,7 @@ where
656671
timings.last = now;
657672
}
658673

659-
if self.fmt_span.trace_active() {
674+
if self.fmt_span.trace_exit() {
660675
with_event_from_span!(id, span, "message" = "exit", |event| {
661676
drop(extensions);
662677
drop(span);

tracing-subscriber/src/fmt/format/mod.rs

Lines changed: 107 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1088,40 +1088,89 @@ impl<'a, F> fmt::Debug for FieldFnVisitor<'a, F> {
10881088
///
10891089
/// See also [`with_span_events`](../struct.SubscriberBuilder.html#method.with_span_events).
10901090
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd)]
1091-
pub struct FmtSpan(FmtSpanInner);
1091+
pub struct FmtSpan(u8);
10921092

10931093
impl FmtSpan {
1094+
/// one event when span is created
1095+
pub const NEW: FmtSpan = FmtSpan(1 << 0);
1096+
/// one event per enter of a span
1097+
pub const ENTER: FmtSpan = FmtSpan(1 << 1);
1098+
/// one event per exit of a span
1099+
pub const EXIT: FmtSpan = FmtSpan(1 << 2);
1100+
/// one event when the span is dropped
1101+
pub const CLOSE: FmtSpan = FmtSpan(1 << 3);
1102+
10941103
/// spans are ignored (this is the default)
1095-
pub const NONE: FmtSpan = FmtSpan(FmtSpanInner::None);
1104+
pub const NONE: FmtSpan = FmtSpan(0);
10961105
/// one event per enter/exit of a span
1097-
pub const ACTIVE: FmtSpan = FmtSpan(FmtSpanInner::Active);
1098-
/// one event when the span is dropped
1099-
pub const CLOSE: FmtSpan = FmtSpan(FmtSpanInner::Close);
1106+
pub const ACTIVE: FmtSpan = FmtSpan(FmtSpan::ENTER.0 | FmtSpan::EXIT.0);
11001107
/// events at all points (new, enter, exit, drop)
1101-
pub const FULL: FmtSpan = FmtSpan(FmtSpanInner::Full);
1108+
pub const FULL: FmtSpan =
1109+
FmtSpan(FmtSpan::NEW.0 | FmtSpan::ENTER.0 | FmtSpan::EXIT.0 | FmtSpan::CLOSE.0);
1110+
1111+
/// Check whether or not a certain flag is set for this [`FmtSpan`]
1112+
fn contains(&self, other: FmtSpan) -> bool {
1113+
self.clone() & other.clone() == other
1114+
}
1115+
}
1116+
1117+
macro_rules! impl_fmt_span_bit_op {
1118+
($trait:ident, $func:ident, $op:tt) => {
1119+
impl std::ops::$trait for FmtSpan {
1120+
type Output = FmtSpan;
1121+
1122+
fn $func(self, rhs: Self) -> Self::Output {
1123+
FmtSpan(self.0 $op rhs.0)
1124+
}
1125+
}
1126+
};
1127+
}
1128+
1129+
macro_rules! impl_fmt_span_bit_assign_op {
1130+
($trait:ident, $func:ident, $op:tt) => {
1131+
impl std::ops::$trait for FmtSpan {
1132+
fn $func(&mut self, rhs: Self) {
1133+
*self = FmtSpan(self.0 $op rhs.0)
1134+
}
1135+
}
1136+
};
11021137
}
11031138

1139+
impl_fmt_span_bit_op!(BitAnd, bitand, &);
1140+
impl_fmt_span_bit_op!(BitOr, bitor, |);
1141+
impl_fmt_span_bit_op!(BitXor, bitxor, ^);
1142+
1143+
impl_fmt_span_bit_assign_op!(BitAndAssign, bitand_assign, &);
1144+
impl_fmt_span_bit_assign_op!(BitOrAssign, bitor_assign, |);
1145+
impl_fmt_span_bit_assign_op!(BitXorAssign, bitxor_assign, ^);
1146+
11041147
impl Debug for FmtSpan {
11051148
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1106-
match self.0 {
1107-
FmtSpanInner::None => f.write_str("FmtSpan::NONE"),
1108-
FmtSpanInner::Active => f.write_str("FmtSpan::ACTIVE"),
1109-
FmtSpanInner::Close => f.write_str("FmtSpan::CLOSE"),
1110-
FmtSpanInner::Full => f.write_str("FmtSpan::FULL"),
1149+
let mut wrote_flag = false;
1150+
let mut write_flags = |flag, flag_str| -> fmt::Result {
1151+
if self.contains(flag) {
1152+
if wrote_flag {
1153+
f.write_str(" | ")?;
1154+
}
1155+
1156+
f.write_str(flag_str)?;
1157+
wrote_flag = true;
1158+
}
1159+
1160+
Ok(())
1161+
};
1162+
1163+
if FmtSpan::NONE | self.clone() == FmtSpan::NONE {
1164+
f.write_str("FmtSpan::NONE")?;
1165+
} else {
1166+
write_flags(FmtSpan::NEW, "FmtSpan::NEW")?;
1167+
write_flags(FmtSpan::ENTER, "FmtSpan::ENTER")?;
1168+
write_flags(FmtSpan::EXIT, "FmtSpan::EXIT")?;
1169+
write_flags(FmtSpan::CLOSE, "FmtSpan::CLOSE")?;
11111170
}
1112-
}
1113-
}
11141171

1115-
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
1116-
enum FmtSpanInner {
1117-
/// spans are ignored (this is the default)
1118-
None,
1119-
/// one event per enter/exit of a span
1120-
Active,
1121-
/// one event when the span is dropped
1122-
Close,
1123-
/// events at all points (new, enter, exit, drop)
1124-
Full,
1172+
Ok(())
1173+
}
11251174
}
11261175

11271176
pub(super) struct FmtSpanConfig {
@@ -1143,13 +1192,16 @@ impl FmtSpanConfig {
11431192
}
11441193
}
11451194
pub(super) fn trace_new(&self) -> bool {
1146-
matches!(self.kind, FmtSpan::FULL)
1195+
self.kind.contains(FmtSpan::NEW)
11471196
}
1148-
pub(super) fn trace_active(&self) -> bool {
1149-
matches!(self.kind, FmtSpan::ACTIVE | FmtSpan::FULL)
1197+
pub(super) fn trace_enter(&self) -> bool {
1198+
self.kind.contains(FmtSpan::ENTER)
1199+
}
1200+
pub(super) fn trace_exit(&self) -> bool {
1201+
self.kind.contains(FmtSpan::EXIT)
11501202
}
11511203
pub(super) fn trace_close(&self) -> bool {
1152-
matches!(self.kind, FmtSpan::CLOSE | FmtSpan::FULL)
1204+
self.kind.contains(FmtSpan::CLOSE)
11531205
}
11541206
}
11551207

@@ -1193,7 +1245,7 @@ pub(super) mod test {
11931245
use lazy_static::lazy_static;
11941246
use tracing::{self, subscriber::with_default};
11951247

1196-
use super::TimingDisplay;
1248+
use super::{FmtSpan, TimingDisplay};
11971249
use std::{fmt, sync::Mutex};
11981250

11991251
pub(crate) struct MockTime;
@@ -1380,4 +1432,31 @@ pub(super) mod test {
13801432
assert_eq!(fmt(123456789012), "123s");
13811433
assert_eq!(fmt(1234567890123), "1235s");
13821434
}
1435+
1436+
#[test]
1437+
fn fmt_span_combinations() {
1438+
let f = FmtSpan::NONE;
1439+
assert_eq!(f.contains(FmtSpan::NEW), false);
1440+
assert_eq!(f.contains(FmtSpan::ENTER), false);
1441+
assert_eq!(f.contains(FmtSpan::EXIT), false);
1442+
assert_eq!(f.contains(FmtSpan::CLOSE), false);
1443+
1444+
let f = FmtSpan::ACTIVE;
1445+
assert_eq!(f.contains(FmtSpan::NEW), false);
1446+
assert_eq!(f.contains(FmtSpan::ENTER), true);
1447+
assert_eq!(f.contains(FmtSpan::EXIT), true);
1448+
assert_eq!(f.contains(FmtSpan::CLOSE), false);
1449+
1450+
let f = FmtSpan::FULL;
1451+
assert_eq!(f.contains(FmtSpan::NEW), true);
1452+
assert_eq!(f.contains(FmtSpan::ENTER), true);
1453+
assert_eq!(f.contains(FmtSpan::EXIT), true);
1454+
assert_eq!(f.contains(FmtSpan::CLOSE), true);
1455+
1456+
let f = FmtSpan::NEW | FmtSpan::CLOSE;
1457+
assert_eq!(f.contains(FmtSpan::NEW), true);
1458+
assert_eq!(f.contains(FmtSpan::ENTER), false);
1459+
assert_eq!(f.contains(FmtSpan::EXIT), false);
1460+
assert_eq!(f.contains(FmtSpan::CLOSE), true);
1461+
}
13831462
}

tracing-subscriber/src/fmt/mod.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -623,18 +623,33 @@ where
623623
/// - `FmtSpan::NONE`: No events will be synthesized when spans are
624624
/// created, entered, exited, or closed. Data from spans will still be
625625
/// included as the context for formatted events. This is the default.
626-
/// - `FmtSpan::ACTIVE`: Events will be synthesized when spans are entered
627-
/// or exited.
626+
/// - `FmtSpan::NEW`: An event will be synthesized when spans are created.
627+
/// - `FmtSpan::ENTER`: An event will be synthesized when spans are entered.
628+
/// - `FmtSpan::EXIT`: An event will be synthesized when spans are exited.
628629
/// - `FmtSpan::CLOSE`: An event will be synthesized when a span closes. If
629630
/// [timestamps are enabled][time] for this formatter, the generated
630631
/// event will contain fields with the span's _busy time_ (the total
631632
/// time for which it was entered) and _idle time_ (the total time that
632633
/// the span existed but was not entered).
634+
/// - `FmtSpan::ACTIVE`: An event will be synthesized when spans are entered
635+
/// or exited.
633636
/// - `FmtSpan::FULL`: Events will be synthesized whenever a span is
634637
/// created, entered, exited, or closed. If timestamps are enabled, the
635638
/// close event will contain the span's busy and idle time, as
636639
/// described above.
637640
///
641+
/// The options can be enabled in any combination. For instance, the following
642+
/// will synthesize events whenever spans are created and closed:
643+
///
644+
/// ```rust
645+
/// use tracing_subscriber::fmt::format::FmtSpan;
646+
/// use tracing_subscriber::fmt;
647+
///
648+
/// let subscriber = fmt()
649+
/// .with_span_events(FmtSpan::NEW | FmtSpan::CLOSE)
650+
/// .finish();
651+
/// ```
652+
///
638653
/// Note that the generated events will only be part of the log output by
639654
/// this formatter; they will not be recorded by other `Subscriber`s or by
640655
/// `Layer`s added to this subscriber.

0 commit comments

Comments
 (0)