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

chore: port PRs pointed at v0.1.x to master #2288

Merged
merged 2 commits into from Aug 24, 2022
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
207 changes: 206 additions & 1 deletion tracing-subscriber/src/fmt/fmt_subscriber.rs
Expand Up @@ -68,6 +68,7 @@ pub struct Subscriber<C, N = format::DefaultFields, E = format::Format, W = fn()
fmt_event: E,
fmt_span: format::FmtSpanConfig,
is_ansi: bool,
log_internal_errors: bool,
_inner: PhantomData<fn(C)>,
}

Expand Down Expand Up @@ -117,6 +118,37 @@ where
fmt_span: self.fmt_span,
make_writer: self.make_writer,
is_ansi: self.is_ansi,
log_internal_errors: self.log_internal_errors,
_inner: self._inner,
}
}

/// Updates the event formatter by applying a function to the existing event formatter.
///
/// This sets the event formatter that the subscriber being built will use to record fields.
///
/// # Examples
///
/// Updating an event formatter:
///
/// ```rust
/// let subscriber = tracing_subscriber::fmt::subscriber()
/// .map_event_format(|e| e.compact());
/// # // this is necessary for type inference.
/// # use tracing_subscriber::Subscribe as _;
/// # let _ = subscriber.with_collector(tracing_subscriber::registry::Registry::default());
/// ```
pub fn map_event_format<E2>(self, f: impl FnOnce(E) -> E2) -> Subscriber<C, N, E2, W>
where
E2: FormatEvent<C, N> + 'static,
{
Subscriber {
fmt_fields: self.fmt_fields,
fmt_event: f(self.fmt_event),
fmt_span: self.fmt_span,
make_writer: self.make_writer,
is_ansi: self.is_ansi,
log_internal_errors: self.log_internal_errors,
_inner: self._inner,
}
}
Expand Down Expand Up @@ -152,6 +184,7 @@ impl<C, N, E, W> Subscriber<C, N, E, W> {
fmt_event: self.fmt_event,
fmt_span: self.fmt_span,
is_ansi: self.is_ansi,
log_internal_errors: self.log_internal_errors,
make_writer,
_inner: self._inner,
}
Expand Down Expand Up @@ -235,6 +268,7 @@ impl<C, N, E, W> Subscriber<C, N, E, W> {
fmt_event: self.fmt_event,
fmt_span: self.fmt_span,
is_ansi: self.is_ansi,
log_internal_errors: self.log_internal_errors,
make_writer: TestWriter::default(),
_inner: self._inner,
}
Expand All @@ -249,6 +283,58 @@ impl<C, N, E, W> Subscriber<C, N, E, W> {
..self
}
}

/// Sets whether to write errors from [`FormatEvent`] to the writer.
/// Defaults to true.
///
/// By default, `fmt::Subscriber` will write any `FormatEvent`-internal errors to
/// the writer. These errors are unlikely and will only occur if there is a
/// bug in the `FormatEvent` implementation or its dependencies.
///
/// If writing to the writer fails, the error message is printed to stderr
/// as a fallback.
///
/// [`FormatEvent`]: crate::fmt::FormatEvent
pub fn log_internal_errors(self, log_internal_errors: bool) -> Self {
Self {
log_internal_errors,
..self
}
}

/// Updates the [`MakeWriter`] by applying a function to the existing [`MakeWriter`].
///
/// This sets the [`MakeWriter`] that the subscriber being built will use to write events.
///
/// # Examples
///
/// Redirect output to stderr if level is <= WARN:
///
/// ```rust
/// use tracing::Level;
/// use tracing_subscriber::fmt::{self, writer::MakeWriterExt};
///
/// let stderr = std::io::stderr.with_max_level(Level::WARN);
/// let subscriber = fmt::subscriber()
/// .map_writer(move |w| stderr.or_else(w));
/// # // this is necessary for type inference.
/// # use tracing_subscriber::Subscribe as _;
/// # let _ = subscriber.with_collector(tracing_subscriber::registry::Registry::default());
/// ```
pub fn map_writer<W2>(self, f: impl FnOnce(W) -> W2) -> Subscriber<C, N, E, W2>
where
W2: for<'writer> MakeWriter<'writer> + 'static,
{
Subscriber {
fmt_fields: self.fmt_fields,
fmt_event: self.fmt_event,
fmt_span: self.fmt_span,
is_ansi: self.is_ansi,
log_internal_errors: self.log_internal_errors,
make_writer: f(self.make_writer),
_inner: self._inner,
}
}
}

impl<C, N, L, T, W> Subscriber<C, N, format::Format<L, T>, W>
Expand Down Expand Up @@ -276,6 +362,7 @@ where
fmt_span: self.fmt_span,
make_writer: self.make_writer,
is_ansi: self.is_ansi,
log_internal_errors: self.log_internal_errors,
_inner: self._inner,
}
}
Expand All @@ -288,6 +375,7 @@ where
fmt_span: self.fmt_span.without_time(),
make_writer: self.make_writer,
is_ansi: self.is_ansi,
log_internal_errors: self.log_internal_errors,
_inner: self._inner,
}
}
Expand Down Expand Up @@ -419,6 +507,7 @@ where
fmt_span: self.fmt_span,
make_writer: self.make_writer,
is_ansi: self.is_ansi,
log_internal_errors: self.log_internal_errors,
_inner: self._inner,
}
}
Expand All @@ -433,6 +522,7 @@ where
fmt_span: self.fmt_span,
make_writer: self.make_writer,
is_ansi: self.is_ansi,
log_internal_errors: self.log_internal_errors,
_inner: self._inner,
}
}
Expand Down Expand Up @@ -462,6 +552,7 @@ where
make_writer: self.make_writer,
// always disable ANSI escapes in JSON mode!
is_ansi: false,
log_internal_errors: self.log_internal_errors,
_inner: self._inner,
}
}
Expand Down Expand Up @@ -528,6 +619,38 @@ impl<C, N, E, W> Subscriber<C, N, E, W> {
fmt_span: self.fmt_span,
make_writer: self.make_writer,
is_ansi: self.is_ansi,
log_internal_errors: self.log_internal_errors,
_inner: self._inner,
}
}

/// Updates the field formatter by applying a function to the existing field formatter.
///
/// This sets the field formatter that the subscriber being built will use to record fields.
///
/// # Examples
///
/// Updating a field formatter:
///
/// ```rust
/// use tracing_subscriber::field::MakeExt;
/// let subscriber = tracing_subscriber::fmt::subscriber()
/// .map_fmt_fields(|f| f.debug_alt());
/// # // this is necessary for type inference.
/// # use tracing_subscriber::Subscribe as _;
/// # let _ = subscriber.with_collector(tracing_subscriber::registry::Registry::default());
/// ```
pub fn map_fmt_fields<N2>(self, f: impl FnOnce(N) -> N2) -> Subscriber<C, N2, E, W>
where
N2: for<'writer> FormatFields<'writer> + 'static,
{
Subscriber {
fmt_event: self.fmt_event,
fmt_fields: f(self.fmt_fields),
fmt_span: self.fmt_span,
make_writer: self.make_writer,
is_ansi: self.is_ansi,
log_internal_errors: self.log_internal_errors,
_inner: self._inner,
}
}
Expand All @@ -541,6 +664,7 @@ impl<C> Default for Subscriber<C> {
fmt_span: format::FmtSpanConfig::default(),
make_writer: io::stdout,
is_ansi: cfg!(feature = "ansi"),
log_internal_errors: false,
_inner: PhantomData,
}
}
Expand Down Expand Up @@ -660,6 +784,11 @@ where
{
fields.was_ansi = self.is_ansi;
extensions.insert(fields);
} else {
eprintln!(
"[tracing-subscriber] Unable to format the following event, ignoring: {:?}",
attrs
);
}
}

Expand Down Expand Up @@ -806,7 +935,20 @@ where
.is_ok()
{
let mut writer = self.make_writer.make_writer_for(event.metadata());
let _ = io::Write::write_all(&mut writer, buf.as_bytes());
let res = io::Write::write_all(&mut writer, buf.as_bytes());
if self.log_internal_errors {
if let Err(e) = res {
eprintln!("[tracing-subscriber] Unable to write an event to the Writer for this Subscriber! Error: {}\n", e);
}
}
} else if self.log_internal_errors {
let err_msg = format!("Unable to format the following event. Name: {}; Fields: {:?}\n",
event.metadata().name(), event.fields());
let mut writer = self.make_writer.make_writer_for(event.metadata());
let res = io::Write::write_all(&mut writer, err_msg.as_bytes());
if let Err(e) = res {
eprintln!("[tracing-subscriber] Unable to write an \"event formatting error\" to the Writer for this Subscriber! Error: {}\n", e);
}
}

buf.clear();
Expand Down Expand Up @@ -1105,6 +1247,69 @@ mod test {
re.replace_all(s.as_str(), "timing").to_string()
}

#[test]
fn format_error_print_to_stderr() {
struct AlwaysError;

impl std::fmt::Debug for AlwaysError {
fn fmt(&self, _f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
Err(std::fmt::Error)
}
}

let make_writer = MockMakeWriter::default();
let subscriber = crate::fmt::Collector::builder()
.with_writer(make_writer.clone())
.with_level(false)
.with_ansi(false)
.with_timer(MockTime)
.finish();

with_default(subscriber, || {
tracing::info!(?AlwaysError);
});
let actual = sanitize_timings(make_writer.get_string());

// Only assert the start because the line number and callsite may change.
let expected = concat!(
"Unable to format the following event. Name: event ",
file!(),
":"
);
assert!(
actual.as_str().starts_with(expected),
"\nactual = {}\nshould start with expected = {}\n",
actual,
expected
);
}

#[test]
fn format_error_ignore_if_log_internal_errors_is_false() {
struct AlwaysError;

impl std::fmt::Debug for AlwaysError {
fn fmt(&self, _f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
Err(std::fmt::Error)
}
}

let make_writer = MockMakeWriter::default();
let subscriber = crate::fmt::Collector::builder()
.with_writer(make_writer.clone())
.with_level(false)
.with_ansi(false)
.with_timer(MockTime)
.log_internal_errors(false)
.finish();

with_default(subscriber, || {
tracing::info!(?AlwaysError);
});
let actual = sanitize_timings(make_writer.get_string());
assert_eq!("", actual.as_str());
}

#[test]
fn synthesize_span_none() {
let make_writer = MockMakeWriter::default();
Expand Down