use std::fmt::Write;
use std::os::raw::c_int;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering;
use logforth_append_async::AsyncBuilder;
use logforth_core::Append;
use logforth_core::Diagnostic;
use logforth_core::Error;
use logforth_core::record::LevelFilter;
use logforth_core::record::Record;
static IS_LOGGED: AtomicBool = AtomicBool::new(false);
static IS_FLUSHED: AtomicBool = AtomicBool::new(false);
#[derive(Debug)]
struct SetFlags;
impl Append for SetFlags {
fn append(&self, _: &Record, _: &[Box<dyn Diagnostic>]) -> Result<(), Error> {
IS_LOGGED.store(true, Ordering::SeqCst);
Ok(())
}
fn flush(&self) -> Result<(), Error> {
assert!(IS_LOGGED.load(Ordering::SeqCst));
IS_FLUSHED.store(true, Ordering::SeqCst);
Ok(())
}
}
fn run_test() {
{
extern "C" fn check() {
assert!(IS_FLUSHED.load(Ordering::SeqCst));
}
unsafe extern "C" {
fn atexit(cb: extern "C" fn()) -> c_int;
}
assert_eq!(unsafe { atexit(check) }, 0);
let asynchronous = AsyncBuilder::new("async-appender").append(SetFlags).build();
logforth::starter_log::builder()
.dispatch(|d| d.filter(LevelFilter::All).append(asynchronous))
.apply();
}
log::info!("hello async sink");
}
fn main() {
{
let mut captured_output = String::new();
let args = std::env::args().collect::<Vec<_>>();
let is_parent = args.iter().all(|arg| arg != "child");
if is_parent {
for i in 0..1000 {
let output = std::process::Command::new(&args[0])
.arg("child")
.stderr(std::process::Stdio::piped())
.output()
.unwrap();
let success = output.status.success();
writeln!(
captured_output,
"Attempt #{i} = {}",
if success { "ok" } else { "failed!" }
)
.unwrap();
if !success {
eprintln!("{captured_output}");
let stderr = String::from_utf8_lossy(&output.stderr).lines().fold(
String::new(),
|mut contents, line| {
writeln!(&mut contents, "> {line}").unwrap();
contents
},
);
eprintln!("stderr of the failed attempt:\n{stderr}");
panic!("test failed");
}
}
return;
} else {
assert_eq!(args[1], "child");
}
}
run_test();
}