quill
|
Configuration options for the backend. More...
#include <BackendOptions.h>
Public Attributes | |
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. More... | |
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. More... | |
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. More... | |
size_t | transit_events_hard_limit = 32'768 |
The backend gives priority to reading messages from the frontend queues and temporarily buffers them. More... | |
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. More... | |
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. More... | |
uint16_t | cpu_affinity = (std::numeric_limits<uint16_t>::max)() |
Pins the backend to the specified CPU. More... | |
std::function< void(std::string const &)> | error_notifier |
The backend may encounter exceptions that cannot be caught within user threads. More... | |
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. More... | |
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. More... | |
std::function< bool(char c)> | check_printable_char |
This option enables a check that verifies the log message contains only printable characters before forwarding it to the sinks. More... | |
std::array< std::string, 11 > | log_level_descriptions |
Holds descriptive names for various log levels used in logging operations. More... | |
std::array< std::string, 11 > | log_level_short_codes |
Short codes or identifiers for each log level. More... | |
bool | check_backend_singleton_instance = true |
Enables a runtime check to detect multiple instances of the backend singleton. More... | |
Configuration options for the backend.
This struct defines settings for the backend thread
bool BackendOptions::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.
std::function<bool(char c)> BackendOptions::check_printable_char |
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 = {}
uint16_t BackendOptions::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.
bool BackendOptions::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::function<void(std::string const&)> BackendOptions::error_notifier |
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::array<std::string, 11> BackendOptions::log_level_descriptions |
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, 11> BackendOptions::log_level_short_codes |
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.
std::chrono::microseconds BackendOptions::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:
now()
and subtracts the grace period, reads queues up to the adjusted now()
, and writes the logs.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.
std::chrono::milliseconds BackendOptions::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 BackendOptions::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.
uint32_t BackendOptions::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 BackendOptions::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.
size_t BackendOptions::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.
bool BackendOptions::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.