Loggers¶
Use this page to understand how to create, retrieve, configure, and remove loggers.
Logger instances are created by users with a specified name, along with designated Sinks and a Formatter. Direct instantiation of logger objects is not possible; instead, they must first be created with the desired configurations.
Upon creation, users specify the Sinks and Formatter for the logger. The logger name serves as an identifier, allowing the same logger configuration to be reused without re-specifying Sinks and Formatter settings.
The Logger class is thread-safe.
Note
Due to the asynchronous design of the library, logger parameters are immutable after creation. To modify a logger (such as adding or removing sinks), you must remove it, wait for its removal, and then recreate it with the same name. Additionally, you should update any stored references to the logger*, as the newly created logger will have a different memory address.
Logger Creation¶
auto console_sink = quill::Frontend::create_or_get_sink<quill::ConsoleSink>("sink_id_1");
quill::Logger* logger = quill::Frontend::create_or_get_logger("root", std::move(console_sink));
LOG_INFO(logger, "Hello from {}", "library foo");
Logger Retrieval¶
Loggers can be obtained using FrontendImpl::get_logger(), FrontendImpl::create_or_get_logger(), or FrontendImpl::create_logger().
create_loggercreates a new logger and throwsQuillErrorif the name is already taken.create_or_get_loggercreates a new logger if one does not already exist; otherwise, it returns the existing logger with the specified name. Note that when a logger with the given name already exists, the provided sinks, pattern, clock source, and other configuration parameters are ignored — the existing logger is returned as-is.get_loggerretrieves an existing logger by name.
quill::Logger* logger = quill::Frontend::get_logger("root");
Logger Removal¶
Loggers can be removed using FrontendImpl::remove_logger() or FrontendImpl::remove_logger_blocking(). These functions remove the logger asynchronously. Once a logger is removed, it becomes invalid and must no longer be used by any other thread. The backend ensures that all pending log statements from the logger are processed before final removal. After removal, a logger with the same logger_name can be recreated with different parameters.
FrontendImpl::remove_logger_blocking should only be used while the backend worker is running
after Backend::start(), and must not be called from backend-thread callbacks because it waits
for the backend worker to process the removal.
If you plan to use logger removal functions, ensure that no other threads continue using the logger after calling remove_logger() or FrontendImpl::remove_logger_blocking(). To avoid potential issues, it is recommended to create a separate logger for each application thread, giving each logger a unique logger_name. This ensures that when one thread removes its logger, it does not affect other threads.
When all loggers associated with a particular Sink are removed, the corresponding Sink instances are destroyed, and any associated files are closed automatically.
In many cases, it is sufficient to create a new logger rather than removing an old one. However, logger removal is particularly useful when the underlying sinks need to be destructed and files closed.
For example, if your server creates a logger for each connected TCP session and writes logs to a separate file for each session, removing the logger upon session disconnection ensures that the underlying file is closed — provided no other logger is sharing the same Sink.
Note
While the logger removal functions (FrontendImpl::remove_logger() and FrontendImpl::remove_logger_blocking()) are thread-safe, removing the same logger (`Logger*`) from multiple threads is not allowed. Ensure that a single thread is responsible for removing a particular logger to avoid undefined behavior.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | |
Note
In FileEventNotifier callbacks, use quill::FileEventNotifierHandle for the file
handle parameter. On Windows this is a native HANDLE. On other platforms it is a FILE*.
before_write runs as part of normal log writing. before_open, after_open,
before_close, and after_close run on whichever thread performs the file open/close
operation. Different callbacks, and different invocations of the same callback, may therefore
run on different threads over the sink lifetime. Callbacks must be thread-safe and must not
assume a single calling thread.
Simplifying Logger Usage for Single Root Logger Applications¶
For some applications the use of the single root logger might be enough. In that case, passing the logger every time
to the macro becomes inconvenient. The solution is to store the created Logger as a static variable and create your
own macros. See example.