Module fern::meta
[−]
[src]
Fern supports logging most things by default, except for one kind of struct: structs which make log calls
to the global logger from within their Display
or Debug
implementations.
Here's an example of such a structure:
struct Thing<'a>(&'a str); impl<'a> fmt::Display for Thing<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { debug!("just displayed a Thing wrapping {}", self.0); f.write_str(self.0) } }
This structure, and this structure alone, will cause some problems when logging in fern. There are mitigations, but since it's a fairly niche use case, they are disabled by default.
The problems are, depending on which backend you use:
- stdout/stderr: logging will 'stutter', with the logs output inside the
Display
implementation cutting other log lines down the center - file: thread will deadlock, and all future logs will also deadlock
There are two mitigations you can make, both completely fix this error.
The simplest mitigation to this is to enable the meta-logging-in-format
feature of fern
. The disadvantage is that
this means fern makes an additional allocation per log call per affected backend. Not a huge cost, but enough to mean
it's disabled by default. To enable this, use the following in your Cargo.toml
:
[dependencies]
# ...
fern = { version = "0.5", features = ["meta-logging-in-format"] }
The second mitigation is one you can make inside a formatting closure. This means extra code complexity, but it also
means you can enable it per-logger: the fix isn't global. This fix is also redundant if you've already enable the
above feature. To add the second mitigation, replace format_args!()
with format!()
as displayed below:
fern::Dispatch::new() ... // instead of doing this: .format(move |out, message, record| { out.finish(format_args!("[{}] {}", record.level(), message)) }) // do this: .format(move |out, message, record| { let formatted = format!("[{}] {}", record.level(), message); out.finish(format_args!("{}", formatted)) })
This second mitigation works by forcing the Display
implementation to run before any text has started to log to the
backend. There's an additional allocation per log, but it no longer deadlocks!
This mitigation also has the advantage of ensuring there's only one call to Display::fmt
. If you use
meta-logging-in-format
and have multiple backends, Display::fmt
will still be called once per backend. With this,
it will only be called once.
If you've never experienced this problem, there's no need to fix it - Display::fmt
and Debug::fmt
are normally
implemented as "pure" functions with no side effects.