1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
/*!
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:

```
# use log::debug;
# use std::fmt;
#
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)
    }
}

# fn main() {}
```

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`:

```toml
[dependencies]
# ...
fern = { version = "0.6", 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, replacec
`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 youc
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.
*/