mirror of
https://github.com/tokio-rs/tracing.git
synced 2025-10-02 07:20:35 +00:00
This backports PR #1067 to v0.1.x. Since this has already been approved on master, I'm just going to go ahead and merge it when CI passes. ## Motivation Currently, the `tracing_subscriber::fmt` module contains only single-line event formatters. Some users have requested a human-readable, pretty-printing event formatter optimized for aesthetics. ## Solution This branch adds a new `Pretty` formatter which uses an _excessively_ pretty output format. It's neither compact, single-line oriented, nor easily machine-readable, but it looks _quite_ nice, in my opinion. This is well suited for local development or potentially for user-facing logs in a CLI application. Additionally, I tried to improve the docs for the different formatters currently provided, including example output. Check out [the Netlify preview][1]! [1]: https://deploy-preview-1067--tracing-rs.netlify.app/tracing_subscriber/fmt/index.html#formatters Signed-off-by: Eliza Weisman <eliza@buoyant.io>
This commit is contained in:
parent
3bc2fd35e6
commit
8bdc6c367d
21
examples/examples/fmt-json.rs
Normal file
21
examples/examples/fmt-json.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#![deny(rust_2018_idioms)]
|
||||||
|
#[path = "fmt/yak_shave.rs"]
|
||||||
|
mod yak_shave;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
tracing_subscriber::fmt()
|
||||||
|
.json()
|
||||||
|
.with_max_level(tracing::Level::TRACE)
|
||||||
|
.with_current_span(false)
|
||||||
|
.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"
|
||||||
|
);
|
||||||
|
}
|
23
examples/examples/fmt-pretty.rs
Normal file
23
examples/examples/fmt-pretty.rs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#![deny(rust_2018_idioms)]
|
||||||
|
#[path = "fmt/yak_shave.rs"]
|
||||||
|
mod yak_shave;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
tracing_subscriber::fmt()
|
||||||
|
.pretty()
|
||||||
|
.with_thread_names(true)
|
||||||
|
// 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"
|
||||||
|
);
|
||||||
|
}
|
@ -1,23 +1,20 @@
|
|||||||
#![deny(rust_2018_idioms)]
|
#![deny(rust_2018_idioms)]
|
||||||
use tracing::{info, Level};
|
|
||||||
|
|
||||||
#[path = "fmt/yak_shave.rs"]
|
#[path = "fmt/yak_shave.rs"]
|
||||||
mod yak_shave;
|
mod yak_shave;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
tracing_subscriber::fmt()
|
tracing_subscriber::fmt()
|
||||||
// all spans/events with a level higher than DEBUG (e.g, info, warn, etc.)
|
// enable everything
|
||||||
// will be written to stdout.
|
.with_max_level(tracing::Level::TRACE)
|
||||||
.with_max_level(Level::DEBUG)
|
// sets this to be the default, global collector for this application.
|
||||||
// sets this to be the default, global subscriber for this application.
|
|
||||||
.init();
|
.init();
|
||||||
|
|
||||||
let number_of_yaks = 3;
|
let number_of_yaks = 3;
|
||||||
// this creates a new event, outside of any spans.
|
// this creates a new event, outside of any spans.
|
||||||
info!(number_of_yaks, "preparing to shave yaks");
|
tracing::info!(number_of_yaks, "preparing to shave yaks");
|
||||||
|
|
||||||
let number_shaved = yak_shave::shave_all(number_of_yaks);
|
let number_shaved = yak_shave::shave_all(number_of_yaks);
|
||||||
info!(
|
tracing::info!(
|
||||||
all_yaks_shaved = number_shaved == number_of_yaks,
|
all_yaks_shaved = number_shaved == number_of_yaks,
|
||||||
"yak shaving completed."
|
"yak shaving completed."
|
||||||
);
|
);
|
||||||
|
@ -1,38 +1,38 @@
|
|||||||
use std::{error::Error, io};
|
use std::{error::Error, io};
|
||||||
use tracing::{debug, error, info, span, warn, Level};
|
use tracing::{debug, error, info, span, trace, warn, Level};
|
||||||
|
|
||||||
// the `#[tracing::instrument]` attribute creates and enters a span
|
// the `#[tracing::instrument]` attribute creates and enters a span
|
||||||
// every time the instrumented function is called. The span is named after the
|
// every time the instrumented function is called. The span is named after the
|
||||||
// the function or method. Paramaters passed to the function are recorded as fields.
|
// the function or method. Paramaters passed to the function are recorded as fields.
|
||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
pub fn shave(yak: usize) -> Result<(), Box<dyn Error + 'static>> {
|
pub fn shave(yak: usize) -> Result<(), Box<dyn Error + 'static>> {
|
||||||
// this creates an event at the DEBUG log level with two fields:
|
// this creates an event at the TRACE log level with two fields:
|
||||||
// - `excitement`, with the key "excitement" and the value "yay!"
|
// - `excitement`, with the key "excitement" and the value "yay!"
|
||||||
// - `message`, with the key "message" and the value "hello! I'm gonna shave a yak."
|
// - `message`, with the key "message" and the value "hello! I'm gonna shave a yak."
|
||||||
//
|
//
|
||||||
// unlike other fields, `message`'s shorthand initialization is just the string itself.
|
// unlike other fields, `message`'s shorthand initialization is just the string itself.
|
||||||
debug!(excitement = "yay!", "hello! I'm gonna shave a yak.");
|
trace!(excitement = "yay!", "hello! I'm gonna shave a yak");
|
||||||
if yak == 3 {
|
if yak == 3 {
|
||||||
warn!("could not locate yak!");
|
warn!("could not locate yak");
|
||||||
// note that this is intended to demonstrate `tracing`'s features, not idiomatic
|
// note that this is intended to demonstrate `tracing`'s features, not idiomatic
|
||||||
// error handling! in a library or application, you should consider returning
|
// error handling! in a library or application, you should consider returning
|
||||||
// a dedicated `YakError`. libraries like snafu or thiserror make this easy.
|
// a dedicated `YakError`. libraries like snafu or thiserror make this easy.
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "shaving yak failed!").into());
|
return Err(io::Error::new(io::ErrorKind::Other, "missing yak").into());
|
||||||
} else {
|
} else {
|
||||||
debug!("yak shaved successfully");
|
trace!("yak shaved successfully");
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn shave_all(yaks: usize) -> usize {
|
pub fn shave_all(yaks: usize) -> usize {
|
||||||
// Constructs a new span named "shaving_yaks" at the TRACE level,
|
// Constructs a new span named "shaving_yaks" at the INFO level,
|
||||||
// and a field whose key is "yaks". This is equivalent to writing:
|
// and a field whose key is "yaks". This is equivalent to writing:
|
||||||
//
|
//
|
||||||
// let span = span!(Level::TRACE, "shaving_yaks", yaks = yaks);
|
// let span = span!(Level::INFO, "shaving_yaks", yaks = yaks);
|
||||||
//
|
//
|
||||||
// local variables (`yaks`) can be used as field values
|
// local variables (`yaks`) can be used as field values
|
||||||
// without an assignment, similar to struct initializers.
|
// without an assignment, similar to struct initializers.
|
||||||
let span = span!(Level::TRACE, "shaving_yaks", yaks);
|
let span = span!(Level::INFO, "shaving_yaks", yaks);
|
||||||
let _enter = span.enter();
|
let _enter = span.enter();
|
||||||
|
|
||||||
info!("shaving yaks");
|
info!("shaving yaks");
|
||||||
@ -40,16 +40,16 @@ pub fn shave_all(yaks: usize) -> usize {
|
|||||||
let mut yaks_shaved = 0;
|
let mut yaks_shaved = 0;
|
||||||
for yak in 1..=yaks {
|
for yak in 1..=yaks {
|
||||||
let res = shave(yak);
|
let res = shave(yak);
|
||||||
debug!(yak, shaved = res.is_ok());
|
debug!(target: "yak_events", yak, shaved = res.is_ok());
|
||||||
|
|
||||||
if let Err(ref error) = res {
|
if let Err(ref error) = res {
|
||||||
// Like spans, events can also use the field initialization shorthand.
|
// Like spans, events can also use the field initialization shorthand.
|
||||||
// In this instance, `yak` is the field being initalized.
|
// In this instance, `yak` is the field being initalized.
|
||||||
error!(yak, error = error.as_ref(), "failed to shave yak!");
|
error!(yak, error = error.as_ref(), "failed to shave yak");
|
||||||
} else {
|
} else {
|
||||||
yaks_shaved += 1;
|
yaks_shaved += 1;
|
||||||
}
|
}
|
||||||
debug!(yaks_shaved);
|
trace!(yaks_shaved);
|
||||||
}
|
}
|
||||||
|
|
||||||
yaks_shaved
|
yaks_shaved
|
||||||
|
@ -367,6 +367,19 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the layer being built to use an [excessively pretty, human-readable formatter](crate::fmt::format::Pretty).
|
||||||
|
#[cfg(feature = "ansi")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "ansi")))]
|
||||||
|
pub fn pretty(self) -> Layer<S, format::Pretty, format::Format<format::Pretty, T>, W> {
|
||||||
|
Layer {
|
||||||
|
fmt_event: self.fmt_event.pretty(),
|
||||||
|
fmt_fields: format::Pretty::default(),
|
||||||
|
fmt_span: self.fmt_span,
|
||||||
|
make_writer: self.make_writer,
|
||||||
|
_inner: self._inner,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Sets the layer being built to use a [JSON formatter](../fmt/format/struct.Json.html).
|
/// Sets the layer being built to use a [JSON formatter](../fmt/format/struct.Json.html).
|
||||||
///
|
///
|
||||||
/// The full format includes fields from all entered spans.
|
/// The full format includes fields from all entered spans.
|
||||||
|
@ -24,12 +24,18 @@ use ansi_term::{Colour, Style};
|
|||||||
|
|
||||||
#[cfg(feature = "json")]
|
#[cfg(feature = "json")]
|
||||||
mod json;
|
mod json;
|
||||||
|
|
||||||
use fmt::{Debug, Display};
|
|
||||||
#[cfg(feature = "json")]
|
#[cfg(feature = "json")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "json")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "json")))]
|
||||||
pub use json::*;
|
pub use json::*;
|
||||||
|
|
||||||
|
#[cfg(feature = "ansi")]
|
||||||
|
mod pretty;
|
||||||
|
#[cfg(feature = "ansi")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "ansi")))]
|
||||||
|
pub use pretty::*;
|
||||||
|
|
||||||
|
use fmt::{Debug, Display};
|
||||||
|
|
||||||
/// A type that can format a tracing `Event` for a `fmt::Write`.
|
/// A type that can format a tracing `Event` for a `fmt::Write`.
|
||||||
///
|
///
|
||||||
/// `FormatEvent` is primarily used in the context of [`fmt::Subscriber`] or [`fmt::Layer`]. Each time an event is
|
/// `FormatEvent` is primarily used in the context of [`fmt::Subscriber`] or [`fmt::Layer`]. Each time an event is
|
||||||
@ -214,6 +220,25 @@ impl<F, T> Format<F, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Use an excessively pretty, human-readable output format.
|
||||||
|
///
|
||||||
|
/// See [`Pretty`].
|
||||||
|
///
|
||||||
|
/// Note that this requires the "ansi" feature to be enabled.
|
||||||
|
#[cfg(feature = "ansi")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "ansi")))]
|
||||||
|
pub fn pretty(self) -> Format<Pretty, T> {
|
||||||
|
Format {
|
||||||
|
format: Pretty::default(),
|
||||||
|
timer: self.timer,
|
||||||
|
ansi: self.ansi,
|
||||||
|
display_target: self.display_target,
|
||||||
|
display_level: self.display_level,
|
||||||
|
display_thread_id: self.display_thread_id,
|
||||||
|
display_thread_name: self.display_thread_name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Use the full JSON format.
|
/// Use the full JSON format.
|
||||||
///
|
///
|
||||||
/// The full format includes fields from all entered spans.
|
/// The full format includes fields from all entered spans.
|
||||||
@ -521,6 +546,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
// === impl FormatFields ===
|
// === impl FormatFields ===
|
||||||
|
|
||||||
impl<'writer, M> FormatFields<'writer> for M
|
impl<'writer, M> FormatFields<'writer> for M
|
||||||
where
|
where
|
||||||
M: MakeOutput<&'writer mut dyn fmt::Write, fmt::Result>,
|
M: MakeOutput<&'writer mut dyn fmt::Write, fmt::Result>,
|
||||||
@ -622,10 +648,7 @@ impl<'a> field::Visit for DefaultVisitor<'a> {
|
|||||||
|
|
||||||
fn record_error(&mut self, field: &Field, value: &(dyn std::error::Error + 'static)) {
|
fn record_error(&mut self, field: &Field, value: &(dyn std::error::Error + 'static)) {
|
||||||
if let Some(source) = value.source() {
|
if let Some(source) = value.source() {
|
||||||
self.record_debug(
|
self.record_debug(field, &format_args!("{}, {}: {}", value, field, source))
|
||||||
field,
|
|
||||||
&format_args!("{} {}.source={}", value, field, source),
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
self.record_debug(field, &format_args!("{}", value))
|
self.record_debug(field, &format_args!("{}", value))
|
||||||
}
|
}
|
||||||
|
339
tracing-subscriber/src/fmt/format/pretty.rs
Normal file
339
tracing-subscriber/src/fmt/format/pretty.rs
Normal file
@ -0,0 +1,339 @@
|
|||||||
|
use super::*;
|
||||||
|
use crate::{
|
||||||
|
field::{VisitFmt, VisitOutput},
|
||||||
|
fmt::fmt_layer::{FmtContext, FormattedFields},
|
||||||
|
registry::LookupSpan,
|
||||||
|
};
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
fmt::{self, Write},
|
||||||
|
iter,
|
||||||
|
};
|
||||||
|
use tracing_core::{
|
||||||
|
field::{self, Field},
|
||||||
|
Event, Level, Subscriber,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(feature = "tracing-log")]
|
||||||
|
use tracing_log::NormalizeEvent;
|
||||||
|
|
||||||
|
use ansi_term::{Colour, Style};
|
||||||
|
|
||||||
|
/// An excessively pretty, human-readable event formatter.
|
||||||
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
|
pub struct Pretty {
|
||||||
|
display_location: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The [visitor] produced by [`Pretty`]'s [`MakeVisitor`] implementation.
|
||||||
|
///
|
||||||
|
/// [visitor]: ../../field/trait.Visit.html
|
||||||
|
/// [`DefaultFields`]: struct.DefaultFields.html
|
||||||
|
/// [`MakeVisitor`]: ../../field/trait.MakeVisitor.html
|
||||||
|
pub struct PrettyVisitor<'a> {
|
||||||
|
writer: &'a mut dyn Write,
|
||||||
|
is_empty: bool,
|
||||||
|
style: Style,
|
||||||
|
result: fmt::Result,
|
||||||
|
}
|
||||||
|
|
||||||
|
// === impl Pretty ===
|
||||||
|
|
||||||
|
impl Default for Pretty {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
display_location: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Pretty {
|
||||||
|
fn style_for(level: &Level) -> Style {
|
||||||
|
match *level {
|
||||||
|
Level::TRACE => Style::new().fg(Colour::Purple),
|
||||||
|
Level::DEBUG => Style::new().fg(Colour::Blue),
|
||||||
|
Level::INFO => Style::new().fg(Colour::Green),
|
||||||
|
Level::WARN => Style::new().fg(Colour::Yellow),
|
||||||
|
Level::ERROR => Style::new().fg(Colour::Red),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets whether the event's source code location is displayed.
|
||||||
|
///
|
||||||
|
/// This defaults to `true`.
|
||||||
|
pub fn with_source_location(self, display_location: bool) -> Self {
|
||||||
|
Self {
|
||||||
|
display_location,
|
||||||
|
..self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Format<Pretty, T> {
|
||||||
|
/// Sets whether or not the source code location from which an event
|
||||||
|
/// originated is displayed.
|
||||||
|
///
|
||||||
|
/// This defaults to `true`.
|
||||||
|
pub fn with_source_location(mut self, display_location: bool) -> Self {
|
||||||
|
self.format = self.format.with_source_location(display_location);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C, N, T> FormatEvent<C, N> for Format<Pretty, T>
|
||||||
|
where
|
||||||
|
C: Subscriber + for<'a> LookupSpan<'a>,
|
||||||
|
N: for<'a> FormatFields<'a> + 'static,
|
||||||
|
T: FormatTime,
|
||||||
|
{
|
||||||
|
fn format_event(
|
||||||
|
&self,
|
||||||
|
ctx: &FmtContext<'_, C, N>,
|
||||||
|
writer: &mut dyn fmt::Write,
|
||||||
|
event: &Event<'_>,
|
||||||
|
) -> fmt::Result {
|
||||||
|
#[cfg(feature = "tracing-log")]
|
||||||
|
let normalized_meta = event.normalized_metadata();
|
||||||
|
#[cfg(feature = "tracing-log")]
|
||||||
|
let meta = normalized_meta.as_ref().unwrap_or_else(|| event.metadata());
|
||||||
|
#[cfg(not(feature = "tracing-log"))]
|
||||||
|
let meta = event.metadata();
|
||||||
|
write!(writer, " ")?;
|
||||||
|
time::write(&self.timer, writer, true)?;
|
||||||
|
|
||||||
|
let style = if self.display_level {
|
||||||
|
Pretty::style_for(meta.level())
|
||||||
|
} else {
|
||||||
|
Style::new()
|
||||||
|
};
|
||||||
|
|
||||||
|
if self.display_target {
|
||||||
|
let bold = style.bold();
|
||||||
|
write!(
|
||||||
|
writer,
|
||||||
|
"{}{}{}: ",
|
||||||
|
bold.prefix(),
|
||||||
|
meta.target(),
|
||||||
|
bold.infix(style)
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
let mut v = PrettyVisitor::new(writer, true).with_style(style);
|
||||||
|
event.record(&mut v);
|
||||||
|
v.finish()?;
|
||||||
|
writer.write_char('\n')?;
|
||||||
|
|
||||||
|
let dimmed = Style::new().dimmed().italic();
|
||||||
|
let thread = self.display_thread_name || self.display_thread_id;
|
||||||
|
if let (true, Some(file), Some(line)) =
|
||||||
|
(self.format.display_location, meta.file(), meta.line())
|
||||||
|
{
|
||||||
|
write!(
|
||||||
|
writer,
|
||||||
|
" {} {}:{}{}",
|
||||||
|
dimmed.paint("at"),
|
||||||
|
file,
|
||||||
|
line,
|
||||||
|
dimmed.paint(if thread { " " } else { "\n" })
|
||||||
|
)?;
|
||||||
|
} else if thread {
|
||||||
|
write!(writer, " ")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if thread {
|
||||||
|
write!(writer, "{} ", dimmed.paint("on"))?;
|
||||||
|
let thread = std::thread::current();
|
||||||
|
if self.display_thread_name {
|
||||||
|
if let Some(name) = thread.name() {
|
||||||
|
write!(writer, "{}", name)?;
|
||||||
|
if self.display_thread_id {
|
||||||
|
write!(writer, " ({:?})", thread.id())?;
|
||||||
|
}
|
||||||
|
} else if !self.display_thread_id {
|
||||||
|
write!(writer, " {:?}", thread.id())?;
|
||||||
|
}
|
||||||
|
} else if self.display_thread_id {
|
||||||
|
write!(writer, " {:?}", thread.id())?;
|
||||||
|
}
|
||||||
|
writer.write_char('\n')?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let bold = Style::new().bold();
|
||||||
|
let span = event
|
||||||
|
.parent()
|
||||||
|
.and_then(|id| ctx.span(&id))
|
||||||
|
.or_else(|| ctx.lookup_current());
|
||||||
|
|
||||||
|
let scope = span.into_iter().flat_map(|span| {
|
||||||
|
let parents = span.parents();
|
||||||
|
iter::once(span).chain(parents)
|
||||||
|
});
|
||||||
|
|
||||||
|
for span in scope {
|
||||||
|
let meta = span.metadata();
|
||||||
|
if self.display_target {
|
||||||
|
write!(
|
||||||
|
writer,
|
||||||
|
" {} {}::{}",
|
||||||
|
dimmed.paint("in"),
|
||||||
|
meta.target(),
|
||||||
|
bold.paint(meta.name()),
|
||||||
|
)?;
|
||||||
|
} else {
|
||||||
|
write!(
|
||||||
|
writer,
|
||||||
|
" {} {}",
|
||||||
|
dimmed.paint("in"),
|
||||||
|
bold.paint(meta.name()),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ext = span.extensions();
|
||||||
|
let fields = &ext
|
||||||
|
.get::<FormattedFields<N>>()
|
||||||
|
.expect("Unable to find FormattedFields in extensions; this is a bug");
|
||||||
|
if !fields.is_empty() {
|
||||||
|
write!(writer, " {} {}", dimmed.paint("with"), fields)?;
|
||||||
|
}
|
||||||
|
writer.write_char('\n')?;
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.write_char('\n')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'writer> FormatFields<'writer> for Pretty {
|
||||||
|
fn format_fields<R: RecordFields>(
|
||||||
|
&self,
|
||||||
|
writer: &'writer mut dyn fmt::Write,
|
||||||
|
fields: R,
|
||||||
|
) -> fmt::Result {
|
||||||
|
let mut v = PrettyVisitor::new(writer, true);
|
||||||
|
fields.record(&mut v);
|
||||||
|
v.finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_fields(&self, current: &'writer mut String, fields: &span::Record<'_>) -> fmt::Result {
|
||||||
|
let empty = current.is_empty();
|
||||||
|
let mut v = PrettyVisitor::new(current, empty);
|
||||||
|
fields.record(&mut v);
|
||||||
|
v.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// === impl PrettyVisitor ===
|
||||||
|
|
||||||
|
impl<'a> PrettyVisitor<'a> {
|
||||||
|
/// Returns a new default visitor that formats to the provided `writer`.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// - `writer`: the writer to format to.
|
||||||
|
/// - `is_empty`: whether or not any fields have been previously written to
|
||||||
|
/// that writer.
|
||||||
|
pub fn new(writer: &'a mut dyn Write, is_empty: bool) -> Self {
|
||||||
|
Self {
|
||||||
|
writer,
|
||||||
|
is_empty,
|
||||||
|
style: Style::default(),
|
||||||
|
result: Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn with_style(self, style: Style) -> Self {
|
||||||
|
Self { style, ..self }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn maybe_pad(&mut self) {
|
||||||
|
if self.is_empty {
|
||||||
|
self.is_empty = false;
|
||||||
|
} else {
|
||||||
|
self.result = write!(self.writer, ", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> field::Visit for PrettyVisitor<'a> {
|
||||||
|
fn record_str(&mut self, field: &Field, value: &str) {
|
||||||
|
if self.result.is_err() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if field.name() == "message" {
|
||||||
|
self.record_debug(field, &format_args!("{}", value))
|
||||||
|
} else {
|
||||||
|
self.record_debug(field, &value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn record_error(&mut self, field: &Field, value: &(dyn std::error::Error + 'static)) {
|
||||||
|
if let Some(source) = value.source() {
|
||||||
|
let bold = self.style.bold();
|
||||||
|
self.record_debug(
|
||||||
|
field,
|
||||||
|
&format_args!(
|
||||||
|
"{}, {}{}.source{}: {}",
|
||||||
|
value,
|
||||||
|
bold.prefix(),
|
||||||
|
field,
|
||||||
|
bold.infix(self.style),
|
||||||
|
source,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
self.record_debug(field, &format_args!("{}", value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
|
||||||
|
if self.result.is_err() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let bold = self.style.bold();
|
||||||
|
self.maybe_pad();
|
||||||
|
self.result = match field.name() {
|
||||||
|
"message" => write!(self.writer, "{}{:?}", self.style.prefix(), value,),
|
||||||
|
// Skip fields that are actually log metadata that have already been handled
|
||||||
|
#[cfg(feature = "tracing-log")]
|
||||||
|
name if name.starts_with("log.") => Ok(()),
|
||||||
|
name if name.starts_with("r#") => write!(
|
||||||
|
self.writer,
|
||||||
|
"{}{}{}: {:?}",
|
||||||
|
bold.prefix(),
|
||||||
|
&name[2..],
|
||||||
|
bold.infix(self.style),
|
||||||
|
value
|
||||||
|
),
|
||||||
|
name => write!(
|
||||||
|
self.writer,
|
||||||
|
"{}{}{}: {:?}",
|
||||||
|
bold.prefix(),
|
||||||
|
name,
|
||||||
|
bold.infix(self.style),
|
||||||
|
value
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> VisitOutput<fmt::Result> for PrettyVisitor<'a> {
|
||||||
|
fn finish(self) -> fmt::Result {
|
||||||
|
write!(self.writer, "{}", self.style.suffix())?;
|
||||||
|
self.result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> VisitFmt for PrettyVisitor<'a> {
|
||||||
|
fn writer(&mut self) -> &mut dyn fmt::Write {
|
||||||
|
self.writer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> fmt::Debug for PrettyVisitor<'a> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("PrettyVisitor")
|
||||||
|
.field("writer", &format_args!("<dyn fmt::Write>"))
|
||||||
|
.field("is_empty", &self.is_empty)
|
||||||
|
.field("result", &self.result)
|
||||||
|
.field("style", &self.style)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
@ -27,7 +27,7 @@
|
|||||||
//!
|
//!
|
||||||
//! ## Filtering Events with Environment Variables
|
//! ## Filtering Events with Environment Variables
|
||||||
//!
|
//!
|
||||||
//! The default subscriber installed by `init` enables you to filter events
|
//! The default collector installed by `init` enables you to filter events
|
||||||
//! at runtime using environment variables (using the [`EnvFilter`]).
|
//! at runtime using environment variables (using the [`EnvFilter`]).
|
||||||
//!
|
//!
|
||||||
//! The filter syntax is a superset of the [`env_logger`] syntax.
|
//! The filter syntax is a superset of the [`env_logger`] syntax.
|
||||||
@ -52,12 +52,148 @@
|
|||||||
//! You can create one by calling:
|
//! You can create one by calling:
|
||||||
//!
|
//!
|
||||||
//! ```rust
|
//! ```rust
|
||||||
//! let subscriber = tracing_subscriber::fmt()
|
//! let collector = tracing_subscriber::fmt()
|
||||||
//! // ... add configuration
|
//! // ... add configuration
|
||||||
//! .finish();
|
//! .finish();
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! You can find the configuration methods for [`FmtSubscriber`] in [`fmtBuilder`].
|
//! You can find the configuration methods for [`FmtSubscriber`] in
|
||||||
|
//! [`SubscriberBuilder`].
|
||||||
|
//!
|
||||||
|
//! ### Formatters
|
||||||
|
//!
|
||||||
|
//! The output format used by the layer and subscriber in this module is
|
||||||
|
//! represented by implementing the [`FormatEvent`] trait, and can be
|
||||||
|
//! customized. This module provides a number of formatter implementations:
|
||||||
|
//!
|
||||||
|
//! * [`format::Full`]: The default formatter. This emits human-readable,
|
||||||
|
//! single-line logs for each event that occurs, with the current span context
|
||||||
|
//! displayed before the formatted representation of the event.
|
||||||
|
//!
|
||||||
|
//! For example:
|
||||||
|
//! <pre><font color="#4E9A06"><b> Finished</b></font> dev [unoptimized + debuginfo] target(s) in 1.59s
|
||||||
|
//! <font color="#4E9A06"><b> Running</b></font> `target/debug/examples/fmt`
|
||||||
|
//! <font color="#AAAAAA">Oct 24 12:55:47.814 </font><font color="#4E9A06"> INFO</font> fmt: preparing to shave yaks number_of_yaks=3
|
||||||
|
//! <font color="#AAAAAA">Oct 24 12:55:47.814 </font><font color="#4E9A06"> INFO</font> <b>shaving_yaks{</b>yaks=3<b>}</b>: fmt::yak_shave: shaving yaks
|
||||||
|
//! <font color="#AAAAAA">Oct 24 12:55:47.814 </font><font color="#75507B">TRACE</font> <b>shaving_yaks{</b>yaks=3<b>}</b>:<b>shave{</b>yak=1<b>}</b>: fmt::yak_shave: hello! I'm gonna shave a yak excitement="yay!"
|
||||||
|
//! <font color="#AAAAAA">Oct 24 12:55:47.814 </font><font color="#75507B">TRACE</font> <b>shaving_yaks{</b>yaks=3<b>}</b>:<b>shave{</b>yak=1<b>}</b>: fmt::yak_shave: yak shaved successfully
|
||||||
|
//! <font color="#AAAAAA">Oct 24 12:55:47.814 </font><font color="#3465A4">DEBUG</font> <b>shaving_yaks{</b>yaks=3<b>}</b>: yak_events: yak=1 shaved=true
|
||||||
|
//! <font color="#AAAAAA">Oct 24 12:55:47.814 </font><font color="#75507B">TRACE</font> <b>shaving_yaks{</b>yaks=3<b>}</b>: fmt::yak_shave: yaks_shaved=1
|
||||||
|
//! <font color="#AAAAAA">Oct 24 12:55:47.815 </font><font color="#75507B">TRACE</font> <b>shaving_yaks{</b>yaks=3<b>}</b>:<b>shave{</b>yak=2<b>}</b>: fmt::yak_shave: hello! I'm gonna shave a yak excitement="yay!"
|
||||||
|
//! <font color="#AAAAAA">Oct 24 12:55:47.815 </font><font color="#75507B">TRACE</font> <b>shaving_yaks{</b>yaks=3<b>}</b>:<b>shave{</b>yak=2<b>}</b>: fmt::yak_shave: yak shaved successfully
|
||||||
|
//! <font color="#AAAAAA">Oct 24 12:55:47.815 </font><font color="#3465A4">DEBUG</font> <b>shaving_yaks{</b>yaks=3<b>}</b>: yak_events: yak=2 shaved=true
|
||||||
|
//! <font color="#AAAAAA">Oct 24 12:55:47.815 </font><font color="#75507B">TRACE</font> <b>shaving_yaks{</b>yaks=3<b>}</b>: fmt::yak_shave: yaks_shaved=2
|
||||||
|
//! <font color="#AAAAAA">Oct 24 12:55:47.815 </font><font color="#75507B">TRACE</font> <b>shaving_yaks{</b>yaks=3<b>}</b>:<b>shave{</b>yak=3<b>}</b>: fmt::yak_shave: hello! I'm gonna shave a yak excitement="yay!"
|
||||||
|
//! <font color="#AAAAAA">Oct 24 12:55:47.815 </font><font color="#C4A000"> WARN</font> <b>shaving_yaks{</b>yaks=3<b>}</b>:<b>shave{</b>yak=3<b>}</b>: fmt::yak_shave: could not locate yak
|
||||||
|
//! <font color="#AAAAAA">Oct 24 12:55:47.815 </font><font color="#3465A4">DEBUG</font> <b>shaving_yaks{</b>yaks=3<b>}</b>: yak_events: yak=3 shaved=false
|
||||||
|
//! <font color="#AAAAAA">Oct 24 12:55:47.815 </font><font color="#CC0000">ERROR</font> <b>shaving_yaks{</b>yaks=3<b>}</b>: fmt::yak_shave: failed to shave yak yak=3 error=missing yak
|
||||||
|
//! <font color="#AAAAAA">Oct 24 12:55:47.815 </font><font color="#75507B">TRACE</font> <b>shaving_yaks{</b>yaks=3<b>}</b>: fmt::yak_shave: yaks_shaved=2
|
||||||
|
//! <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::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
|
||||||
|
//! automated analysis and compact storage of logs is less of a priority than
|
||||||
|
//! readability and visual appeal.
|
||||||
|
//!
|
||||||
|
//! For example:
|
||||||
|
//! <pre><font color="#4E9A06"><b> Finished</b></font> dev [unoptimized + debuginfo] target(s) in 1.61s
|
||||||
|
//! <font color="#4E9A06"><b> Running</b></font> `target/debug/examples/fmt-pretty`
|
||||||
|
//! Oct 24 12:57:29.386 <font color="#4E9A06"><b>fmt_pretty</b></font><font color="#4E9A06">: preparing to shave yaks, </font><font color="#4E9A06"><b>number_of_yaks</b></font><font color="#4E9A06">: 3</font>
|
||||||
|
//! <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt-pretty.rs:16<font color="#AAAAAA"><i> on</i></font> main
|
||||||
|
//!
|
||||||
|
//! Oct 24 12:57:29.386 <font color="#4E9A06"><b>fmt_pretty::yak_shave</b></font><font color="#4E9A06">: shaving yaks</font>
|
||||||
|
//! <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:38<font color="#AAAAAA"><i> on</i></font> main
|
||||||
|
//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3
|
||||||
|
//!
|
||||||
|
//! Oct 24 12:57:29.387 <font color="#75507B"><b>fmt_pretty::yak_shave</b></font><font color="#75507B">: hello! I'm gonna shave a yak, </font><font color="#75507B"><b>excitement</b></font><font color="#75507B">: "yay!"</font>
|
||||||
|
//! <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:14<font color="#AAAAAA"><i> on</i></font> main
|
||||||
|
//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shave</b> <font color="#AAAAAA"><i>with</i></font> <b>yak</b>: 1
|
||||||
|
//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3
|
||||||
|
//!
|
||||||
|
//! Oct 24 12:57:29.387 <font color="#75507B"><b>fmt_pretty::yak_shave</b></font><font color="#75507B">: yak shaved successfully</font>
|
||||||
|
//! <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:22<font color="#AAAAAA"><i> on</i></font> main
|
||||||
|
//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shave</b> <font color="#AAAAAA"><i>with</i></font> <b>yak</b>: 1
|
||||||
|
//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3
|
||||||
|
//!
|
||||||
|
//! Oct 24 12:57:29.387 <font color="#3465A4"><b>yak_events</b></font><font color="#3465A4">: </font><font color="#3465A4"><b>yak</b></font><font color="#3465A4">: 1, </font><font color="#3465A4"><b>shaved</b></font><font color="#3465A4">: true</font>
|
||||||
|
//! <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:43<font color="#AAAAAA"><i> on</i></font> main
|
||||||
|
//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3
|
||||||
|
//!
|
||||||
|
//! Oct 24 12:57:29.387 <font color="#75507B"><b>fmt_pretty::yak_shave</b></font><font color="#75507B">: </font><font color="#75507B"><b>yaks_shaved</b></font><font color="#75507B">: 1</font>
|
||||||
|
//! <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:52<font color="#AAAAAA"><i> on</i></font> main
|
||||||
|
//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3
|
||||||
|
//!
|
||||||
|
//! Oct 24 12:57:29.387 <font color="#75507B"><b>fmt_pretty::yak_shave</b></font><font color="#75507B">: hello! I'm gonna shave a yak, </font><font color="#75507B"><b>excitement</b></font><font color="#75507B">: "yay!"</font>
|
||||||
|
//! <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:14<font color="#AAAAAA"><i> on</i></font> main
|
||||||
|
//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shave</b> <font color="#AAAAAA"><i>with</i></font> <b>yak</b>: 2
|
||||||
|
//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3
|
||||||
|
//!
|
||||||
|
//! Oct 24 12:57:29.387 <font color="#75507B"><b>fmt_pretty::yak_shave</b></font><font color="#75507B">: yak shaved successfully</font>
|
||||||
|
//! <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:22<font color="#AAAAAA"><i> on</i></font> main
|
||||||
|
//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shave</b> <font color="#AAAAAA"><i>with</i></font> <b>yak</b>: 2
|
||||||
|
//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3
|
||||||
|
//!
|
||||||
|
//! Oct 24 12:57:29.387 <font color="#3465A4"><b>yak_events</b></font><font color="#3465A4">: </font><font color="#3465A4"><b>yak</b></font><font color="#3465A4">: 2, </font><font color="#3465A4"><b>shaved</b></font><font color="#3465A4">: true</font>
|
||||||
|
//! <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:43<font color="#AAAAAA"><i> on</i></font> main
|
||||||
|
//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3
|
||||||
|
//!
|
||||||
|
//! Oct 24 12:57:29.387 <font color="#75507B"><b>fmt_pretty::yak_shave</b></font><font color="#75507B">: </font><font color="#75507B"><b>yaks_shaved</b></font><font color="#75507B">: 2</font>
|
||||||
|
//! <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:52<font color="#AAAAAA"><i> on</i></font> main
|
||||||
|
//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3
|
||||||
|
//!
|
||||||
|
//! Oct 24 12:57:29.387 <font color="#75507B"><b>fmt_pretty::yak_shave</b></font><font color="#75507B">: hello! I'm gonna shave a yak, </font><font color="#75507B"><b>excitement</b></font><font color="#75507B">: "yay!"</font>
|
||||||
|
//! <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:14<font color="#AAAAAA"><i> on</i></font> main
|
||||||
|
//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shave</b> <font color="#AAAAAA"><i>with</i></font> <b>yak</b>: 3
|
||||||
|
//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3
|
||||||
|
//!
|
||||||
|
//! Oct 24 12:57:29.387 <font color="#C4A000"><b>fmt_pretty::yak_shave</b></font><font color="#C4A000">: could not locate yak</font>
|
||||||
|
//! <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:16<font color="#AAAAAA"><i> on</i></font> main
|
||||||
|
//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shave</b> <font color="#AAAAAA"><i>with</i></font> <b>yak</b>: 3
|
||||||
|
//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3
|
||||||
|
//!
|
||||||
|
//! Oct 24 12:57:29.387 <font color="#3465A4"><b>yak_events</b></font><font color="#3465A4">: </font><font color="#3465A4"><b>yak</b></font><font color="#3465A4">: 3, </font><font color="#3465A4"><b>shaved</b></font><font color="#3465A4">: false</font>
|
||||||
|
//! <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:43<font color="#AAAAAA"><i> on</i></font> main
|
||||||
|
//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3
|
||||||
|
//!
|
||||||
|
//! Oct 24 12:57:29.387 <font color="#CC0000"><b>fmt_pretty::yak_shave</b></font><font color="#CC0000">: failed to shave yak, </font><font color="#CC0000"><b>yak</b></font><font color="#CC0000">: 3, </font><font color="#CC0000"><b>error</b></font><font color="#CC0000">: missing yak</font>
|
||||||
|
//! <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:48<font color="#AAAAAA"><i> on</i></font> main
|
||||||
|
//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3
|
||||||
|
//!
|
||||||
|
//! Oct 24 12:57:29.387 <font color="#75507B"><b>fmt_pretty::yak_shave</b></font><font color="#75507B">: </font><font color="#75507B"><b>yaks_shaved</b></font><font color="#75507B">: 2</font>
|
||||||
|
//! <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:52<font color="#AAAAAA"><i> on</i></font> main
|
||||||
|
//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3
|
||||||
|
//!
|
||||||
|
//! Oct 24 12:57:29.387 <font color="#4E9A06"><b>fmt_pretty</b></font><font color="#4E9A06">: yak shaving completed, </font><font color="#4E9A06"><b>all_yaks_shaved</b></font><font color="#4E9A06">: false</font>
|
||||||
|
//! <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt-pretty.rs:19<font color="#AAAAAA"><i> on</i></font> main
|
||||||
|
//! </pre>
|
||||||
|
//!
|
||||||
|
//! * [`format::Json`]: Outputs newline-delimited JSON logs. This is intended
|
||||||
|
//! for production use with systems where structured logs are consumed as JSON
|
||||||
|
//! by analysis and viewing tools. The JSON output, as seen below, is *not*
|
||||||
|
//! optimized for human readability.
|
||||||
|
//!
|
||||||
|
//! For example:
|
||||||
|
//! <pre><font color="#4E9A06"><b> Finished</b></font> dev [unoptimized + debuginfo] target(s) in 1.58s
|
||||||
|
//! <font color="#4E9A06"><b> Running</b></font> `target/debug/examples/fmt-json`
|
||||||
|
//! {"timestamp":"Oct 24 13:00:00.873","level":"INFO","fields":{"message":"preparing to shave yaks","number_of_yaks":3},"target":"fmt_json"}
|
||||||
|
//! {"timestamp":"Oct 24 13:00:00.874","level":"INFO","fields":{"message":"shaving yaks"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"}]}
|
||||||
|
//! {"timestamp":"Oct 24 13:00:00.874","level":"TRACE","fields":{"message":"hello! I'm gonna shave a yak","excitement":"yay!"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"},{"yak":"1","name":"shave"}]}
|
||||||
|
//! {"timestamp":"Oct 24 13:00:00.874","level":"TRACE","fields":{"message":"yak shaved successfully"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"},{"yak":"1","name":"shave"}]}
|
||||||
|
//! {"timestamp":"Oct 24 13:00:00.874","level":"DEBUG","fields":{"yak":1,"shaved":true},"target":"yak_events","spans":[{"yaks":3,"name":"shaving_yaks"}]}
|
||||||
|
//! {"timestamp":"Oct 24 13:00:00.874","level":"TRACE","fields":{"yaks_shaved":1},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"}]}
|
||||||
|
//! {"timestamp":"Oct 24 13:00:00.874","level":"TRACE","fields":{"message":"hello! I'm gonna shave a yak","excitement":"yay!"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"},{"yak":"2","name":"shave"}]}
|
||||||
|
//! {"timestamp":"Oct 24 13:00:00.874","level":"TRACE","fields":{"message":"yak shaved successfully"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"},{"yak":"2","name":"shave"}]}
|
||||||
|
//! {"timestamp":"Oct 24 13:00:00.874","level":"DEBUG","fields":{"yak":2,"shaved":true},"target":"yak_events","spans":[{"yaks":3,"name":"shaving_yaks"}]}
|
||||||
|
//! {"timestamp":"Oct 24 13:00:00.874","level":"TRACE","fields":{"yaks_shaved":2},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"}]}
|
||||||
|
//! {"timestamp":"Oct 24 13:00:00.874","level":"TRACE","fields":{"message":"hello! I'm gonna shave a yak","excitement":"yay!"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"},{"yak":"3","name":"shave"}]}
|
||||||
|
//! {"timestamp":"Oct 24 13:00:00.875","level":"WARN","fields":{"message":"could not locate yak"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"},{"yak":"3","name":"shave"}]}
|
||||||
|
//! {"timestamp":"Oct 24 13:00:00.875","level":"DEBUG","fields":{"yak":3,"shaved":false},"target":"yak_events","spans":[{"yaks":3,"name":"shaving_yaks"}]}
|
||||||
|
//! {"timestamp":"Oct 24 13:00:00.875","level":"ERROR","fields":{"message":"failed to shave yak","yak":3,"error":"missing yak"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"}]}
|
||||||
|
//! {"timestamp":"Oct 24 13:00:00.875","level":"TRACE","fields":{"yaks_shaved":2},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"}]}
|
||||||
|
//! {"timestamp":"Oct 24 13:00:00.875","level":"INFO","fields":{"message":"yak shaving completed","all_yaks_shaved":false},"target":"fmt_json"}
|
||||||
|
//! </pre>
|
||||||
//!
|
//!
|
||||||
//! ### Filters
|
//! ### Filters
|
||||||
//!
|
//!
|
||||||
@ -116,7 +252,7 @@
|
|||||||
//! [`EnvFilter`]: ../filter/struct.EnvFilter.html
|
//! [`EnvFilter`]: ../filter/struct.EnvFilter.html
|
||||||
//! [`env_logger`]: https://docs.rs/env_logger/
|
//! [`env_logger`]: https://docs.rs/env_logger/
|
||||||
//! [`filter`]: ../filter/index.html
|
//! [`filter`]: ../filter/index.html
|
||||||
//! [`fmtBuilder`]: ./struct.SubscriberBuilder.html
|
//! [`SubscriberBuilder`]: ./struct.SubscriberBuilder.html
|
||||||
//! [`FmtSubscriber`]: ./struct.Subscriber.html
|
//! [`FmtSubscriber`]: ./struct.Subscriber.html
|
||||||
//! [`Subscriber`]:
|
//! [`Subscriber`]:
|
||||||
//! https://docs.rs/tracing/latest/tracing/trait.Subscriber.html
|
//! https://docs.rs/tracing/latest/tracing/trait.Subscriber.html
|
||||||
@ -200,7 +336,7 @@ pub struct SubscriberBuilder<
|
|||||||
/// .with_target(false)
|
/// .with_target(false)
|
||||||
/// .with_timer(tracing_subscriber::fmt::time::uptime())
|
/// .with_timer(tracing_subscriber::fmt::time::uptime())
|
||||||
/// .with_level(true)
|
/// .with_level(true)
|
||||||
/// // Set the subscriber as the default.
|
/// // Set the collector as the default.
|
||||||
/// .init();
|
/// .init();
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
@ -211,11 +347,11 @@ pub struct SubscriberBuilder<
|
|||||||
///
|
///
|
||||||
/// fn init_subscriber() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
|
/// fn init_subscriber() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
|
||||||
/// tracing_subscriber::fmt()
|
/// tracing_subscriber::fmt()
|
||||||
/// // Configure the subscriber to emit logs in JSON format.
|
/// // Configure the collector to emit logs in JSON format.
|
||||||
/// .json()
|
/// .json()
|
||||||
/// // Configure the subscriber to flatten event fields in the output JSON objects.
|
/// // Configure the collector to flatten event fields in the output JSON objects.
|
||||||
/// .flatten_event(true)
|
/// .flatten_event(true)
|
||||||
/// // Set the subscriber as the default, returning an error if this fails.
|
/// // Set the collector as the default, returning an error if this fails.
|
||||||
/// .try_init()?;
|
/// .try_init()?;
|
||||||
///
|
///
|
||||||
/// Ok(())
|
/// Ok(())
|
||||||
@ -572,7 +708,7 @@ where
|
|||||||
|
|
||||||
/// Sets the subscriber being built to use a less verbose formatter.
|
/// Sets the subscriber being built to use a less verbose formatter.
|
||||||
///
|
///
|
||||||
/// See [`format::Compact`](../fmt/format/struct.Compact.html).
|
/// See [`format::Compact`].
|
||||||
pub fn compact(self) -> SubscriberBuilder<N, format::Format<format::Compact, T>, F, W>
|
pub fn compact(self) -> SubscriberBuilder<N, format::Format<format::Compact, T>, F, W>
|
||||||
where
|
where
|
||||||
N: for<'writer> FormatFields<'writer> + 'static,
|
N: for<'writer> FormatFields<'writer> + 'static,
|
||||||
@ -583,6 +719,18 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the subscriber being built to use an [excessively pretty, human-readable formatter](crate::fmt::format::Pretty).
|
||||||
|
#[cfg(feature = "ansi")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "ansi")))]
|
||||||
|
pub fn pretty(
|
||||||
|
self,
|
||||||
|
) -> SubscriberBuilder<format::Pretty, format::Format<format::Pretty, T>, F, W> {
|
||||||
|
SubscriberBuilder {
|
||||||
|
filter: self.filter,
|
||||||
|
inner: self.inner.pretty(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Sets the subscriber being built to use a JSON formatter.
|
/// Sets the subscriber being built to use a JSON formatter.
|
||||||
///
|
///
|
||||||
/// See [`format::Json`](../fmt/format/struct.Json.html)
|
/// See [`format::Json`](../fmt/format/struct.Json.html)
|
||||||
@ -617,7 +765,7 @@ impl<T, F, W> SubscriberBuilder<format::JsonFields, format::Format<format::Json,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets whether or not the JSON layer being built will include the current span
|
/// Sets whether or not the JSON subscriber being built will include the current span
|
||||||
/// in formatted events.
|
/// in formatted events.
|
||||||
///
|
///
|
||||||
/// See [`format::Json`](../fmt/format/struct.Json.html)
|
/// See [`format::Json`](../fmt/format/struct.Json.html)
|
||||||
@ -631,7 +779,7 @@ impl<T, F, W> SubscriberBuilder<format::JsonFields, format::Format<format::Json,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets whether or not the JSON layer being built will include a list (from
|
/// Sets whether or not the JSON subscriber being built will include a list (from
|
||||||
/// root to leaf) of all currently entered spans in formatted events.
|
/// root to leaf) of all currently entered spans in formatted events.
|
||||||
///
|
///
|
||||||
/// See [`format::Json`](../fmt/format/struct.Json.html)
|
/// See [`format::Json`](../fmt/format/struct.Json.html)
|
||||||
|
@ -95,6 +95,12 @@
|
|||||||
unused_parens,
|
unused_parens,
|
||||||
while_true
|
while_true
|
||||||
)]
|
)]
|
||||||
|
// Using struct update syntax when a struct has no additional fields avoids
|
||||||
|
// a potential source change if additional fields are added to the struct in the
|
||||||
|
// future, reducing diff noise. Allow this even though clippy considers it
|
||||||
|
// "needless".
|
||||||
|
#![allow(clippy::needless_update)]
|
||||||
|
|
||||||
use tracing_core::span::Id;
|
use tracing_core::span::Id;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user