Skip to content

Commit 00b3532

Browse files
committed
update docs
1 parent ff6d78d commit 00b3532

12 files changed

+240
-21
lines changed

docs/backend_options.rst

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,43 @@
33
Backend Options
44
===============
55

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+
-------------
710

811
For example, to pin the backend worker thread to a specific CPU, you can use the following code:
912

1013
.. literalinclude:: examples/quill_docs_example_backend_options.cpp
1114
:language: cpp
1215
:linenos:
16+
17+
Character Sanitization
18+
-----------------------
19+
20+
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:
27+
28+
.. code-block:: cpp
29+
30+
quill::BackendOptions backend_options;
31+
backend_options.check_printable_char = {}; // Disable sanitization
32+
quill::Backend::start(backend_options);
33+
34+
**Custom Character Filtering**
35+
36+
You can also define custom printable character rules:
37+
38+
.. code-block:: cpp
39+
40+
quill::BackendOptions backend_options;
41+
backend_options.check_printable_char = [](char c) {
42+
// Allow ASCII printable + newline + common UTF-8 byte ranges
43+
return (c >= ' ' && c <= '~') || (c == '\n') || (static_cast<unsigned char>(c) >= 128);
44+
};
45+
quill::Backend::start(backend_options);

docs/cheat_sheet.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ Outputs:
190190

191191
Logging Strings Without Additional Copy
192192
---------------------------------------
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``.
194194

195195
.. code:: cpp
196196
@@ -302,7 +302,7 @@ To log user-defined types, you need to define how they should be serialized or c
302302
- If the type is **not trivially copyable**, it should have both a **copy constructor** and a **move constructor**.
303303

304304
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.
306306

307307
3. **Implement a Custom Codec**
308308
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
480480
Serialising Non Trivially Copyable User Defined Types With Public Members
481481
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
482482

483-
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.
484484

485485
.. code:: cpp
486486

docs/filters.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Each :cpp:class:`Sink` can be associated with one or multiple :cpp:class:`Filter
99

1010
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.
1111

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.
1313

1414
Filtering Logs with the Built-In Filter
1515
---------------------------------------

docs/formatters.rst

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,4 +96,90 @@ Customizing Log Message Formats
9696

9797
.. literalinclude:: examples/quill_docs_example_custom_format.cpp
9898
:language: cpp
99-
:linenos:
99+
:linenos:
100+
101+
Advanced Pattern Formatter Configuration
102+
-----------------------------------------
103+
104+
The :cpp:class:`PatternFormatterOptions` class provides additional configuration options beyond the basic format pattern:
105+
106+
**Source Location Path Customization**
107+
108+
You can customize how source file paths are displayed when using the ``%(source_location)`` attribute (full path + line number):
109+
110+
.. code-block:: cpp
111+
112+
quill::PatternFormatterOptions options;
113+
114+
// Strip common path prefixes to shorten source locations
115+
options.source_location_path_strip_prefix = "/home/user/project/";
116+
// "/home/user/project/src/main.cpp:42" becomes "src/main.cpp:42"
117+
118+
// Remove relative path components like "../"
119+
options.source_location_remove_relative_paths = true;
120+
// "../../src/utils/../main.cpp:15" becomes "src/main.cpp:15"
121+
122+
.. note::
123+
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
143+
options.process_function_name = [](const char* detailed_name) -> std::string_view {
144+
// 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.
153+
154+
**Timestamp Configuration**
155+
156+
Control timestamp timezone and format:
157+
158+
.. code-block:: cpp
159+
160+
quill::PatternFormatterOptions options;
161+
162+
// Use GMT timezone instead of local time
163+
options.timestamp_timezone = quill::Timezone::GmtTime;
164+
165+
// Customize timestamp format (same as strftime + fractional specifiers)
166+
options.timestamp_pattern = "%Y-%m-%d %H:%M:%S.%Qms"; // Include date and milliseconds
167+
168+
**Multi-line Message Handling**
169+
170+
Control whether metadata is added to each line of multi-line log messages:
171+
172+
.. code-block:: cpp
173+
174+
quill::PatternFormatterOptions options;
175+
176+
// Disable metadata on continuation lines for cleaner multi-line output
177+
options.add_metadata_to_multi_line_logs = false;
178+
179+
// With add_metadata_to_multi_line_logs = true (default):
180+
// 2024-01-15 10:30:45.123 [1234] main.cpp:42 LOG_INFO MyLogger Line 1
181+
// 2024-01-15 10:30:45.123 [1234] main.cpp:42 LOG_INFO MyLogger Line 2
182+
183+
// With add_metadata_to_multi_line_logs = false:
184+
// 2024-01-15 10:30:45.123 [1234] main.cpp:42 LOG_INFO MyLogger Line 1
185+
// Line 2

docs/frontend_options.rst

Lines changed: 79 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33
Frontend Options
44
================
55

6-
The frontend options provide a flexible way to configure hot path settings. These options are compile time options 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.
77

88
Each frontend thread operates with its own queue, which can be configured with one of the following options:
99

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.
1111
- **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.
1313
- **BoundedDropping**: Has a fixed capacity and never reallocates. It discards log messages when the limit is reached.
1414

1515
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
1818

1919
It is important to consistently use your custom types throughout the application, instead of the default ones.
2020

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:
52+
53+
.. code-block:: cpp
54+
55+
quill::BackendOptions backend_options{
56+
.error_notifier = [](const std::string& error_message) {
57+
// 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
77+
struct MyFrontendOptions : quill::FrontendOptions
78+
{
79+
static constexpr size_t initial_queue_capacity = 64 * 1024 * 1024; // 64MB
80+
// ... other options
81+
};
82+
83+
// Hot path threads: Use the large queue (no shrinking needed)
84+
// LOG_INFO(hot_path_logger, "High frequency logging...");
85+
86+
// Cold path threads: Shrink to smaller size after initialization
87+
void cold_path_thread_init() {
88+
quill::Frontend::shrink_thread_local_queue(128 * 1024); // Shrink to 128KB
89+
// LOG_INFO(cold_path_logger, "Infrequent logging...");
90+
}
91+
92+
This approach prevents runtime allocations on performance-critical threads while conserving memory on threads with lighter logging workloads.
93+
94+
Example Usage
95+
-------------
96+
2197
For example, to use a `BoundedDropping` queue with a fixed capacity of `131'072`, you can follow the steps below:
2298

2399
.. literalinclude:: ../examples/custom_frontend_options.cpp

docs/json_logging.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
JSON Logging
44
============
55

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.
77

88
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.
99

docs/log_tagging.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
Log Tagging
44
===========
55

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 compile time, providing zero runtime overhead for categorization. This enhances your ability to search, monitor, categorize, and understand events in your software.
77

88
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.
99

docs/overview.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,11 @@ using :cpp:func:`LoggerImpl::flush_log`. The calling thread will **block** until
4141
Synchronized Logs for Debugging
4242
-------------------------------
4343

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.
4545

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.
4747

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.
4949

5050
Handling Application Crashes
5151
----------------------------

docs/quick_start.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ Quick Start
55

66
The library is header only and consists of two main components: the frontend and the backend.
77

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.
99

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.
1111

1212
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``.
1313

docs/sink_types.rst

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,26 @@ SyslogSink
4949

5050
The :cpp:class:`SyslogSink` leverages the syslog API to send messages.
5151

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+
5272
.. note:: Macro Collision Notice
5373

5474
When including ``syslog.h`` via :cpp:class:`SyslogSink`, the header defines macros such as ``LOG_INFO``

0 commit comments

Comments
 (0)