Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions spdlog/src/lib.rs
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We currently set atexit and only hook_panic if atexit fails.

However, it seems that atexit is only called when the process is normally terminated. Not sure if a panic causes a normal exit, or an abnormal exit.

At least when panic = "abort", the atexit glue may not be called.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not at home these days, will take a look at it days later.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're not in a rush. Enjoy your days :D

Original file line number Diff line number Diff line change
Expand Up @@ -736,18 +736,15 @@ pub fn log_crate_proxy() -> &'static LogCrateProxy {
&PROXY
}

static IS_TEARING_DOWN: AtomicBool = AtomicBool::new(false);

fn flush_default_logger_at_exit() {
// Rust never calls `drop` for static variables.
//
// Setting up an exit handler gives us a chance to flush the default logger
// once at the program exit, thus we don't lose the last logs.

extern "C" fn handler() {
IS_TEARING_DOWN.store(true, Ordering::SeqCst);
if let Some(default_logger) = DEFAULT_LOGGER.get() {
default_logger.load().flush()
default_logger.load().flush_sinks_atexit()
}
}

Expand Down
12 changes: 10 additions & 2 deletions spdlog/src/logger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -497,14 +497,22 @@ impl Logger {
}
}

fn flush_sinks(&self) {
fn flush_sinks_with(&self, with: impl Fn(&dyn Sink) -> Result<()>) {
self.sinks.iter().for_each(|sink| {
if let Err(err) = sink.flush() {
if let Err(err) = with(&**sink) {
self.handle_error(err);
}
});
}

pub(crate) fn flush_sinks_atexit(&self) {
self.flush_sinks_with(|sink| sink.flush_atexit());
}

pub(crate) fn flush_sinks(&self) {
self.flush_sinks_with(|sink| sink.flush());
}

fn handle_error(&self, err: Error) {
self.error_handler.read_expect().call_internal(
format!(
Expand Down
42 changes: 25 additions & 17 deletions spdlog/src/sink/async_sink/async_pool_sink.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,21 +129,21 @@ impl Sink for AsyncPoolSink {
}

fn flush(&self) -> Result<()> {
if crate::IS_TEARING_DOWN.load(Ordering::SeqCst) {
// https://github.com/SpriteOvO/spdlog-rs/issues/64
//
// If the program is tearing down, this will be the final flush. `crossbeam`
// uses thread-local internally, which is not supported in `atexit` callback.
// This can be bypassed by flushing sinks directly on the current thread, but
// before we do that we have to destroy the thread pool to ensure that any
// pending log tasks are completed.
self.thread_pool.destroy();
self.backend.flush()
} else {
self.assign_task(Task::Flush {
backend: self.clone_backend(),
})
}
self.assign_task(Task::Flush {
backend: self.clone_backend(),
})
}

fn flush_atexit(&self) -> Result<()> {
// https://github.com/SpriteOvO/spdlog-rs/issues/64
//
// If the program is tearing down, this will be the final flush. `crossbeam`
// uses thread-local internally, which is not supported in `atexit` callback.
// This can be bypassed by flushing sinks directly on the current thread, but
// before we do that we have to destroy the thread pool to ensure that any
// pending log tasks are completed.
self.thread_pool.destroy();
self.backend.flush_atexit()
}
}

Expand Down Expand Up @@ -258,14 +258,22 @@ impl Backend {
result
}

fn flush(&self) -> Result<()> {
fn flush_with(&self, with: impl Fn(&dyn Sink) -> Result<()>) -> Result<()> {
let mut result = Ok(());
for sink in &self.sinks {
result = Error::push_result(result, sink.flush());
result = Error::push_result(result, with(&**sink));
}
result
}

fn flush(&self) -> Result<()> {
self.flush_with(|sink| sink.flush())
}

fn flush_atexit(&self) -> Result<()> {
self.flush_with(|sink| sink.flush_atexit())
}

fn handle_error(&self, err: Error) {
self.prop.call_error_handler_internal("AsyncPoolSink", err)
}
Expand Down
16 changes: 14 additions & 2 deletions spdlog/src/sink/dedup_sink.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,12 +152,20 @@ impl DedupSink {
})
}

fn flush_sinks(&self) -> Result<()> {
fn flush_with(&self, with: fn(&dyn Sink) -> Result<()>) -> Result<()> {
#[allow(clippy::manual_try_fold)] // https://github.com/rust-lang/rust-clippy/issues/11554
self.sinks.iter().fold(Ok(()), |result, sink| {
Error::push_result(result, sink.flush())
Error::push_result(result, with(sink.as_ref()))
})
}

fn flush_sinks(&self) -> Result<()> {
self.flush_with(|sink| sink.flush())
}

fn flush_sinks_atexit(&self) -> Result<()> {
self.flush_with(|sink| sink.flush_atexit())
}
}

impl GetSinkProp for DedupSink {
Expand Down Expand Up @@ -186,6 +194,10 @@ impl Sink for DedupSink {
fn flush(&self) -> Result<()> {
self.flush_sinks()
}

fn flush_atexit(&self) -> Result<()> {
self.flush_sinks_atexit()
}
}

impl Drop for DedupSink {
Expand Down
7 changes: 7 additions & 0 deletions spdlog/src/sink/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,13 @@ pub trait Sink: SinkPropAccess + Sync + Send {

/// Flushes any buffered records.
fn flush(&self) -> Result<()>;

/// Flushes any buffered records at program exit.
///
/// Default to call `flush()`.
fn flush_atexit(&self) -> Result<()> {
self.flush()
}
}

/// Container type for [`Sink`]s.
Expand Down
Loading