You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/backend_options.rst
+34-1Lines changed: 34 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -3,10 +3,43 @@
3
3
Backend Options
4
4
===============
5
5
6
-
The backend options allow you to customize the behavior of the backend thread and are applied at runtime. To utilize these options, you need to create an object and pass it when starting the backend thread. Most options come with default values, but they can be tailored to meet the specific needs of your application. Refer to :cpp:struct:`BackendOptions` for detailed information.
6
+
The backend options allow you to customize the behavior of the backend thread and are applied at runtime. To utilize these options, you need to create an object and pass it when starting the backend thread. Most options come with carefully tuned default values for general use, but they can be adjusted to meet the specific performance and latency requirements of your application. Refer to :cpp:struct:`BackendOptions` for detailed information.
7
+
8
+
Example Usage
9
+
-------------
7
10
8
11
For example, to pin the backend worker thread to a specific CPU, you can use the following code:
By default, Quill filters log messages to ensure they contain only printable characters before writing them to sinks. This safety feature converts non-printable characters (including non-ASCII characters like Chinese, Japanese, or other Unicode text) to their hexadecimal representation (e.g., ``\xE4\xB8\xAD`` for Chinese characters).
21
+
22
+
The default printable character range is limited to ASCII characters from space (``' '``) to tilde (``'~'``), plus newline (``'\n'``).
23
+
24
+
**Disabling Character Sanitization for UTF-8 Logging**
25
+
26
+
If you need to log UTF-8 or other non-ASCII text (such as Chinese, etc.), you can disable character sanitization:
Copy file name to clipboardExpand all lines: docs/cheat_sheet.rst
+3-3Lines changed: 3 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -190,7 +190,7 @@ Outputs:
190
190
191
191
Logging Strings Without Additional Copy
192
192
---------------------------------------
193
-
By default, the logger takes a deep copy of any string. To log an immutable string with a valid lifetime without copying, use ``quill::utility::StringRef``.
193
+
By default, the logger takes a deep copy of any string for thread safety. To log an immutable string with a valid lifetime without copying (e.g., string literals, static strings), use ``quill::utility::StringRef``.
194
194
195
195
.. code:: cpp
196
196
@@ -302,7 +302,7 @@ To log user-defined types, you need to define how they should be serialized or c
302
302
- If the type is **not trivially copyable**, it should have both a **copy constructor** and a **move constructor**.
303
303
304
304
2. **Use DirectFormatCodec**
305
-
Suitable for objects that are not safe to copy across threads or for cases where formatting occurs in the slow path. This method converts the object to a string immediately in the hot path using `fmt::format`.
305
+
Suitable for objects that are not safe to copy across threads (e.g., contain raw pointers, references, or non-copyable resources). This method converts the object to a string immediately in the hot path using `fmt::format`, which increases hot-path latency.
306
306
307
307
3. **Implement a Custom Codec**
308
308
For maximum flexibility, you can define a custom codec to specify exactly how the object should be serialized and deserialized.
@@ -480,7 +480,7 @@ Writing Custom Codec
480
480
Serialising Non Trivially Copyable User Defined Types With Public Members
Note that it is possible to pass STL types to ``compute_total_encoded_size``, ``encode_members``, and ``decode_members`` as long as the relevant header file from ``quill/std/`` for that type is included.
483
+
Note that STL types can be used in custom codecs by passing them to ``compute_total_encoded_size``, ``encode_members``, and ``decode_members``, provided you include the relevant header from ``quill/std/`` for each STL type used.
Copy file name to clipboardExpand all lines: docs/filters.rst
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -9,7 +9,7 @@ Each :cpp:class:`Sink` can be associated with one or multiple :cpp:class:`Filter
9
9
10
10
By default, a logger sends all log messages to its ``Sinks``. Filters provide a way to intercept and selectively process log records before they are outputted.
11
11
12
-
A filter is implemented as a callable object that evaluates each log statement and returns a boolean value. This boolean value determines whether the log statement should be forwarded to the ``Sink`` or filtered out.
12
+
A filter is implemented as a callable object that evaluates each log statement on the backend thread and returns a boolean value. When the filter returns ``true``, the log statement is forwarded to the ``Sink``; when ``false``, the log statement is discarded.
These options only affect the ``%(source_location)`` attribute, which shows the full file path. The ``%(short_source_location)`` attribute (filename only + line number) is not affected by these settings.
124
+
125
+
**Custom Function Name Processing**
126
+
127
+
By default, the ``%(caller_function)`` attribute shows basic function names. However, you can enable detailed function signatures by defining ``QUILL_DETAILED_FUNCTION_NAME`` before including Quill headers or as a compiler flag:
128
+
129
+
.. code-block:: cpp
130
+
131
+
#define QUILL_DETAILED_FUNCTION_NAME
132
+
#include "quill/LogMacros.h"
133
+
134
+
// Or compile with: -DQUILL_DETAILED_FUNCTION_NAME
135
+
136
+
When ``QUILL_DETAILED_FUNCTION_NAME`` is enabled, the logger uses compiler-specific macros (like ``__PRETTY_FUNCTION__``) to provide full function signatures including return types, namespaces, class names, and parameter types. Since these detailed signatures can be verbose and compiler-specific, you can provide a custom processing function to format them:
137
+
138
+
.. code-block:: cpp
139
+
140
+
quill::PatternFormatterOptions options;
141
+
142
+
// Custom function to extract just the function name from detailed signatures
// Example: Extract "myFunction" from "void MyClass::myFunction(int, const std::string&)"
145
+
// Implementation depends on your compiler and requirements
146
+
std::string_view name(detailed_name);
147
+
// ... custom parsing logic to extract just the function name ...
148
+
return name;
149
+
};
150
+
151
+
.. note::
152
+
The ``process_function_name`` callback is only used when ``QUILL_DETAILED_FUNCTION_NAME`` is enabled. Without this define, ``%(caller_function)`` shows simple function names and this callback is ignored.
Copy file name to clipboardExpand all lines: docs/frontend_options.rst
+79-3Lines changed: 79 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -3,13 +3,13 @@
3
3
Frontend Options
4
4
================
5
5
6
-
The frontend options provide a flexible way to configure hot path settings. These options are compile timeoptions and allow for the customisation of queue types, as well as the use of huge pages on Linux systems.
6
+
The frontend options provide a flexible way to configure hot path settings at compile time. These options allow for the customisation of queue types and memory allocation strategies, including the use of huge pages on Linux systems for improved performance.
7
7
8
8
Each frontend thread operates with its own queue, which can be configured with one of the following options:
9
9
10
-
- **UnboundedBlocking**: Starts with a small initial capacity. The queue reallocates up to `FrontendOptions::unbounded_queue_max_capacity` and then blocks further log messages.
10
+
- **UnboundedBlocking**: Starts with a small initial capacity. The queue reallocates up to `FrontendOptions::unbounded_queue_max_capacity` and then blocks the calling thread until space becomes available.
11
11
- **UnboundedDropping**: Starts with a small initial capacity. The queue reallocates up to `FrontendOptions::unbounded_queue_max_capacity` and then discards log messages.
12
-
- **BoundedBlocking**: Has a fixed capacity and never reallocates. It blocks log messages when the limit is reached.
12
+
- **BoundedBlocking**: Has a fixed capacity and never reallocates. It blocks the calling thread when the limit is reached until space becomes available.
13
13
- **BoundedDropping**: Has a fixed capacity and never reallocates. It discards log messages when the limit is reached.
14
14
15
15
Even though each thread has its own queue, a single queue type must be defined for the entire application. By default the `UnboundedBlocking` queue type is used.
@@ -18,6 +18,82 @@ To modify the queue type, you should define your own :cpp:struct:`FrontendOption
18
18
19
19
It is important to consistently use your custom types throughout the application, instead of the default ones.
20
20
21
+
Error Notifications
22
+
-------------------
23
+
24
+
The library provides error notifications through the :cpp:member:`BackendOptions::error_notifier` callback:
25
+
26
+
- **Unbounded queues**: Notify when queue reallocations occur
27
+
- **Bounded queues**: Notify when messages are dropped due to full queues, including a count of dropped messages
28
+
29
+
These notifications are processed by the backend thread and can help monitor queue behavior in production.
30
+
31
+
Queue Memory Management
32
+
-----------------------
33
+
34
+
**Queue Shrinking**
35
+
36
+
For unbounded queues, you can explicitly reduce memory usage on specific threads using :cpp:func:`Frontend::shrink_thread_local_queue`. This is particularly useful in thread pool scenarios where some threads may experience logging bursts that cause queue growth, but subsequent tasks don't require the large capacity:
37
+
38
+
.. code-block:: cpp
39
+
40
+
// After a logging-intensive task completes, shrink the queue
41
+
quill::Frontend::shrink_thread_local_queue(512 * 1024); // Shrink to 512KB
42
+
43
+
**Monitoring Queue Allocations**
44
+
45
+
By default, Quill automatically reports queue allocation events to stderr through :cpp:member:`BackendOptions::error_notifier`. You'll see messages like:
46
+
47
+
.. code-block:: shell
48
+
49
+
Allocated a new SPSC queue with a capacity of 256 KiB (previously 128 KiB) from thread 3764
50
+
51
+
These allocation messages are informational, not errors, indicating the queue is dynamically resizing to handle traffic spikes. To customize this behavior, you can override the error notifier:
// Custom handling - log to your preferred destination
58
+
my_logger.info("Quill: {}", error_message);
59
+
}
60
+
};
61
+
62
+
To completely disable these notifications, set the error notifier to an empty function:
63
+
64
+
.. code-block:: cpp
65
+
66
+
quill::BackendOptions backend_options{
67
+
.error_notifier = {} // Disable notifications
68
+
};
69
+
70
+
**Mixed Hot/Cold Path Optimization**
71
+
72
+
For applications with both hot path (performance-critical) and cold path (less frequent) logging threads, you can optimize memory allocation by using a larger initial queue size globally, then selectively shrinking queues on cold path threads:
73
+
74
+
.. code-block:: cpp
75
+
76
+
// Configure large initial capacity to avoid hot path allocations
Copy file name to clipboardExpand all lines: docs/json_logging.rst
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -3,7 +3,7 @@
3
3
JSON Logging
4
4
============
5
5
6
-
The library supports outputting JSON-structured logs to either the console or a file. To utilize this feature, you need to use named arguments within the format string, specifically inside the ``{}`` placeholders, when invoking the ``LOG_`` macros.
6
+
The library supports outputting structured JSON logs to either the console or a file. To utilize this feature, you must use named arguments within the format string placeholders (e.g., ``{name}`` instead of ``{}``) when invoking the ``LOG_`` macros.
7
7
8
8
For convenience, the ``LOGJ_`` macros offer an alternative method for logging l-values, automatically including the argument names in the placeholders. These macros support up to 20 arguments.
Copy file name to clipboardExpand all lines: docs/log_tagging.rst
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -3,7 +3,7 @@
3
3
Log Tagging
4
4
===========
5
5
6
-
In addition to creating multiple `Logger` instances, each with a unique name, which can be used as a runtime tag to filter and search logs using `%(logger)` in the `PatternFormatter` format, you can also add static compile-time tags to your log messages. This enhances your ability to search, monitor, categorize, and understand events in your software.
6
+
In addition to creating multiple `Logger` instances, each with a unique name, you can add static compile-time tags to your log messages. These tags are embedded directly into the log message format at compiletime, providing zero runtime overhead for categorization. This enhances your ability to search, monitor, categorize, and understand events in your software.
7
7
8
8
These static tags are included as hashtag-style keywords within your log messages, making it easier to filter and categorize logs based on these predefined tags.
Copy file name to clipboardExpand all lines: docs/overview.rst
+3-3Lines changed: 3 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -41,11 +41,11 @@ using :cpp:func:`LoggerImpl::flush_log`. The calling thread will **block** until
41
41
Synchronized Logs for Debugging
42
42
-------------------------------
43
43
44
-
Sometimes, synchronized logging is necessary during application debugging. This can be achieved by configuring the logger to invoke :cpp:func:`LoggerImpl::flush_log` with each log statement using the `QUILL_IMMEDIATE_FLUSH` preprocessor variable.
44
+
Sometimes, synchronized logging is necessary during application debugging. This can be achieved by calling :cpp:func:`LoggerImpl::set_immediate_flush` to enable immediate flushing for a specific logger instance.
45
45
46
-
Enabling `QUILL_IMMEDIATE_FLUSH` causes the calling thread to pause until the log is processed and written to the log file by the backend thread before proceeding, which may have a notable impact on performance.
46
+
This causes the calling thread to pause until the log is processed and written to the log file by the backend thread before proceeding, which may have a notable impact on performance.
47
47
48
-
To enable this behavior, define `QUILL_IMMEDIATE_FLUSH` before including `LogMacros.h` or pass it as a compiler flag.
48
+
Note that the immediate flush feature can be completely disabled at compile time by defining `QUILL_ENABLE_IMMEDIATE_FLUSH=0`, which eliminates the conditional branch from the hot path for better performance when immediate flushing is never needed.
Copy file name to clipboardExpand all lines: docs/quick_start.rst
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -5,9 +5,9 @@ Quick Start
5
5
6
6
The library is header only and consists of two main components: the frontend and the backend.
7
7
8
-
The **frontend** captures a copy of the log arguments and metadata from each ``LOG_*`` statement and places them in a thread-local SPSC queue buffer.
8
+
The **frontend** captures a copy of the log arguments and metadata from each ``LOG_*`` statement and places them in a thread-local SPSC (Single Producer Single Consumer) queue buffer. Each frontend thread has its own lock-free queue, ensuring no contention between logging threads.
9
9
10
-
The **backend** runs in a separate thread, spawned by the library, asynchronously consuming messages from the frontend, formatting them, and writing them to the configured sinks.
10
+
The **backend** runs in a separate thread, spawned by the library, asynchronously consuming messages from all frontend queues, formatting them, and writing them to the configured sinks.
11
11
12
12
To use the library, you need to start the backend thread in your application. Then, set up one or more output ``Sinks`` and a ``Logger``.
Copy file name to clipboardExpand all lines: docs/sink_types.rst
+20Lines changed: 20 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -49,6 +49,26 @@ SyslogSink
49
49
50
50
The :cpp:class:`SyslogSink` leverages the syslog API to send messages.
51
51
52
+
SystemdSink
53
+
~~~~~~~~~~~
54
+
55
+
The :cpp:class:`SystemdSink` sends log messages to systemd's journal using the systemd journal API, providing structured logging with systemd metadata.
56
+
57
+
StreamSink
58
+
~~~~~~~~~~
59
+
60
+
The :cpp:class:`StreamSink` allows logging to any output stream derived from `std::ostream`, providing flexibility for custom output destinations.
61
+
62
+
AndroidSink
63
+
~~~~~~~~~~~
64
+
65
+
The :cpp:class:`AndroidSink` sends log messages to the Android logging system using the Android NDK logging API.
66
+
67
+
NullSink
68
+
~~~~~~~~
69
+
70
+
The :cpp:class:`NullSink` discards all log messages, useful for performance testing or disabling specific logger output without removing logging calls.
71
+
52
72
.. note:: Macro Collision Notice
53
73
54
74
When including ``syslog.h`` via :cpp:class:`SyslogSink`, the header defines macros such as ``LOG_INFO``
0 commit comments