User’s API

Backend Options

struct BackendOptions

Configuration options for the backend.

This struct defines settings for the backend thread

Public Members

std::string thread_name = "QuillBackend"

The name assigned to the backend, visible during thread naming queries (e.g., pthread_getname_np) or in the debugger.

bool enable_yield_when_idle = false

The backend employs “busy-waiting” by spinning around each frontend thread’s queue. If enabled, the backend will yield when there is no remaining work, potentially reducing the OS scheduler priority for the backend. This option is effective only when sleep_duration is set to 0.

std::chrono::nanoseconds sleep_duration = std::chrono::nanoseconds{500}

Specifies the duration the backend sleeps if there is no remaining work to process in the queues.

uint32_t transit_event_buffer_initial_capacity = 128

The backend pops all log messages from the frontend queues and buffers them in a local ring buffer queue as transit events. The transit_event_buffer is unbounded, starting with a customizable initial capacity (in items, not bytes) and will reallocate up to transit_events_hard_limit The backend will use a separate transit_event_buffer for each frontend thread. The capacity must be a power of two.

size_t transit_events_soft_limit = 4096

The backend gives priority to reading messages from the frontend queues of all the hot threads and temporarily buffers them.

If a frontend threads continuously push messages to the queue (e.g., logging in a loop), no logs can ever be processed.

When the soft limit is reached the backend worker thread will try to process a batch of cached transit events all at once

The frontend queues are emptied on each iteration, so the actual popped messages can be much greater than the transit_events_soft_limit.

Note

This number represents a limit across the messages received from ALL frontend threads.

size_t transit_events_hard_limit = 32'768

The backend gives priority to reading messages from the frontend queues and temporarily buffers them.

If a frontend thread continuously push messages to the queue (e.g., logging in a loop), no logs can ever be processed.

As the backend buffers messages, it can keep buffering indefinitely if the frontend threads keep pushing.

This limit is the maximum size of the backend event buffer. When reached, the backend will stop reading the frontend queues until there is space available in the buffer.

Note

This number represents a limit PER frontend threads.

std::chrono::microseconds log_timestamp_ordering_grace_period = {1}

The backend iterates through all frontend lock-free queues and pops all messages from each queue. It then buffers and logs the message with the lowest timestamp among them.

Each frontend lock-free queue corresponds to a thread, and when multiple frontend threads are pushing logs simultaneously, it is possible to read a timestamp from the last queue in the iteration but miss that timestamp when the first queue was read because it was not available at that time.

When this option is set to a non-zero value, the backend takes a timestamp (now()) before reading the queues. It uses that timestamp to ensure that each log message’s timestamp from the frontend queues is less than or equal to the stored now() timestamp minus the specified grace period, guaranteeing ordering by timestamp.

Messages that fail the above check remain in the lock-free queue. They are checked again in the next iteration. The timestamp check is performed with microsecond precision.

Example scenario:

  1. Frontend thread takes a timestamp, then sleeps before pushing to the queue.

  2. Backend thread takes timestamp now() and subtracts the grace period, reads queues up to the adjusted now(), and writes the logs.

  3. Frontend thread wakes up and pushes to the queue.

  4. Backend thread reads and writes the delayed timestamp, resulting in an out-of-order log.

Setting this option to a non-zero value causes a minor delay in reading the messages from the lock-free queues but ensures correct timestamp order.

Setting log_timestamp_ordering_grace_period to zero disables strict timestamp ordering.

bool wait_for_queues_to_empty_before_exit = true

When this option is enabled and the application is terminating, the backend worker thread will not exit until all the frontend queues are empty.

However, if there is a thread during application destruction that keeps trying to log indefinitely, the backend will be unable to exit because it keeps popping log messages.

When this option is disabled, the backend will try to read the queues once and then exit. Reading the queues only once means that some log messages can be dropped, especially when strict_log_timestamp_order is set to true.

uint16_t cpu_affinity = (std::numeric_limits<uint16_t>::max)()

Pins the backend to the specified CPU.

By default, the backend is not pinned to any CPU unless a value is specified. It is recommended to pin the backend to a shared non-critical CPU. Use std::numeric_limits<uint16_t>::max() as an undefined value to avoid setting CPU affinity.

std::function<void(std::string const&)> error_notifier = [](std::string const& error_message){std::fprintf(stderr, "%s\n", error_message.data());}

The backend may encounter exceptions that cannot be caught within user threads. In such cases, the backend invokes this callback to notify the user.

This function sets up a user error notifier to handle backend errors and notifications, such as when the unbounded queue reallocates or when the bounded queue becomes full.

To disable notifications, simply leave the function undefined: std::function<void(std::string const&)> backend_error_notifier = {};

It’s safe to perform logging operations within this function (e.g., LOG_INFO(…)), but avoid calling logger->flush_log(). The function is invoked on the backend thread, which should not remain in a waiting state as it waits for itself.

std::chrono::milliseconds rdtsc_resync_interval = std::chrono::milliseconds{500}

This option is only applicable if at least one frontend is using a Logger with ClockSourceType::Tsc

When the system clock is used, this option can be ignored.

Controls the frequency at which the backend recalculates and syncs the internal RdtscClock with the system time from the system wall clock. The TSC clock can drift slightly over time and is not synchronized with NTP server updates.

Smaller values provide more accurate log timestamps at the cost of additional system clock calls. Changing this value only affects the performance of the backend worker.

std::chrono::milliseconds sink_min_flush_interval = std::chrono::milliseconds{200}

This option specifies the minimum time interval (in milliseconds) before the backend thread flushes the output buffers (flush_sink()) for all sinks in the application.

The backend thread will ensure that no sink is flushed more frequently than this interval. Explicit calls to logger->flush_log() override this interval and trigger an immediate flush.

However, if the backend thread is actively processing messages, flushing may occur less frequently than the specified interval.

Setting this value to 0 disables the feature, causing the backend thread to flush sinks whenever there is no pending work, provided a write to the sink has occurred.

This setting applies globally and affects all sinks in the application.

std::function<bool(char c)> check_printable_char = [](char c){ return (c >= ' ' && c <= '~') || (c == '\n'); }

This option enables a check that verifies the log message contains only printable characters before forwarding it to the sinks. This adds an extra layer of safety by filtering out non-printable characters from the log file. Any non-printable characters are converted to their equivalent hex value.

The check applies only when at least one argument in a log statement is of type string.

You can customize this callback to define your own range of printable characters if needed.

To disable this check, you can provide: std::function<bool(char c)> check_printable_char = {}

std::array<std::string, 12> log_level_descriptions = {"TRACE_L3", "TRACE_L2", "TRACE_L1", "DEBUG", "INFO", "NOTICE", "WARNING", "ERROR", "CRITICAL", "BACKTRACE", "NONE", "DYNAMIC"}

Holds descriptive names for various log levels used in logging operations. The indices correspond to LogLevel enum values defined elsewhere in the codebase. These names provide human-readable identifiers for each log level.

std::array<std::string, 12> log_level_short_codes = {"T3", "T2", "T1", "D", "I", "N", "W", "E", "C", "BT", "_", "DN"}

Short codes or identifiers for each log level.

Provides short codes representing each log level for compact identification and usage. The indices correspond to LogLevel enum values defined elsewhere in the codebase.

bool check_backend_singleton_instance = true

Enables a runtime check to detect multiple instances of the backend singleton.

When mixing shared and static libraries, linkage issues can lead to multiple instances of the backend singleton. This may result in multiple backend worker threads running simultaneously, causing unexpected behavior or crashes.

This issue commonly occurs on Windows when Quill is compiled as a static library and linked into both a shared library and the main executable, creating separate instances. While using Quill as a static library is generally recommended, in such cases, the preferred approach is to build Quill as a shared library and export its symbols (e.g., using WINDOWS_EXPORT_ALL_SYMBOLS).

On Windows, this check is implemented using a named mutex, whereas on Linux and other POSIX systems, it relies on a named semaphore. In rare cases, this mechanism may interfere with certain environments or containerized deployments. If necessary, this check can be disabled by setting this option to false.

Setting this option to true enables the check, while setting it to false disables it.

Backend Class

class Backend

Public Static Functions

static inline void start(BackendOptions const &options = BackendOptions{})

Starts the backend thread.

Parameters:

optionsBackend options to configure the backend behavior.

template<typename TFrontendOptions>
static inline void start(BackendOptions const &backend_options, SignalHandlerOptions const &signal_handler_options)

Starts the backend thread and initialises a signal handler

Note

When using the SignalHandler on Linux/MacOS, ensure that each spawned thread in your application has performed one of the following actions: i) Logged at least once. or ii) Called Frontend::preallocate(). or iii) Blocked signals on that thread to prevent the signal handler from running on it. This requirement is because the built-in signal handler utilizes a lock-free queue to issue log statements and await the log flushing. The queue is constructed on its first use with new(). Failing to meet any of the above criteria means the queue was never used, and it will be constructed inside the signal handler. The new operation is not an async signal-safe function and may lead to potential issues. However, when the queue is already created, no new call is made, and the remaining functions invoked internally by the built-in signal handler are async safe.

Parameters:
  • backend_optionsBackend options to configure the backend behavior.

  • signal_handler_options – SignalHandler options to configure the signal handler behavior. is enabled.

static inline void stop() noexcept

Stops the backend thread.

Note

thread-safe

static inline void notify() noexcept

Notifies the backend thread to wake up. It is possible to use a long backend sleep_duration and then notify the backend to wake up from any frontend thread.

Note

thread-safe

static inline bool is_running() noexcept

Checks if the backend is currently running.

Returns:

True if the backend is running, false otherwise.

static inline uint32_t get_thread_id() noexcept

Retrieves the ID of the backend thread.

Returns:

The ID of the backend thread.

static inline uint64_t convert_rdtsc_to_epoch_time(uint64_t rdtsc_value) noexcept

Converts an rdtsc value to epoch time. This function uses the same clock as the backend and can be called from any frontend thread. It is useful when using a logger with ClockSourceType::Tsc and you want to obtain a timestamp synchronized with the log files generated by the backend.

Alternatively you can use the Clock class from backend/Clock.h

Parameters:

rdtsc_value – The RDTSC value to convert.

Returns:

The epoch time corresponding to the RDTSC value.

static inline ManualBackendWorker *acquire_manual_backend_worker()

This feature is designed for advanced users who need to run the backend worker on their own thread, providing more flexibility at the cost of complexity and potential pitfalls.

This approach is generally not recommended due to the potential for inefficiency and complexity in managing the backend worker outside the provided mechanisms.

Important notes:

  • Do not use this to run the library in a single threaded application. This will lead to inefficiencies. The design of this logging library assumes that the backend worker operates in a separate thread from the frontend threads that issue log statements.

  • The thread running the ManualBackendWorker can log but it must not call logger->flush_log(), as this can lead to a deadlock situation.

  • The ManualBackendWorker should only be used by a single thread. It is not designed to handle multiple threads calling poll() simultaneously.

  • The built-in signal handler is not set up with ManualBackendWorker. If signal handling is required, you must manually set up the signal handler and block signals from reaching the ManualBackendWorker thread. See the start<FrontendOptions>(BackendOptions, SignalHandlerOptions) implementation for guidance on how to do this.

  • The following options are not supported when using ManualBackendWorker: cpu_affinity, thread_name, sleep_duration, and enable_yield_when_idle.

  • Avoid performing very heavy tasks in your custom thread. Significant delays in calling poll() can lead to the SPSC queues of the frontend threads becoming full. When this happens, the frontend threads may need to allocate additional memory on the hot path.

std::thread backend_worker([]()
  {
    quill::ManualBackendWorker* manual_backend_worker = quill::Backend::acquire_manual_backend_worker();

    quill::BackendOptions backend_options;
    manual_backend_worker->init(backend_options);

    while (true)
    {
      manual_backend_worker->poll();
    }
  });

BackendTscClock Class

class BackendTscClock

A utility class for accessing the Time Stamp Counter (TSC) clock used by the backend logging thread.

This class provides access to the TSC clock maintained by the backend logging thread, allowing for synchronized timestamp retrieval.

Other threads can obtain timestamps synchronized with the TSC clock of the backend logging thread, ensuring synchronization with log statement timestamps.

If ClockSourceType::Tsc is not used by any Logger, this class reverts to using the system clock for providing a timestamp.

Note

For more accurate timestamps, consider reducing rdtsc_resync_interval in BackendOptions.

Note

All methods of the class are thread-safe.

Public Static Functions

static inline time_point now() noexcept

Provides the current synchronized timestamp obtained using the TSC clock maintained by the backend logging thread.

Returns:

A wall clock timestamp in nanoseconds since epoch, synchronized with the backend logging thread’s TSC clock.

static inline RdtscVal rdtsc() noexcept

Returns the current value of the TSC timer maintained by the backend logging thread.

Returns:

The current value of the TSC timer.

static inline time_point to_time_point(RdtscVal rdtsc) noexcept

Converts a TSC (Time Stamp Counter) value to a wall clock timestamp.

Warning

This function will return 0 if no Logger with a TSC clock source has been used. The TSC clock is initialized by the backend thread when the first log statement is processed, provided that a TSC-based logger is used. If the backend thread has not processed any log statements, the function may return zero.

Parameters:

rdtsc – The TSC counter value

Returns:

The time since the Unix epoch, in nanoseconds, corresponding to the given TSC counter value.

class RdtscVal

SignalHandler Options

struct SignalHandlerOptions

Struct to hold options for the signal handler.

Public Members

std::vector<int> catchable_signals = {SIGTERM, SIGINT, SIGABRT, SIGFPE, SIGILL, SIGSEGV}

List of signals that the backend should catch if with_signal_handler is enabled.

uint32_t timeout_seconds = 20u

Defines the timeout duration in seconds for the signal handler alarm. It is only available on Linux, as Windows does not support the alarm function. The signal handler sets up an alarm to ensure that the process will terminate if it does not complete within the specified time frame. This is particularly useful to prevent the process from hanging indefinitely in case the signal handler encounters an issue.

std::string logger

The logger instance that the signal handler will use to log errors when the application crashes. The logger is accessed by the signal handler and must be created by your application using Frontend::create_or_get_logger(…). If the specified logger is not found, or if this parameter is left empty, the signal handler will default to using the first valid logger it finds.

Frontend Options

struct FrontendOptions

Public Static Attributes

static constexpr QueueType queue_type = QueueType::UnboundedBlocking

Each frontend thread has its own queue, which can be configured with various options:

  • UnboundedBlocking: Starts with initial_queue_capacity and reallocates up to unbounded_queue_max_capacity, then blocks.

  • UnboundedDropping: Starts with initial_queue_capacity and reallocates up to unbounded_queue_max_capacity, then drops log messages.

  • BoundedBlocking: Starts with initial_queue_capacity and never reallocates; blocks when the limit is reached.

  • BoundedDropping: Starts with initial_queue_capacity and never reallocates; drops log messages when the limit is reached.

By default, the library uses an UnboundedBlocking queue, which starts with initial_queue_capacity.

static constexpr size_t initial_queue_capacity = 128u * 1024u

Initial capacity of the queue.

static constexpr uint32_t blocking_queue_retry_interval_ns = 800

Interval for retrying when using BoundedBlocking or UnboundedBlocking. Applicable only when using BoundedBlocking or UnboundedBlocking.

static constexpr size_t unbounded_queue_max_capacity = 2ull * 1024u * 1024u * 1024u

Maximum capacity for unbounded queues (UnboundedBlocking, UnboundedDropping). This defines the maximum size to which the queue can grow before blocking or dropping messages.

static constexpr HugePagesPolicy huge_pages_policy = HugePagesPolicy::Never

Enables huge pages on the frontend queues to reduce TLB misses. Available only for Linux.

Frontend Class

template<typename TFrontendOptions>
class FrontendImpl

Public Static Functions

static inline void preallocate()

Pre-allocates the thread-local data needed for the current thread.

Although optional, it is recommended to invoke this function during the thread initialization phase before the first log message.

static inline void shrink_thread_local_queue(size_t capacity)

Shrink the thread-local SPSC queue to the specified target capacity.

This function helps manage memory usage by reducing the size of the thread-local queue. In scenarios where a thread pool executes multiple jobs, one job might log a burst of messages that causes the queue to grow significantly. Subsequent jobs may not require such a large capacity, so you can call this function to explicitly shrink the queue to a smaller size.

Note

This function only applies when using the UnboundedQueue configuration. It will have no effect if the BoundedQueue is enabled.

Note

The function will only shrink the queue if the provided target capacity is smaller than the current queue capacity. If the target capacity is greater than or equal to the current capacity, no change is made.

Warning

The Logger object may maintain multiple thread-local queues. This function will only shrink the queue associated with the calling thread, so it is important that the appropriate thread invokes it.

Parameters:

capacity – The desired new capacity for the thread-local SPSC queue.

static inline size_t get_thread_local_queue_capacity() noexcept

Retrieve the current capacity of the thread-local SPSC queue.

This function returns the capacity of the SPSC queue that belongs to the calling thread. It is particularly useful for monitoring how much an UnboundedQueue has grown over time, while for a BoundedQueue, the capacity remains constant.

Note

When using an UnboundedQueue, the function returns the capacity as determined by the producer, reflecting the dynamic growth of the queue. For a BoundedQueue, the returned capacity is fixed.

Note

Since the Logger object can maintain multiple thread-local queues, this function always returns the capacity of the queue associated with the thread that calls it. Ensure that the correct thread is invoking this function to check its own queue.

Returns:

The current capacity of the thread-local SPSC queue.

template<typename TSink, typename ...Args>
static inline std::shared_ptr<Sink> create_or_get_sink(std::string const &sink_name, Args&&... args)

Creates a new sink or retrieves an existing one with the specified name.

Parameters:
  • sink_name – The name of the sink.

  • args – The arguments to pass to the sink constructor.

Returns:

std::shared_ptr<Sink> A shared pointer to the created or retrieved sink.

static inline std::shared_ptr<Sink> get_sink(std::string const &sink_name)

Retrieves an existing sink with the specified name.

Parameters:

sink_name – The name of the sink.

Returns:

std::shared_ptr<Sink> A shared pointer to the retrieved sink, or nullptr if not found.

static inline logger_t *create_or_get_logger(std::string const &logger_name, std::shared_ptr<Sink> sink, PatternFormatterOptions const &pattern_formatter_options = PatternFormatterOptions{}, ClockSourceType clock_source = ClockSourceType::Tsc, UserClockSource *user_clock = nullptr)

Creates a new logger or retrieves an existing one with the specified name.

Parameters:
  • logger_name – The name of the logger.

  • sink – A shared pointer to the sink to associate with the logger.

  • pattern_formatter_options – Contains the formatting configuration for PatternFormatter

  • clock_source – The clock source for log timestamps.

  • user_clock – A pointer to a custom user clock.

Returns:

Logger* A pointer to the created or retrieved logger.

static inline logger_t *create_or_get_logger(std::string const &logger_name, std::vector<std::shared_ptr<Sink>> sinks, PatternFormatterOptions const &pattern_formatter_options = PatternFormatterOptions{}, ClockSourceType clock_source = ClockSourceType::Tsc, UserClockSource *user_clock = nullptr)

Creates a new logger or retrieves an existing one with the specified name and multiple sinks.

Parameters:
  • logger_name – The name of the logger.

  • sinks – A vector of shared pointers to sinks to associate with the logger.

  • pattern_formatter_options – Contains the formatting configuration for PatternFormatter

  • clock_source – The clock source for log timestamps.

  • user_clock – A pointer to a custom user clock.

Returns:

Logger* A pointer to the created or retrieved logger.

static inline logger_t *create_or_get_logger(std::string const &logger_name, std::initializer_list<std::shared_ptr<Sink>> sinks, PatternFormatterOptions const &pattern_formatter_options = PatternFormatterOptions{}, ClockSourceType clock_source = ClockSourceType::Tsc, UserClockSource *user_clock = nullptr)

Creates a new logger or retrieves an existing one with the specified name and multiple sinks.

Parameters:
  • logger_name – The name of the logger.

  • sinks – An initializer list of shared pointers to sinks to associate with the logger.

  • pattern_formatter_options – Contains the formatting configuration for PatternFormatter

  • clock_source – The clock source for log timestamps.

  • user_clock – A pointer to a custom user clock.

Returns:

Logger* A pointer to the created or retrieved logger.

static inline logger_t *create_or_get_logger(std::string const &logger_name, detail::LoggerBase *source_logger = nullptr)

Creates a new logger or retrieves an existing one that shares the same options as the specified logger.

This function allows you to create or obtain a logger identified by logger_name. If a logger with the same name already exists, its configuration options will be used. If it does not exist, a new logger will be created with the same options as the provided source_logger.

Parameters:
  • logger_name – The name of the logger to create or retrieve.

  • source_logger – The logger from which to copy the configuration options.

Returns:

A pointer to the logger instance, either newly created or retrieved.

static inline void remove_logger(detail::LoggerBase *logger)

Asynchronously removes the specified logger.

When a logger is removed, if its underlying sinks are not shared by any other logger, they are destructed, and any associated files are also closed.

A common use case for this function is when you want to close the underlying files that the logger is using.

Since the exact removal timing is unknown, you should not attempt to create a new logger with the same name as the one being removed.

Note

This function is thread-safe. However, removing the same logger (logger_t*) from multiple threads is not allowed. You must ensure that remove_logger_blocking is only called by a single thread for a given logger.

Warning

After calling this function, no thread should use this logger.

Parameters:

logger – A pointer to the logger to remove.

static inline void remove_logger_blocking(logger_t *logger, uint32_t sleep_duration_ns = 100)

Asynchronously removes the specified logger and blocks until removal is complete.

When a logger is removed, any files associated with its sinks are also closed.

A use case for this function is when you want to change the sinks of a logger. You can call this function to remove the logger and then recreate it with new sinks and the same name. However, no other threads should be using the logger after the call to this function.

Note

This function is thread-safe. However, removing the same logger (logger_t*) from multiple threads is not allowed. You must ensure that remove_logger_blocking is only called by a single thread for a given logger.

Warning

After calling this function, no thread should use this logger.

Parameters:
  • logger – A pointer to the logger to remove.

  • sleep_duration_ns – The duration in nanoseconds to sleep between retries

static inline logger_t *get_logger(std::string const &logger_name)

Retrieves an existing logger with the specified name.

Parameters:

logger_name – The name of the logger.

Returns:

Logger* A pointer to the retrieved logger, or nullptr if not found.

static inline std::vector<logger_t*> get_all_loggers()

Retrieves a map of all registered valid loggers.

Note

If remove_logger() is called from this or another thread, the return value of this function will become invalid.

Returns:

A vector containing all registered loggers.

static inline logger_t *get_valid_logger() noexcept

Returns the first valid logger that is found. This is useful when you do not want to use the std::vector<logger_t*> return value of get_all_loggers.

Returns:

A pointer to the first valid logger, or nullptr if no valid logger is found.

static inline size_t get_number_of_loggers() noexcept

Counts the number of existing loggers, including any invalidated loggers. This function can be useful for verifying if a logger has been removed after calling remove_logger() by the backend, as removal occurs asynchronously.

Returns:

The number of loggers.

Log Levels

enum class LogLevel : uint8_t

Log level enum

Values:

enumerator TraceL3
enumerator TraceL2
enumerator TraceL1
enumerator Debug
enumerator Info
enumerator Notice
enumerator Warning
enumerator Error
enumerator Critical
enumerator Backtrace

This is only used for backtrace logging. Should not be set by the user.

enumerator None
enumerator Dynamic

This is only used for dynamic logging. Should not be set by the user.

LoggerImpl Class

template<typename TFrontendOptions>
class LoggerImpl : public detail::LoggerBase

Thread safe logger.

Logger must be obtained from create_or_get_logger(), therefore constructors are private

Public Functions

template<bool immediate_flush, bool has_dynamic_log_level, typename... Args> inline bool log_statement (QUILL_MAYBE_UNUSED LogLevel dynamic_log_level, MacroMetadata const *macro_metadata, Args &&... fmt_args)

Push a log message to the spsc queue to be logged by the backend thread. One spsc queue per caller thread. This function is enabled only when all arguments are fundamental types. This is the fastest way possible to log

Note

This function is thread-safe.

Parameters:
  • dynamic_log_level – dynamic log level

  • macro_metadata – metadata of the log message

  • fmt_args – arguments

Returns:

true if the message is written to the queue, false if it is dropped (when a dropping queue is used)

inline void init_backtrace(uint32_t max_capacity, LogLevel flush_level = LogLevel::None)

Init a backtrace for this logger. Stores messages logged with LOG_BACKTRACE in a ring buffer messages and displays them later on demand.

Parameters:
  • max_capacity – The max number of messages to store in the backtrace

  • flush_level – If this loggers logs any message higher or equal to this severity level the backtrace will also get flushed. Default level is None meaning the user has to call flush_backtrace explicitly

inline void flush_backtrace()

Dump any stored backtrace messages

inline void flush_log(uint32_t sleep_duration_ns = 100)

Blocks the calling thread until all log messages up to the current timestamp are flushed.

The backend thread will invoke the write operation on all sinks for all loggers up to the point (timestamp) when this function is invoked.

Note

This function should only be called when the backend worker is running after Backend::start(…)

Note

This function will block the calling thread until the flush message is processed by the backend thread. The calling thread can block for up to backend_options.sleep_duration. If you configure a custom long sleep duration on the backend thread, e.g., backend_options.sleep_duration = std::chrono::minutes{1}, then you should ideally avoid calling this function as you can block for long period of times unless you use another thread that calls Backend::notify()

Warning

Do not call this function from the destructor of a static object. This may lead to application crashes if the thread-local ThreadContext is destroyed before the static object invoking flush_log.

Parameters:

sleep_duration_ns – The duration in nanoseconds to sleep between retries when the blocking queue is full, and between checks for the flush completion. Default is 100 nanoseconds.

PatternFormatter Class

class PatternFormatter

Public Types

enum class TimestampPrecision : uint8_t

Public classes Stores the precision of the timestamp

Values:

enumerator None
enumerator MilliSeconds
enumerator MicroSeconds
enumerator NanoSeconds

Public Functions

inline explicit PatternFormatter(PatternFormatterOptions options)

Main PatternFormatter class Constructor for a PatternFormatter with custom formatting options.

See also

PatternFormatterOptions for detailed information on available options.

Parameters:

options – The PatternFormatterOptions object containing the formatting configuration.

Throws:

std::invalid_argument – if the format string in options is invalid

PatternFormatterOptions Class

class PatternFormatterOptions

Configuration options for the PatternFormatter.

This class encapsulates the configuration options used to customize the formatting of log messages.

Public Members

std::string format_pattern

The format pattern for log messages.

This string defines the overall structure of each log message.

It can include various placeholders that will be replaced with actual values when formatting the log message.

%(time) - Human-readable timestamp representing when the log statement was created. %(file_name) - Name of the source file where the logging call was issued. %(full_path) - Full path of the source file where the logging call was issued. %(caller_function) - Name of the function containing the logging call. %(log_level) - Textual representation of the logging level for the message. %(log_level_short_code) - Abbreviated log level name. %(line_number) - Line number in the source file where the logging call was issued. %(logger) - Name of the logger used to log the call. %(message) - The logged message itself. %(thread_id) - ID of the thread in which the logging call was made. %(thread_name) - Name of the thread. Must be set before the first log statement on that thread. %(process_id) - ID of the process in which the logging call was made. %(source_location) - Full source file path and line number as a single string. %(short_source_location) - Shortened source file name and line number as a single string. %(tags) - Additional custom tags appended to the message when _TAGS macros are used. %(named_args) - Key-value pairs appended to the message. Only applicable when the message has named args; remains empty otherwise.

Warning

The same attribute cannot be used twice in the same format pattern.

std::string timestamp_pattern

The format pattern for timestamps.

This string defines how timestamps are formatted in log messages. It follows the strftime() format with additional specifiers:

  • Qms : Milliseconds

  • Qus : Microseconds

  • Qns : Nanoseconds

Timezone timestamp_timezone

The timezone to use for timestamps.

Determines whether timestamps are formatted in local time or GMT.

bool add_metadata_to_multi_line_logs

Whether to add metadata to each line of multi-line log messages.

If true, ensures that metadata (e.g., timestamp, log level) is added to every line of multi-line log entries, maintaining consistency across all log outputs.

Sink Class

class Sink

Base class for sinks

Subclassed by NullSink, StreamSink

Public Functions

inline explicit Sink(std::optional<PatternFormatterOptions> override_pattern_formatter_options = std::nullopt)

Constructor Uses the default pattern formatter

virtual ~Sink() = default

Destructor

inline void set_log_level_filter(LogLevel log_level)

Sets a log level filter on the sink.

Note

Thread safe.

Parameters:

log_level – The log level severity.

inline LogLevel get_log_level_filter() const noexcept

Returns the current log level filter set on the sink.

Note

Thread safe.

Returns:

The current log level filter.

inline void add_filter(std::unique_ptr<Filter> filter)

Adds a new filter to the sink.

Note

Thread safe.

Parameters:

filter – Unique pointer to the filter instance.

Filter Class

class Filter

Base filter class. Filters can be added to Sinks

Public Functions

inline explicit Filter(std::string filter_name)

Constructor

Parameters:

filter_name – unique filter name

virtual ~Filter() = default

Destructor

virtual bool filter(MacroMetadata const *log_metadata, uint64_t log_timestamp, std::string_view thread_id, std::string_view thread_name, std::string_view logger_name, LogLevel log_level, std::string_view log_message, std::string_view log_statement) noexcept = 0

Filters a log message.

Parameters:
  • log_metadata – Pointer to the macro metadata.

  • log_timestamp – Timestamp of the log event.

  • thread_id – ID of the thread.

  • thread_name – Name of the thread.

  • logger_name – Name of the logger.

  • log_level – Log level of the message.

  • log_message – The log message.

  • log_statement – The log statement.

Returns:

true if the log message should be written to the file, false otherwise

inline virtual std::string const &get_filter_name() const noexcept

Gets the name of the filter. Only useful if an existing filter is needed to be looked up

Returns:

the name of the filter

FileSinkConfig Class

class FileSinkConfig

The FileSinkConfig class holds the configuration options for the FileSink

Subclassed by RotatingFileSinkConfig

Public Functions

inline void set_filename_append_option(FilenameAppendOption value, std::string_view append_filename_format_pattern = std::string_view{})

Sets the append type for the file name. Possible append types are: StartDate, StartDateTime or None. When this option is set, the file name will be appended with the start date or date and time timestamp of when the process started.

For example: application.log -> application_20230101.log (StartDate) application.log -> application_20230101_121020.log (StartDateTime)

Parameters:
  • value – The append type to set. Valid options are Date and DateAndTime.

  • append_filename_format_pattern – Specifies a custom strftime format pattern to use for the filename. This parameter is only applicable when FilenameAppendOption::CustomDateTimeFormat is selected

inline void set_timezone(Timezone time_zone)

Sets the timezone to use for time-based operations e.g. when appending the date to the get_filename or when setting the logging pattern. Valid options for the timezone are ‘LocalTime’ or ‘GmtTime’ The default value is ‘LocalTime’.

Parameters:

time_zone – The timezone to use for time-based operations.

inline void set_fsync_enabled(bool value)

Sets whether fsync should be performed when flushing. The default value is false.

Parameters:

value – True to perform fsync, false otherwise.

inline void set_open_mode(char open_mode)

Sets the open mode for the file. Valid options for the open mode are ‘a’ or ‘w’. The default value is ‘a’.

Parameters:

open_mode – open mode for the file.

inline void set_write_buffer_size(size_t value)

Sets the user-defined buffer size for fwrite operations.

This function allows you to specify a custom buffer size for fwrite, improving efficiency for file write operations.

To disable custom buffering and revert to the default size, pass a value of 0.

Note

By default, a buffer size of 64 KB is used.

Parameters:

value – Size of the buffer in bytes. If set to 0, the default buffer size will be used.

inline void set_minimum_fsync_interval(std::chrono::milliseconds value)

Sets the minimum interval between fsync calls. This specifies the minimum time between consecutive fsync operations but does not guarantee that fsync will be called exactly at that interval.

For example, if some messages are flushed to the log and fsync is skipped because it was previously called, and no further messages are written to the file, fsync will not be called even if the minimum interval has passed. This is because the previous call was skipped due to the interval, and no new messages necessitate another fsync call.

This feature is intended to mitigate concerns about frequent fsync calls potentially causing disk wear.

Note: This option is only applicable when fsync is enabled. By default, the value is 0, which means that fsync will be called periodically by the backend worker thread when messages are written to the file, irrespective of the interval.

Parameters:

value – The minimum interval, in milliseconds, between fsync calls.

inline void set_override_pattern_formatter_options(std::optional<PatternFormatterOptions> const &options)

Sets custom pattern formatter options for this sink.

By default, the logger’s pattern formatter is used to format log messages. This function allows overriding the default formatter with custom options for this specific sink. If a custom formatter is provided, it will be used instead of the logger’s formatter.

Parameters:

options – The custom pattern formatter options to use

inline bool fsync_enabled() const noexcept

Getters

FileSink Class

class FileSink : public StreamSink

FileSink Writes the log messages to a file

Subclassed by detail::JsonSink< FileSink >

Public Functions

inline explicit FileSink(fs::path const &filename, FileSinkConfig const &config = FileSinkConfig{}, FileEventNotifier file_event_notifier = FileEventNotifier{}, bool do_fopen = true, std::chrono::system_clock::time_point start_time = std::chrono::system_clock::now())

Construct a FileSink object. This constructor will always attempt to open the given file.

Parameters:
  • filename – Path to the file to be opened.

  • config – Configuration for the FileSink.

  • file_event_notifier – Notifies on file events.

  • do_fopen – If false, the file will not be opened.

  • start_time – start time

inline virtual void flush_sink() override

Flushes the stream and optionally fsyncs it.

RotatingSink Class

template<typename TBase>
class RotatingSink : public TBase

The RotatingSink class.

Public Functions

inline RotatingSink(fs::path const &filename, RotatingFileSinkConfig const &config, FileEventNotifier file_event_notifier = FileEventNotifier{}, std::chrono::system_clock::time_point start_time = std::chrono::system_clock::now())

Constructor.

Creates a new instance of the RotatingSink class.

Parameters:
  • filename – The base file name to be used for logs.

  • config – The sink configuration.

  • file_event_notifier – file event notifier

  • start_time – start time

inline void write_log(MacroMetadata const *log_metadata, uint64_t log_timestamp, std::string_view thread_id, std::string_view thread_name, std::string const &process_id, std::string_view logger_name, LogLevel log_level, std::string_view log_level_description, std::string_view log_level_short_code, std::vector<std::pair<std::string, std::string>> const *named_args, std::string_view log_message, std::string_view log_statement) override

Writes a formatted log message to the stream.

Parameters:
  • log_metadata – The metadata of the log message

  • log_timestamp – The timestamp of the log message

  • thread_id – The ID of the thread that generated the log message

  • thread_name – The name of the thread that generated the log message

  • process_id – Process Id

  • logger_name – logger name

  • log_level – Log level of the message.

  • log_level_description – Description of the log level.

  • log_level_short_code – Short code representing the log level.

  • named_args – Structured key-value pairs associated with the log message

  • log_message – The log message to write

  • log_statement – The full log statement

RotatingFileSinkConfig Class

class RotatingFileSinkConfig : public FileSinkConfig

The configuration options for the RotatingSink.

Public Types

enum class RotationFrequency : uint8_t

The frequency of log file rotation.

Values:

enumerator Disabled
enumerator Daily
enumerator Hourly
enumerator Minutely
enum class RotationNamingScheme : uint8_t

The naming scheme for rotated log files.

Values:

enumerator Index
enumerator Date
enumerator DateAndTime

Public Functions

inline RotatingFileSinkConfig()

Constructs a new RotatingFileSinkConfig object.

inline void set_rotation_max_file_size(size_t value)

Sets the maximum file size for rotation.

Parameters:

value – The maximum file size in bytes per file

inline void set_rotation_frequency_and_interval(char frequency, uint32_t interval)

Sets the frequency and interval of file rotation.

Parameters:
  • frequency – The frequency of file rotation (‘M’ for minutes, ‘H’ for hours)

  • interval – The rotation interval

inline void set_rotation_time_daily(std::string const &daily_rotation_time_str)

Sets the time of day for daily log file rotation.

Parameters:

daily_rotation_time_str – The time of day for rotation (format: “HH:MM”)

inline void set_max_backup_files(uint32_t value)

Sets the maximum number of log files to keep.

Parameters:

value – The maximum number of log files

inline void set_overwrite_rolled_files(bool value)

Sets whether the oldest rolled logs should be overwritten when the maximum backup count is reached. If set to false, the oldest logs will not be overwritten when the maximum backup count is reached, and log file rotation will stop. The default value is true.

Parameters:

value – True to overwrite the oldest logs, false otherwise.

inline void set_remove_old_files(bool value)

Sets whether previous rotated log files should be removed on process start up.

Note

This option works only when using the mode=”w” This is useful to avoid conflicting file names when the process restarts and FilenameAppend::DateTime was not set. The default value is true.

Parameters:

value – True to remove old log files, false otherwise.

inline void set_rotation_naming_scheme(RotationNamingScheme value)

Sets the naming scheme for the rotated files. The default value is ‘Index’.

Parameters:

value – The naming scheme to set.

inline size_t rotation_max_file_size() const noexcept

Getter methods

JsonFileSink Class

class JsonFileSink : public detail::JsonSink<FileSink>

JSON File Sink

JsonConsoleSink Class

class JsonConsoleSink : public detail::JsonSink<StreamSink>

JSON Console Sink

SyslogSink Class

class SyslogSink : public quill::Sink

A sink that writes log messages to the system logger (syslog).

This sink leverages the syslog API to send log messages. It uses the configuration provided via SyslogSinkConfig to determine how the messages are formatted and mapped.

Public Functions

inline explicit SyslogSink(SyslogSinkConfig config = SyslogSinkConfig{})

Constructs a SyslogSink with the given configuration. This constructor initializes the syslog connection using openlog().

Parameters:

config – The configuration options for the SyslogSink. Defaults to a default-configured SyslogSinkConfig.

inline void write_log(MacroMetadata const*, uint64_t, std::string_view, std::string_view, std::string const&, std::string_view, LogLevel log_level, std::string_view, std::string_view, std::vector<std::pair<std::string, std::string>> const*, std::string_view log_message, std::string_view log_statement) override

Writes a formatted log message to the stream.

SyslogSinkConfig Class

class SyslogSinkConfig

Holds the configuration options for the SyslogSink.

When including syslog.h via SyslogSink, the header defines macros such as LOG_INFO and others that conflict with Quill’s LOG_ macros.

To resolve this issue, consider one of the following solutions:

  1. Include SyslogSink in a .cpp file only: Instantiate the SyslogSink in a source file rather than a header file. This ensures that syslog.h is only included in that specific translation unit, avoiding collisions in other files where you want to use the unprefixed Quill LOG_ macros.

  2. Define the preprocessor flag : When this flag is defined, Quill will disable its unprefixed LOG_ macros. Instead, you must use the longer QUILL_LOG_ macros. This approach allows Quill and syslog.h to coexist in the same translation unit.

Alternatively, you can combine both approaches if you include SyslogSink in a .cpp file where you also intend to use the LOG_ macros.

However, the first solution is generally preferable, as it lets you take advantage of the more concise LOG_ macros without additional typing.

This configuration class allows you to set various parameters that determine how log messages are mapped and sent to the syslog.

Note

IMPORTANT: Handling Macro Collisions between syslog.h and Quill

Public Functions

inline void set_identifier(std::string const &identifier)

Sets the identifier that is prepended to every syslog message. Typically, this is set to the program name.

Parameters:

identifier – The identifier string.

inline void set_options(int options)

Sets the options to be passed to openlog(). These options control various aspects of syslog behavior.

Parameters:

options – Integer representing syslog options.

inline void set_facility(int facility)

Sets the facility code for syslog. The facility code indicates the type of program logging the message.

Parameters:

facility – Integer representing the syslog facility.

inline void set_format_message(bool format_message)

Enables or disables message formatting. If enabled, the log message will be formatted using the specified PatternFormatter before being sent to syslog.

Parameters:

format_message – Set to true to format the message; false otherwise.

inline void set_log_level_mapping(std::array<int, 12> mapping)

Sets the mapping from quill log levels to syslog levels. This mapping determines which syslog level is used for each quill log level.

Parameters:

mapping – An array of 12 integers representing syslog levels.

inline std::string const &identifier() const noexcept

Getters

SystemdSink Class

class SystemdSink : public quill::Sink

A sink that writes log messages to the system logger (systemd).

This sink leverages the systemd API to send log messages. It uses the configuration provided via SystemdSinkConfig to determine how the messages are formatted and mapped.

Public Functions

inline explicit SystemdSink(SystemdSinkConfig config = SystemdSinkConfig{})

Constructs a SystemdSink with the given configuration. This constructor initializes the systemd connection using openlog().

Parameters:

config – The configuration options for the SystemdSink. Defaults to a default-configured SystemdSinkConfig.

inline void write_log(MacroMetadata const *log_metadata, uint64_t, std::string_view thread_id, std::string_view, std::string const&, std::string_view logger_name, LogLevel log_level, std::string_view, std::string_view, std::vector<std::pair<std::string, std::string>> const*, std::string_view log_message, std::string_view log_statement) override

Writes a formatted log message to the stream.

SystemdSinkConfig Class

class SystemdSinkConfig

Holds the configuration options for the SystemdSink.

When including systemd.h via SystemdSink, the header defines macros such as LOG_INFO and others that conflict with Quill’s LOG_ macros.

To resolve this issue, consider one of the following solutions:

  1. Include SystemdSink in a .cpp file only: Instantiate the SystemdSink in a source file rather than a header file. This ensures that systemd.h is only included in that specific translation unit, avoiding collisions in other files where you want to use the unprefixed Quill LOG_ macros.

  2. Define the preprocessor flag : When this flag is defined, Quill will disable its unprefixed LOG_ macros. Instead, you must use the longer QUILL_LOG_ macros. This approach allows Quill and systemd.h to coexist in the same translation unit.

Alternatively, you can combine both approaches if you include SystemdSink in a .cpp file where you also intend to use the LOG_ macros.

However, the first solution is generally preferable, as it lets you take advantage of the more concise LOG_ macros without additional typing.

This configuration class allows you to set various parameters that determine how log messages are mapped and sent to the systemd.

Note

IMPORTANT: Handling Macro Collisions between systemd.h and Quill

Public Functions

inline void set_identifier(std::string const &identifier)

Sets the identifier that is prepended to every systemd message. Typically, this is set to the program name.

Parameters:

identifier – The identifier string.

inline void set_format_message(bool format_message)

Enables or disables message formatting. If enabled, the log message will be formatted using the specified PatternFormatter before being sent to systemd.

Parameters:

format_message – Set to true to format the message; false otherwise.

inline void set_log_level_mapping(std::array<int, 12> mapping)

Sets the mapping from quill log levels to systemd levels. This mapping determines which systemd level is used for each quill log level.

Parameters:

mapping – An array of 12 integers representing systemd levels.

inline std::string const &identifier() const noexcept

Getters

CsvWriter Class

template<typename TCsvSchema, typename TFrontendOptions>
class CsvWriter

A CSV writer class for asynchronous logging of CSV files.

This class facilitates the asynchronous logging of CSV files, where formatting and I/O operations are handled by the backend worker thread.

The TCsvSchema struct should define the CSV header and format, for example:

struct OrderCsvSchema
{
  static constexpr char const* header = "order_id,symbol,quantity,price,side";
  static constexpr char const* format = "{},{},{},{:.2f},{}";
};
Template Parameters:
  • TCsvSchema – A user-defined struct specifying the CSV schema at compile-time.

  • TFrontendOptions – Custom frontend options if they are used application-wide. If no custom frontend options are used, then use quill::FrontendOptions.

Public Functions

inline explicit CsvWriter(std::string const &filename, char open_mode = 'w', FilenameAppendOption filename_append = FilenameAppendOption::None)

Constructs a CsvWriter object that writes to a file.

Parameters:
  • filename – The name of the CSV file to write to.

  • open_mode – The mode in which to open the file (‘w’ for write, ‘a’ for append).

  • filename_append – Option to append to the filename (None, Date, DateTime).

inline CsvWriter(std::string const &filename, FileSinkConfig sink_config, bool should_write_header = true)

Constructs a CsvWriter object that writes to a file.

Parameters:
  • filename – The name of the CSV file to write to.

  • sink_config – Configuration settings for the file sink.

  • should_write_header – Whether to write the header at the beginning of the CSV file.

inline CsvWriter(std::string const &filename, RotatingFileSinkConfig sink_config, bool should_write_header = true)

Constructs a CsvWriter object that writes to a rotating file.

Parameters:
  • filename – The name of the CSV file to write to.

  • sink_config – Configuration settings for the file sink.

  • should_write_header – Whether to write the header at the beginning of the CSV file.

inline CsvWriter(std::string const &unique_name, std::shared_ptr<Sink> sink, bool should_write_header = true)

Constructs a CsvWriter object that writes to a specified sink.

Parameters:
  • unique_name – A unique name for this CsvWriter instance.

  • sink – The sink to output the data to (e.g., a ConsoleSink or a user-defined Sink).

  • should_write_header – Whether to write the header at the beginning of the CSV file.

inline CsvWriter(std::string const &unique_name, std::vector<std::shared_ptr<Sink>> sinks, bool should_write_header = true)

Constructs a CsvWriter object that writes to multiple sinks.

Parameters:
  • unique_name – A unique name for this CsvWriter instance.

  • sinks – A list of sinks to output the data to.

  • should_write_header – Whether to write the header at the beginning of the CSV file.

inline ~CsvWriter()

Destructor for CsvWriter. Flushes the log and removes the logger.

template<typename ...Args>
inline void append_row(Args&&... fields)

Appends a row to the CSV file. This function is also thread safe.

Parameters:

fields – The fields to append to the CSV row.

inline void write_header()

Writes the csv header

inline void write_header(FILE *file)

Writes the csv header to the specified file

Parameters:

file – file to write

inline void flush()

Flushes the log to ensure all data is written to the file. This method will block the caller thread until the file is flushed, ensuring that all data are flushed to the file.