Skip to content

Fatal Handling

Eduard Mishkurov edited this page Jun 19, 2026 · 2 revisions

Fatal Handling and Critical Logs

LogmeC writes a LEVEL_CRITICAL record. By default it does not terminate the process.

This is intentional. Existing projects and tests may use critical messages as severe diagnostics without expecting abort() or std::terminate() to be called. Termination is a policy decision, and logme lets the application choose that policy explicitly.

Fatal handler

A process can install a fatal handler on the global logger:

Logme::Instance->SetFatalHandler([]()
{
  std::abort();
});

or:

Logme::Instance->SetFatalHandler([]()
{
  std::terminate();
});

The handler is called after a LEVEL_CRITICAL record is written. If no handler is installed, LogmeC behaves like any other log level and only writes the critical record.

The handler can be reset:

Logme::Instance->ResetFatalHandler();

Flush before termination

When a fatal handler is installed, logme calls:

Logme::Instance->FlushAll();

before invoking the handler.

This matters for long-running services and asynchronous file logging. A critical message is often the last useful diagnostic before a crash or forced shutdown. FlushAll() gives backends and managers a chance to write pending records before the process terminates.

FlushAll() is also available as a normal public API. It is useful when the application performs an orderly shutdown or when a controlled fatal path is still running in normal application context.

FlushAll() is not a signal-handler-safe crash logging API. It walks normal channels and backends, so it should not be used from a POSIX signal handler where the process may have interrupted the logger, allocator, or backend code.

logme does not install signal handlers by itself. Signal policy belongs to the application. For emergency output from a crash or signal handler, use the separate Crash Logging path.

Recursion protection

Fatal handling is protected against recursion. If a fatal handler writes another critical message, logme will not start a second nested fatal-handling path.

This allows handlers to write final diagnostics without creating infinite recursion. The critical record is still written; the repeated fatal callback is suppressed.

Not a crash-handler API

Fatal handling is for controlled fatal records written through the normal logging pipeline. LogmeC, LogmeCheck, CHECK, and LOG(FATAL) can use channels, backends, formatting, and FlushAll() before the configured fatal handler is invoked.

This is different from a signal handler or crash handler. If the process may have interrupted the logger, allocator, or backend code, use the separate Crash Logging path instead. LogmeCrashRaw writes a literal emergency marker without using channels or backends, and LogmeCrash provides a less strict C-formatting emergency path.

Relation to glog-style CHECK and FATAL

The glog compatibility macros use this mechanism.

LOG(FATAL), CHECK(...), CHECK_EQ(...), and PCHECK(...) write through LogmeC. Whether the process terminates depends on the installed fatal handler.

This gives two useful modes:

// Compatibility mode with glog-like termination.
Logme::Instance->SetFatalHandler([]()
{
  std::abort();
});

or:

// Test or diagnostic mode: critical logs are recorded, but the process continues.
Logme::Instance->ResetFatalHandler();

That separation is deliberate. LEVEL_CRITICAL describes the severity of the record. The fatal handler describes what the application wants to do after such a record.

C API

The C API exposes global flushing:

LogmeFlushAll();

Fatal handler configuration is C++ API only.

Clone this wiki locally