Skip to content

Commit fddbbc2

Browse files
committed
Avoid panicking for logging-while-logging
The `borrow_mut` panic could trip if a log happened while otherwise already logging, so this adds a test and then avoid the panic in a relatively naive way. If the panic should be avoided differently though, just let me know!
1 parent 1908978 commit fddbbc2

3 files changed

Lines changed: 55 additions & 1 deletion

File tree

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,9 @@ chrono = "0.4"
2323
name = "regexp_filter"
2424
harness = false
2525

26+
[[test]]
27+
name = "log-in-log"
28+
harness = false
29+
2630
[features]
2731
default = ["regex"]

src/lib.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,19 @@ impl Log for Logger {
468468
}
469469

470470
FORMATTER.with(|tl_buf| {
471-
let mut tl_buf = tl_buf.borrow_mut();
471+
// It's possible for implementations to sometimes
472+
// log-while-logging (e.g. a `std::fmt` implementation logs
473+
// internally) but it's super rare. If this happens make sure we
474+
// at least don't panic and ship some output to the screen.
475+
let mut a;
476+
let mut b = None;
477+
let tl_buf = match tl_buf.try_borrow_mut() {
478+
Ok(f) => {
479+
a = f;
480+
&mut *a
481+
}
482+
Err(_) => &mut b,
483+
};
472484

473485
// Check the buffer style. If it's different from the logger's
474486
// style then drop the buffer and recreate it.

tests/log-in-log.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#[macro_use] extern crate log;
2+
extern crate env_logger;
3+
4+
use std::process;
5+
use std::fmt;
6+
use std::env;
7+
use std::str;
8+
9+
struct Foo;
10+
11+
impl fmt::Display for Foo {
12+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
13+
info!("test");
14+
f.write_str("bar")
15+
}
16+
}
17+
18+
fn main() {
19+
env_logger::init();
20+
if env::var("YOU_ARE_TESTING_NOW").is_ok() {
21+
return info!("{}", Foo);
22+
}
23+
24+
let exe = env::current_exe().unwrap();
25+
let out = process::Command::new(exe)
26+
.env("YOU_ARE_TESTING_NOW", "1")
27+
.env("RUST_LOG", "debug")
28+
.output()
29+
.unwrap_or_else(|e| panic!("Unable to start child process: {}", e));
30+
if out.status.success() {
31+
return
32+
}
33+
34+
println!("test failed: {}", out.status);
35+
println!("--- stdout\n{}", str::from_utf8(&out.stdout).unwrap());
36+
println!("--- stderr\n{}", str::from_utf8(&out.stderr).unwrap());
37+
process::exit(1);
38+
}

0 commit comments

Comments
 (0)