Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

subscriber: make Compact formatter not be useless #1069

Merged
merged 4 commits into from
Oct 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
22 changes: 22 additions & 0 deletions examples/examples/fmt-compact.rs
@@ -0,0 +1,22 @@
#![deny(rust_2018_idioms)]
#[path = "fmt/yak_shave.rs"]
mod yak_shave;

fn main() {
tracing_subscriber::fmt()
.compact()
// enable everything
.with_max_level(tracing::Level::TRACE)
// sets this to be the default, global collector for this application.
.init();

let number_of_yaks = 3;
// this creates a new event, outside of any spans.
tracing::info!(number_of_yaks, "preparing to shave yaks");

let number_shaved = yak_shave::shave_all(number_of_yaks);
tracing::info!(
all_yaks_shaved = number_shaved == number_of_yaks,
"yak shaving completed"
);
}
269 changes: 115 additions & 154 deletions tracing-subscriber/src/fmt/format/mod.rs
Expand Up @@ -10,6 +10,7 @@ use crate::{
use std::{
fmt::{self, Write},
iter,
marker::PhantomData,
};
use tracing_core::{
field::{self, Field, Visit},
Expand Down Expand Up @@ -213,7 +214,7 @@ impl<F, T> Format<F, T> {
format: Compact,
timer: self.timer,
ansi: self.ansi,
display_target: self.display_target,
display_target: false,
display_level: self.display_level,
display_thread_id: self.display_thread_id,
display_thread_name: self.display_thread_name,
Expand Down Expand Up @@ -347,6 +348,27 @@ impl<F, T> Format<F, T> {
..self
}
}

fn format_level(&self, level: Level, writer: &mut dyn fmt::Write) -> fmt::Result
where
F: LevelNames,
{
if self.display_level {
let fmt_level = {
#[cfg(feature = "ansi")]
{
F::format_level(level, self.ansi)
}
#[cfg(not(feature = "ansi"))]
{
F::format_level(level)
}
};
return write!(writer, "{} ", fmt_level);
}

Ok(())
}
}

#[cfg(feature = "json")]
Expand Down Expand Up @@ -413,19 +435,7 @@ where
#[cfg(not(feature = "ansi"))]
time::write(&self.timer, writer)?;

if self.display_level {
let fmt_level = {
#[cfg(feature = "ansi")]
{
FmtLevel::new(meta.level(), self.ansi)
}
#[cfg(not(feature = "ansi"))]
{
FmtLevel::new(meta.level())
}
};
write!(writer, "{} ", fmt_level)?;
}
self.format_level(*meta.level(), writer)?;

if self.display_thread_name {
let current_thread = std::thread::current();
Expand Down Expand Up @@ -488,19 +498,7 @@ where
#[cfg(not(feature = "ansi"))]
time::write(&self.timer, writer)?;

if self.display_level {
let fmt_level = {
#[cfg(feature = "ansi")]
{
FmtLevel::new(meta.level(), self.ansi)
}
#[cfg(not(feature = "ansi"))]
{
FmtLevel::new(meta.level())
}
};
write!(writer, "{} ", fmt_level)?;
}
self.format_level(*meta.level(), writer)?;

if self.display_thread_name {
let current_thread = std::thread::current();
Expand All @@ -520,27 +518,46 @@ where
write!(writer, "{:0>2?} ", std::thread::current().id())?;
}

let fmt_ctx = {
#[cfg(feature = "ansi")]
{
FmtCtx::new(&ctx, event.parent(), self.ansi)
}
#[cfg(not(feature = "ansi"))]
{
FmtCtx::new(&ctx, event.parent())
}
};
write!(writer, "{}", fmt_ctx)?;
if self.display_target {
write!(writer, "{}:", meta.target())?;
let target = meta.target();
#[cfg(feature = "ansi")]
let target = if self.ansi {
Style::new().bold().paint(target)
} else {
Style::new().paint(target)
};

write!(writer, "{}:", target)?;
}

ctx.format_fields(writer, event)?;
let span = ctx.ctx.current_span();
if let Some(id) = span.id() {
if let Some(span) = ctx.ctx.metadata(id) {
write!(writer, "{}", span.fields()).unwrap_or(());

let span = event
.parent()
.and_then(|id| ctx.ctx.span(&id))
.or_else(|| ctx.ctx.lookup_current());

let scope = span.into_iter().flat_map(|span| {
let parents = span.parents();
iter::once(span).chain(parents)
});
#[cfg(feature = "ansi")]
let dimmed = if self.ansi {
Style::new().dimmed()
} else {
Style::new()
};
for span in scope {
let exts = span.extensions();
if let Some(fields) = exts.get::<FormattedFields<N>>() {
if !fields.is_empty() {
#[cfg(feature = "ansi")]
let fields = dimmed.paint(fields.as_str());
write!(writer, " {}", fields)?;
}
}
}

writeln!(writer)
}
}
Expand Down Expand Up @@ -693,74 +710,6 @@ impl<'a> fmt::Debug for DefaultVisitor<'a> {
}
}

struct FmtCtx<'a, S, N> {
ctx: &'a FmtContext<'a, S, N>,
span: Option<&'a span::Id>,
#[cfg(feature = "ansi")]
ansi: bool,
}

impl<'a, S, N: 'a> FmtCtx<'a, S, N>
where
S: Collect + for<'lookup> LookupSpan<'lookup>,
N: for<'writer> FormatFields<'writer> + 'static,
{
#[cfg(feature = "ansi")]
pub(crate) fn new(
ctx: &'a FmtContext<'_, S, N>,
span: Option<&'a span::Id>,
ansi: bool,
) -> Self {
Self { ctx, ansi, span }
}

#[cfg(not(feature = "ansi"))]
pub(crate) fn new(ctx: &'a FmtContext<'_, S, N>, span: Option<&'a span::Id>) -> Self {
Self { ctx, span }
}

fn bold(&self) -> Style {
#[cfg(feature = "ansi")]
{
if self.ansi {
return Style::new().bold();
}
}

Style::new()
}
}

impl<'a, S, N: 'a> fmt::Display for FmtCtx<'a, S, N>
where
S: Collect + for<'lookup> LookupSpan<'lookup>,
N: for<'writer> FormatFields<'writer> + 'static,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let bold = self.bold();
let mut seen = false;

let span = self
.span
.and_then(|id| self.ctx.ctx.span(&id))
.or_else(|| self.ctx.ctx.lookup_current());

let scope = span
.into_iter()
.flat_map(|span| span.from_root().chain(iter::once(span)));

for span in scope {
seen = true;
write!(f, "{}:", bold.paint(span.metadata().name()))?;
}

if seen {
f.write_char(' ')?;
}
Ok(())
}
}

struct FullCtx<'a, S, N>
where
S: Collect + for<'lookup> LookupSpan<'lookup>,
Expand Down Expand Up @@ -898,63 +847,75 @@ impl<'a> fmt::Display for FmtThreadName<'a> {
}
}

struct FmtLevel<'a> {
level: &'a Level,
#[cfg(feature = "ansi")]
ansi: bool,
}
trait LevelNames {
const TRACE_STR: &'static str;
const DEBUG_STR: &'static str;
const INFO_STR: &'static str;
const WARN_STR: &'static str;
const ERROR_STR: &'static str;

impl<'a> FmtLevel<'a> {
#[cfg(feature = "ansi")]
pub(crate) fn new(level: &'a Level, ansi: bool) -> Self {
Self { level, ansi }
fn format_level(level: Level, ansi: bool) -> FmtLevel<Self> {
FmtLevel {
level,
ansi,
_f: PhantomData,
}
}

#[cfg(not(feature = "ansi"))]
pub(crate) fn new(level: &'a Level) -> Self {
Self { level }
fn format_level(level: Level) -> FmtLevel<Self> {
FmtLevel {
level,
_f: PhantomData,
}
}
}

const TRACE_STR: &str = "TRACE";
const DEBUG_STR: &str = "DEBUG";
const INFO_STR: &str = " INFO";
const WARN_STR: &str = " WARN";
const ERROR_STR: &str = "ERROR";
impl LevelNames for Full {
const TRACE_STR: &'static str = "TRACE";
const DEBUG_STR: &'static str = "DEBUG";
const INFO_STR: &'static str = " INFO";
const WARN_STR: &'static str = " WARN";
const ERROR_STR: &'static str = "ERROR";
}
impl LevelNames for Compact {
const TRACE_STR: &'static str = "T";
const DEBUG_STR: &'static str = "D";
const INFO_STR: &'static str = "I";
const WARN_STR: &'static str = "W";
const ERROR_STR: &'static str = "!";
}

#[cfg(not(feature = "ansi"))]
impl<'a> fmt::Display for FmtLevel<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self.level {
Level::TRACE => f.pad(TRACE_STR),
Level::DEBUG => f.pad(DEBUG_STR),
Level::INFO => f.pad(INFO_STR),
Level::WARN => f.pad(WARN_STR),
Level::ERROR => f.pad(ERROR_STR),
}
}
struct FmtLevel<F: ?Sized> {
level: Level,
#[cfg(feature = "ansi")]
ansi: bool,
_f: PhantomData<fn(F)>,
}

#[cfg(feature = "ansi")]
impl<'a> fmt::Display for FmtLevel<'a> {
impl<'a, F: LevelNames> fmt::Display for FmtLevel<F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.ansi {
match *self.level {
Level::TRACE => write!(f, "{}", Colour::Purple.paint(TRACE_STR)),
Level::DEBUG => write!(f, "{}", Colour::Blue.paint(DEBUG_STR)),
Level::INFO => write!(f, "{}", Colour::Green.paint(INFO_STR)),
Level::WARN => write!(f, "{}", Colour::Yellow.paint(WARN_STR)),
Level::ERROR => write!(f, "{}", Colour::Red.paint(ERROR_STR)),
}
} else {
match *self.level {
Level::TRACE => f.pad(TRACE_STR),
Level::DEBUG => f.pad(DEBUG_STR),
Level::INFO => f.pad(INFO_STR),
Level::WARN => f.pad(WARN_STR),
Level::ERROR => f.pad(ERROR_STR),
#[cfg(feature = "ansi")]
{
if self.ansi {
return match self.level {
Level::TRACE => write!(f, "{}", Colour::Purple.paint(F::TRACE_STR)),
Level::DEBUG => write!(f, "{}", Colour::Blue.paint(F::DEBUG_STR)),
Level::INFO => write!(f, "{}", Colour::Green.paint(F::INFO_STR)),
Level::WARN => write!(f, "{}", Colour::Yellow.paint(F::WARN_STR)),
Level::ERROR => write!(f, "{}", Colour::Red.paint(F::ERROR_STR)),
};
}
}

match self.level {
Level::TRACE => f.pad(F::TRACE_STR),
Level::DEBUG => f.pad(F::DEBUG_STR),
Level::INFO => f.pad(F::INFO_STR),
Level::WARN => f.pad(F::WARN_STR),
Level::ERROR => f.pad(F::ERROR_STR),
}
}
}

Expand Down
26 changes: 26 additions & 0 deletions tracing-subscriber/src/fmt/mod.rs
Expand Up @@ -91,6 +91,32 @@
//! <font color="#AAAAAA">Oct 24 12:55:47.815 </font><font color="#4E9A06"> INFO</font> fmt: yak shaving completed all_yaks_shaved=false
//! </pre>
//!
//! * [`format::Compact`]: A variant of the default formatter, optimized for
//! short line lengths. Fields from the current span context are appended to
//! the fields of the formatted event, and span names are not shown; the
//! verbosity level is abbreviated to a single character.
//!
//! For example:
//! <pre><font color="#4E9A06"><b> Finished</b></font> dev [unoptimized + debuginfo] target(s) in 1.51s
//! <font color="#4E9A06"><b> Running</b></font> `target/debug/examples/fmt-compact`
//! <font color="#AAAAAA">Oct 24 13:40:45.682 </font><font color="#4E9A06">I</font> preparing to shave yaks number_of_yaks=3
//! <font color="#AAAAAA">Oct 24 13:40:45.682 </font><font color="#4E9A06">I</font> shaving yaks yaks=3
//! <font color="#AAAAAA">Oct 24 13:40:45.683 </font><font color="#75507B">T</font> hello! I&apos;m gonna shave a yak excitement=&quot;yay!&quot; yak=1 yaks=3
//! <font color="#AAAAAA">Oct 24 13:40:45.683 </font><font color="#75507B">T</font> yak shaved successfully yak=1 yaks=3
//! <font color="#AAAAAA">Oct 24 13:40:45.683 </font><font color="#3465A4">D</font> yak=1 shaved=true yaks=3
//! <font color="#AAAAAA">Oct 24 13:40:45.683 </font><font color="#75507B">T</font> yaks_shaved=1 yaks=3
//! <font color="#AAAAAA">Oct 24 13:40:45.683 </font><font color="#75507B">T</font> hello! I&apos;m gonna shave a yak excitement=&quot;yay!&quot; yak=2 yaks=3
//! <font color="#AAAAAA">Oct 24 13:40:45.683 </font><font color="#75507B">T</font> yak shaved successfully yak=2 yaks=3
//! <font color="#AAAAAA">Oct 24 13:40:45.683 </font><font color="#3465A4">D</font> yak=2 shaved=true yaks=3
//! <font color="#AAAAAA">Oct 24 13:40:45.683 </font><font color="#75507B">T</font> yaks_shaved=2 yaks=3
//! <font color="#AAAAAA">Oct 24 13:40:45.683 </font><font color="#75507B">T</font> hello! I&apos;m gonna shave a yak excitement=&quot;yay!&quot; yak=3 yaks=3
//! <font color="#AAAAAA">Oct 24 13:40:45.683 </font><font color="#C4A000">W</font> could not locate yak yak=3 yaks=3
//! <font color="#AAAAAA">Oct 24 13:40:45.683 </font><font color="#3465A4">D</font> yak=3 shaved=false yaks=3
//! <font color="#AAAAAA">Oct 24 13:40:45.683 </font><font color="#CC0000">!</font> failed to shave yak yak=3 error=missing yak yaks=3
//! <font color="#AAAAAA">Oct 24 13:40:45.683 </font><font color="#75507B">T</font> yaks_shaved=2 yaks=3
//! <font color="#AAAAAA">Oct 24 13:40:45.683 </font><font color="#4E9A06">I</font> yak shaving completed all_yaks_shaved=false
//! </pre>
//!
//! * [`format::Pretty`]: Emits excessively pretty, multi-line logs, optimized
//! for human readability. This is primarily intended to be used in local
//! development and debugging, or for command-line applications, where
Expand Down