- v11.1.0
- v11.0.2
- v11.0.1
- v11.0.0
- v10.2.0
- v10.1.0
- v10.0.1
- v10.0.0
- v9.0.3
- v9.0.2
- v9.0.1
- v9.0.0
- v8.2.0
- v8.1.1
- v8.1.0
- v8.0.0
- v7.5.0
- v7.4.0
- v7.3.0
- v7.2.2
- v7.2.1
- v7.2.0
- v7.1.0
- v7.0.0
- v6.1.2
- v6.1.1
- v6.1.0
- v6.0.0
- v5.1.0
- v5.0.0
- v4.5.0
- v4.4.1
- v4.4.0
- v4.3.0
- v4.2.1
- v4.2.0
- v4.1.0
- v4.0.0
- v3.9.0
- v3.8.0
- v3.7.0
- v3.6.0
- v3.5.1
- v3.5.0
- v3.4.1
- v3.4.0
- v3.3.1
- v3.3.0
- v3.2.0
- v3.1.0
- v3.0.2
- v3.0.1
- v3.0.0
- v2.9.2
- v2.9.1
- v2.9.0
- v2.8.0
- v2.7.0
- v2.6.0
- v2.5.1
- v2.5.0
- v2.4.2
- v2.4.1
- v2.4.0
- v2.3.4
- v2.3.3
- v2.3.2
- v2.3.1
- v2.3.0
- v2.2.0
- v2.1.0
- v2.0.2
- v2.0.1
- v2.0.0
- v1.7.3
- v1.7.2
- v1.7.1
- v1.7.0
- v1.6.3
- v1.6.2
- v1.6.1
- v1.6.0
- v1.5.2
- v1.5.1
- v1.5.0
- v1.4.1
- v1.4.0
- v1.3.3
- v1.3.2
- v1.3.1
- v1.3.0
- v1.2.3
- v1.2.2
- v1.2.1
- v1.2.0
- v1.1.0
- v1.0.0
- Fixed a signal handler shutdown issue where crashes after
Backend::stop()could hang while trying toflush()through a stopped backend worker. (#906) - Fixed duplicate
atexithandler registration on repeatedBackend::start()/Backend::stop()cycles.
- Fixed thread-local context duplication across shared libraries (#890)
- Added a
nullptrcheck in macro-free log functions (LogFunctions.h) to allow calls with an uninitialized logger. Macro-based logging remains deliberately unchanged (#894) - Suppress GCC false-positive warnings during LTO builds.
- Added backend worker poll loop hooks
backend_worker_on_poll_begin/backend_worker_on_poll_end(#897) - Added opt-in sequential thread IDs via
QUILL_USE_SEQUENTIAL_THREAD_IDwithQUILL_DEFINE_SEQUENTIAL_THREAD_ID(#898)
- Fixed UBSAN warning when logging empty
std::string_view(#885) - Updated
ConsoleSinkconstructor to accept an optionalFileEventNotifierparameter for consistency with other sinks (#886)
- Fix
BacktraceStorageindexreset to preventSIGSEGVwhen usingLOG_BACKTRACE
- Update bundled
libfmttov12.1.0 - Minor correction to
_last_sink_flush_time updatewhenfflush()fails - Added retry logic and shared access handling for file open and rotation on Windows
- Use
::WriteFileinstead offwriteto prevent\r\r\nline endings on Windows - Avoid file descriptor leaks by setting
O_CLOEXECon Unix andHANDLE_FLAG_INHERITon Windows - Added
SimpleSetup.hconvenience header for trivial program cases to easily setup a logger. For example#include "quill/SimpleSetup.h" #include "quill/LogMacros.h" int main() { auto* logger = quill::simple_logger(); LOG_INFO(logger, "Hello from {}!", "Quill"); auto* logger2 = quill::simple_logger("test.log"); LOG_INFO(logger2, "This message goes to a file"); }
- Fixed argument forwarding when encoding user-defined types with
DeferredFormatCodecor STL containers to properly handle rvalue references. For example, the following move-only type will now work correctly:class MoveOnlyType { public: MoveOnlyType(std::string name, std::string value, uint32_t count) : name(std::move(name)), value(std::move(value)), count(count) {} MoveOnlyType(MoveOnlyType&&) = default; MoveOnlyType(MoveOnlyType const&) = delete; std::string name; std::string value; uint32_t count; }; template <> struct fmtquill::formatter<MoveOnlyType> { constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } auto format(MoveOnlyType const& obj, format_context& ctx) const { return fmtquill::format_to(ctx.out(), "MoveOnlyType(name: {}, value: {}, count: {})", obj.name, obj.value, obj.count); } }; template <> struct quill::Codec<MoveOnlyType> : quill::DeferredFormatCodec<MoveOnlyType> {}; MoveOnlyType obj{"Test", "Value1", 42}; LOG_INFO(logger, "obj: {}", std::move(obj)); // Properly forwards and moves
- Added fuzzing tests to CI to catch memory and undefined behavior issues
- Fixed
PatternFormatterautomatic newline appending by making the suffix ('\n') configurable or optionally disabled viaPatternFormatterOptions - Fixed segmentation fault when
DirectFormatCodecwas used with enums types (#848) - Fixed segmentation fault when
DirectFormatCodecwas used with STL containers of enums - Fixed a compiler error when
LOG_DYNAMICis used withQUILL_DISABLE_FILE_INFO(#847) - Fixed process ID capture in
BackendWorkerto supportfork()correctly (#860) - Fixed undefined behavior caused by passing
nullptrtomemcpywhen encoding emptystd::vector - Updated
BackendOptions::check_printable_charto allow tab (\t) and carriage return (\r) characters by default (#856) - Increased
RdtscClockresync lag thresholds to improve cross-system compatibility - Added
QUILL_ENABLE_ASSERTIONSCMake option and preprocessor flag to enable assertions in release builds - Allow
RotatingSinkto rotate the file on creation withrotation_on_creation() - Improved
SignalHandlerOptionsconfigurability by replacing hardcoded logger exclusion string withexcluded_logger_substringsoption - Silence MSVC warnings (4324, 4996) in source code instead of CMake
- Fixed potential conflicts by adding unique prefixes to internal macro variables to prevent conflicts with user variable names in the same scope. (#799)
- Fixed potential
UBSanwarnings by adding overflow check when doubling resync interval inRdtscClock::resync()(#809) - Minor improvements in
Utility::to_hexfunction andStringFromTime - Fixed an issue where
BackendWorker::_exitwas always executed during destruction, even when the backend thread had already stopped (#815) - Fixed
RotatingFileSinkto correctly handleFilenameAppendOption::StartDateconfiguration (#822) - Fixed unnecessary allocation caused by empty
std::vectorwhileBackendWorkeris idle on Windows (#827) - Fixed
FileSink::open_modestring comparison for file mode flags - Adjusted default
BackendOptionsvalues for broader system compatibility and typical usage patterns
- Fixed PatternFormatter test to work with any repository name instead of hardcoded
quill(#795) - Fixed Windows compiler warnings when clang-cl >= 19 is used
-
There is a new macro-free mode that allows logging without macros. You have two options: either
#include "quill/LogMacros.h"or#include "quill/LogFunctions.h". The macro mode still remains the recommended and main method for logging. The new macro-free log has higher overhead than using macros. To use the macro-free mode, for example:quill::debug(logger, "A {} message with number {}", "test", 123);
See macro-free mode documentation here for details.
-
Added
BinaryDataDeferredFormatCodecfor efficient binary data logging. This codec allows efficient logging of variable-sized binary data by copying the raw bytes on the hot path and deferring the formatting to the backend thread. This is particularly useful for logging binary protocol messages (like SBE or custom binary formats), network packets, and raw binary data without impacting application performance. See the example sbe_logging and binary_protocol_logging for details. For documentation, see here. -
The immediate flush feature has been enhanced to support interval-based flushing and moved to runtime. This feature helps with debugging by ensuring log statements are flushed to the sink, blocking the caller thread. (#660)
-
Added
source_location_path_strip_prefixoption inPatternFormatterOptionsto customize the display of the%(source_location)attribute ofPatternFormatter. When set, any paths that contain this prefix will have the prefix and everything before it stripped from the displayed path. For example, with prefix "projects", a source location like "/home/user/projects/app/main.cpp:5" would be displayed as "app/main.cpp: 5". (#772) -
Added
source_location_remove_relative_pathsoption inPatternFormatterOptionsto remove relative path components from the%(source_location)attribute ofPatternFormatter. When enabled, relative path components like "../" are processed and removed, simplifying paths from__FILE__which might contain relative paths like "../../../test/main.cpp". (#778) -
Added the
QUILL_DISABLE_FILE_INFOpreprocessor flag and CMake option.
This disables__FILE__and__LINE__information in log statements at compile time when location-related patterns (%(file_name),%(line_number),%(short_source_location),%(source_location)) are not needed in thePatternFormatter. This removes embedded source path strings from built binaries from the security viewpoint. -
Added the
QUILL_DETAILED_FUNCTION_NAMECMake option. When enabled, this option uses compiler-specific detailed function signatures (such as__PRETTY_FUNCTION__on GCC/Clang or__FUNCSIG__on MSVC) instead of the standard__FUNCTION__in log macros. This provides more complete function information, including return types, namespaces, and parameter types. This option is only relevant when%(caller_function)is used in the pattern formatter. (#785) -
Added
process_function_namecustomisation point inPatternFormatterOptions. This function allows custom processing of the function signature before it's displayed in logs. This makes more sense to use whenQUILL_DETAILED_FUNCTION_NAMEis used. This provides flexibility to trim, format, or otherwise modify function signatures to improve readability in log output when using the%(caller_function)pattern. (#785) -
Added helper macros for easy logging of user-defined types. Two new macros are available in
quill/HelperMacros.h:QUILL_LOGGABLE_DIRECT_FORMAT(Type): For types that contain pointers or have lifetime dependenciesQUILL_LOGGABLE_DEFERRED_FORMAT(Type): For types that only contain value types and are safe to copy
Note that these macros require you to provide either an
operator<<for your type and they are just shortcuts to existing functionality. (#777)Example usage:
class User { /* ... */ }; std::ostream& operator<<(std::ostream& os, User const& user) { /* ... */ } // For types with pointers - will format immediately QUILL_LOGGABLE_DIRECT_FORMAT(User) class Product { /* ... */ }; std::ostream& operator<<(std::ostream& os, Product const& product) { /* ... */ } // For types with only value members - can format asynchronously QUILL_LOGGABLE_DEFERRED_FORMAT(Product)
-
Internally, refactored how runtime metadata are handled for more flexibility, providing three macros for logging with runtime metadata:
QUILL_LOG_RUNTIME_METADATA_DEEP- Takes a deep copy offmt,file,functionandtags. Most flexible option, useful for forwarding logs from another logging library.QUILL_LOG_RUNTIME_METADATA_HYBRID- Will take a deep copy offmtandtagsand will takefileandfunctionas reference. This is used for the new macro-free mode.QUILL_LOG_RUNTIME_METADATA_SHALLOW- Will take everything as reference. This is used when logging with compile-time metadata and using, for example, a dynamic log-level such asLOG_DYNAMIC.
-
When using a sink with overridden
PatternFormatterOptions, the optionadd_metadata_to_multi_line_logswill now be correctly applied at the Sink level. Previously, this option was only available and effective at the Logger levelPatternFormatter. -
When a Sink with override
PatternFormatterOptionsis used and if no other sink exists using theLoggerPatternFormatterOptions, then the backend thread will no longer perform a redundant format log statement. -
When using a sink with overridden
PatternFormatterOptions, thelog_statementthat is passed to theFilter::filter()will now be formatted based on the overridden options instead of using theLoggerPatternFormatterOptions. -
Update bundled
libfmttov11.2.0
-
If you were previously setting
QUILL_ENABLE_IMMEDIATE_FLUSHto1, this functionality has been moved to runtime with more flexibility. Instead of using a boolean flag, you can now specify the flush interval by callinglogger->set_immediate_flush(flush_every_n_messages)on each logger instance. Set it to1for per-message flushing, or to a higher value to flush after that many messages. Setting it to0disables flushing which is the default behaviour.QUILL_ENABLE_IMMEDIATE_FLUSHstill exists as a compile-time preprocessor flag and is set to1by default. SettingQUILL_ENABLE_IMMEDIATE_FLUSH 0in the preprocessor will eliminate theifbranch from the hot path and disable this feature entirely, regardless of the value passed toset_immediate_flush(flush_every_n_messages). -
The
QUILL_LOG_RUNTIME_METADATAmacro requiresfile,functionandfmtto be passed aschar const*andline_numberasuint32_t. This is a breaking change from the previous version.
- Add support for
void*formatting (#759) - Fix a bug in
RotatingJsonFileSink.hwhere file size-based rotation wasn't triggering properly (#767) - Fix false positive
-Wstringop-overreadwarning in GCC (#766)
- Add missing namespace in
QUILL_LOG_RUNTIME_METADATA(#743)
- Fix crash when
LOG_BACKTRACEis used (#744) - Add missing namespace in
QUILL_LOG_RUNTIME_METADATA(#743) - Check for
nullptrLogger*before setting log level viaQUILL_LOG_LEVELenvironment variable (#749) - Change default mode of
FileSinkfopentoato avoid overwriting existing files
- Replaced the
bool huge_pages_enabledflag inFrontendOptionswithquill::HugePagesPolicy huge_pages_policyenum, allowing huge page allocation to be attempted with a fallback to normal pages if unavailable. If you are using a customFrontendOptionstype, you will need to update it to use the new flag. (#707) - Previously,
QueueType::UnboundedDroppingandQueueType::UnboundedBlockingcould grow up to 2 GB in size. This limit is now configurable viaFrontendOptions::unbounded_queue_max_capacity, which defaults to 2 GB. QueueType::UnboundedUnlimitedhas been removed, as the same behavior can now be achieved by settingFrontendOptions::unbounded_queue_max_capacityto the maximum value.- The
ConsoleSinkconstructor now optionally accepts aConsoleSinkConfig, similar to other sinks. If noConsoleSinkConfigis provided, a default one is used, logging tostdoutwithColourMode::Automatic. For example:Frontend::create_or_get_sink<ConsoleSink>("console_sink", []() { ConsoleSinkConfig config; config.set_colour_mode(ConsoleSinkConfig::ColourMode::Never); config.set_stream("stderr"); return config; }());
-
The default log level for each
Loggercan now be configured using the environment variableQUILL_LOG_LEVEL. Supported values:"tracel3","tracel2","tracel1","debug","info","notice","warning","error","critical","none". When set, the logger is initialized with the corresponding log level. Iflogger->set_log_level(level)is explicitly called in code, it will override the log level set via the environment variable. -
Added the
LOG_RUNTIME_METADATA(logger, log_level, file, line_number, function, fmt, ...)macro.
This enables passing runtime metadata (such as file, line number, and function) along with a log message,
providing greater flexibility when forwarding logs from other logging libraries. (#696)LOG_RUNTIME_METADATA(logger, quill::LogLevel::Info, "main.cpp", 20, "foo()", "Hello number {}", 8);
-
Added a runtime check to detect duplicate backend worker threads caused by inconsistent linkage
(e.g., mixing static and shared libraries). If needed, this check can be disabled using the
check_backend_singleton_instanceflag inBackendOptions. (#687) -
Added the
QUILL_DISABLE_FUNCTION_NAMEpreprocessor flag and CMake option.
This allows disabling__FUNCTION__inLOG_*macros when%(caller_function)is not used inPatternFormatter,
eliminating Clang-Tidy warnings when logging inside lambdas. -
It is now possible to override a logger's
PatternFormatteron a per-sink basis. This allows the same logger to output different formats for different sinks. Previously, achieving this required creating a custom sink type, but this functionality is now built-in. See the example: sink_formatter_override. -
Added
Frontend::remove_logger_blocking(...), which blocks the caller thread until the specified logger is fully removed. -
Added
Frontend::shrink_thread_local_queue(capacity)andFrontend::get_thread_local_queue_capacity(). These functions allow dynamic management of thread-local SPSC queues when using an unbounded queue configuration. They enable on-demand shrinking of a queue that has grown due to bursty logging, helping to reduce memory usage, although in typical scenarios they won't be required. -
Added the
SyslogSink, which logs messages to the system's syslog.auto sink = quill::Frontend::create_or_get_sink<quill::SyslogSink>( "app", []() { quill::SyslogSinkConfig config; config.set_identifier("app"); return config; }());
-
Added the
SystemdSink, which logs messages to systemd.auto sink = quill::Frontend::create_or_get_sink<quill::SystemdSink>( "app", []() { quill::SystemdSinkConfig config; config.set_identifier("app"); return config; }());
-
Added the
AndroidSink, which integrates with Android's logging system.auto sink = quill::Frontend::create_or_get_sink<quill::AndroidSink>( "s1", []() { quill::AndroidSinkConfig config; config.set_tag("app"); config.set_format_message(true); return config; }());
-
Updated bundled
libfmtto11.1.4. -
When
add_metadata_to_multi_line_logsin thePatternFormatterwas set to false, fixed a bug where the last character of the log message was dropped and added protection for empty messages. -
Updated
LOG_EVERY_Nmacros to log on the first occurrence (0th call) instead of waiting until the Nth call. -
Added a
nullptrcheck forchar*andconst char*during encoding, ensuring the library handlesnullptrvalues gracefully (#735) -
The
CsvWritercould previously be used withRotatingFileSinkvia the constructor that accepted
std::shared_ptr<Sink>, but rotated files did not include the CSV header.
This has now been improved—when using the new constructor that acceptsquill::RotatingFileSinkConfig,
the CSV header is written at the start of each new rotated file. (#700)quill::RotatingFileSinkConfig sink_config; sink_config.set_open_mode('w'); sink_config.set_filename_append_option(FilenameAppendOption::None); sink_config.set_rotation_max_file_size(512); sink_config.set_rotation_naming_scheme(RotatingFileSinkConfig::RotationNamingScheme::Index); quill::CsvWriter<OrderCsvSchema, quill::FrontendOptions> csv_writer{"orders.csv", sink_config}; for (size_t i = 0; i < 40; ++i) { csv_writer.append_row(132121122 + i, "AAPL", i, 100.1, "BUY"); }
-
When using
CsvWriterwithopen_mode == 'a', the header will no longer be rewritten if the file already exists. -
On Linux, setting a long backend thread name now truncates it instead of failing. (#691)
-
Fixed BSD builds. (#688)
-
Added adaptive termination for stable measurements in
rdtsccalibration during init -
Fixed
QUILL_ATTRIBUTE_HOTandQUILL_ATTRIBUTE_COLDclang detection -
CMake improvements: switched to range syntax for minimum required version and bumped minimum required CMake version to
3.12. (#686) -
Correct the installation location of pkg-config files. They are now properly placed in
/usr/local/lib. (#715) -
Removed deprecated
TriviallyCopyableTypeCodec
-
Added
DeferredFormatCodecandDirectFormatCodecfor easier logging of user-defined types and smoother migration from pre-v4versions. Previously, users had to define a customCodecfor every non-trivially copyable user-defined type they wanted to log.template <> struct quill::Codec<UserTypeA> : quill::DeferredFormatCodec<UserTypeA> { }; template <> struct quill::Codec<UserTypeB> : quill::DirectFormatCodec<UserTypeB> { };
DeferredFormatCodecnow supports both trivially and non-trivially copyable types:- For trivially copyable types, it behaves the same as
TriviallyCopyableTypeCodec. - For non-trivially copyable types, it works similarly to pre-
v4by taking a copy of the object using the copy constructor and placement new.
- For trivially copyable types, it behaves the same as
DirectFormatCodecformats the object immediately in the hot path, serving as a shortcut to explicitly formatting the object when logging.- For advanced use cases, a custom
Codeccan still be defined for finer control over encoding/decoding.
See:
-
Added codec support for C-style arrays of user-defined types in
std/Array.h -
Fixed warnings:
-Wimplicit-int-float-conversion,-Wfloat-equal, and-Wdocumentation. -
Marked
TriviallyCopyableTypeCodecas deprecated.DeferredFormatCodecshould be used instead, requiring no further changes. -
Raised minimum
CMakerequired version from3.8to3.10to avoid deprecation warnings.
- Updated bazel
rules_ccto0.1.1(#664)
- Updated bundled
libfmtto11.1.3 - Suppressed clang-19 warning when building the tests with C++17. (#646)
- Fixed windows linkage error when shared library is used.
- Fixed redefinition of
struct fmt_detail::time_zoneerror (#649)
-
Unified
JsonFileSink.handJsonConsoleSink.hinto a single header,JsonSink.h, with both classes now sharing a common implementation -
Users can now inherit from
JsonFileSinkorJsonConsoleSinkand override thegenerate_json_message(...)function to implement their own custom JSON log formats -
Removed
JsonFileSinkConfig. Please rename it toFileSinkConfig, which retains the same API and is fully compatible. -
Added
RotatingJsonFileSink. Functions likeRotatingFileSink, but specifically designed for rotating JSON log files. (#637) -
Simplified
ConsoleSinkby applying ANSI colour codes universally across all platforms, including Windows. The previous Windows-specific implementation has been removed. Note thatquill::ConsoleColourshas been replaced withquill::ConsoleSink::Colours, andquill::ConsoleColours::ColourModehas been renamed toquill::ConsoleSink::ColourMode. -
Changed class member visibility in
FileSink,JsonSink, andRotatingSinkfrom private to protected, enabling easier customization through inheritance for user-defined implementations. -
Added a new
sink_min_flush_intervaloption inBackendOptions, which specifies the minimum time interval (in milliseconds) before the backend thread flushes the output buffers callingflush_sink()for all sinks, with a default value of 200ms; The backend thread ensures sinks aren't flushed more frequently than this interval, while explicit calls tologger->flush_log()trigger an immediate flush, and flushing may occur less frequently if the backend thread is busy, with this setting applying globally to all sinks. Setting this value to 0 disables the feature. (#641) -
Updated bundled
libfmtto11.1.2 -
Added a
StopWatchutility for easy logging of elapsed time. It can log the time elapsed since construction in various formats. You can use eitherquill::StopWatchTscfor high-resolution TSC-based timing orquill::StopWatchChronofor standard std::chrono-based timing. (#640)For example:
#include "quill/StopWatch.h" quill::StopWatchTsc swt; std::this_thread::sleep_for(std::chrono::seconds(1)); LOG_INFO(logger, "After 1s, elapsed: {:.6}s", swt); // => After 1s, elapsed: 1.00849s std::this_thread::sleep_for(std::chrono::milliseconds(500)); LOG_INFO(logger, "After 500ms, elapsed: {}s", swt); // => After 500ms, elapsed: 1.521880274s LOG_INFO(logger, "elapsed: {}", swt.elapsed_as<std::chrono::nanoseconds>()); // => elapsed: 1521807324ns
-
Suppress
-Wredundant-declswarning in GCC builds. -
Remove
-Wno-gnu-zero-variadic-macro-argumentsfor GCC in CMake.
-
In previous versions, logging on Windows automatically included
windows.hin all components. The frontend will no longer includewindows.h. By following the recommended usage example provided here as guidance, you can create a wrapper library around Quill for the backend, allowing you to log on Windows without includingwindows.hin the frontend or main program. (#618) -
The
LOG_LEVEL_LIMITtime-based rate-limiting macros now log the count of how many times a message would be logged when throttled. For example, a log message may appear asA log message with number 123 (21x)to indicate that the message would have been logged 21 times. (#616) -
New macros
LOG_LEVEL_LIMIT_EVERY_Nhave been added, allowing for count-based rate limiting and giving developers greater control over logging frequency. (#616) -
Renamed
PACKEDused inlibfmttoQUILLPACKEDto avoid naming collisions. (#620) -
The
set_thread_namefunction has been fixed to provide accurate error reporting, ensuring that the correct error message is displayed in the event of a failure.
-
Fixed a build issue when compiling with
-fno-rtti. This ensures compatibility with projects that disableRTTI. (#604) -
Fixed an incorrectly triggered assertion in debug builds when
BackendOptions::log_timestamp_ordering_grace_periodis set to 0 (#605) -
Fixed a compile-time error in
CsvWriterthat occurred when passing a customFrontendOptionstype as a template parameter. (#609) -
Added accessors to
Loggerfor sinks, user clock source, clock source type, and pattern formatter options that can be used to create anotherLoggerwith similar configuration. -
Added
ConsoleColours::ColourModetoConsoleSink, allowing colors to be explicitly forced or conditionally enabled based on the environment. Previously, colors were only conditionally enabled. (#611).For example:
quill::Frontend::create_or_get_sink<quill::ConsoleSink>( "sink_id_1", quill::ConsoleColours::ColourMode::Automatic);
- Added the option to explicitly specify the
Loggerused by the built-inSignalHandlerfor logging errors during application crashes. (#590) - Prevented error logs from the
SignalHandlerfrom being output to CSV files when aCsvWriteris in use. (#588) - Introduced
SignalHandlerOptionsto simplify and unify the API.Backend::start_with_signal_handleris now deprecated, replaced by a newBackend::startoverload that acceptsSignalHandlerOptionsfor enabling signal handling. - Added a new
create_or_get_loggeroverload that accepts astd::vector<std::shared_ptr<Sink>>, improving flexibility by allowing a variable number of sinks to be passed at runtime when creating a logger. - Added a new overload to
create_or_get_loggerto create a logger that inherits configuration options from a specified logger. (#596) - Implemented a workaround to resolve false positive warnings from
clang-tidyon Windows.
- Fixed race condition during DLL unload by ensuring safe cleanup of
ThreadContextwhen callingflush_log()(#586)
- Fixed an unused variable warning treated as an error on MSVC.
Bug Fixes:
- Fixed compile error in
BackendTscClock(#577) - Added a missing header include in
TriviallyCopyableCodec.h. (#560) - Fixed incorrect log level short codes introduced in v7 after adding the new log level
NOTICE. Using%(log_level_short_code)in the pattern formatter could incorrectly mapLOG_ERRORto"C"and LOG_WARNING to"E". (#564) - Fixed an overflow issue when logging more than
uint32_t::max()bytes in a single log message. For example, attempting to logstd::string s(std::numeric_limits<uint32_t>::max(), 'a');would previously cause a crash.
Improvements:
- Optimised dynamic log level handling and size calculation for fundamental types,
std::stringandstd:: string_viewon the hot path. - Several enhancements to the backend worker thread, resulting in an overall 10% backend throughput increase.
Key optimizations include the simplification of
TransitEventBuffer, reducing the memory footprint ofTransitEvent, introducing support for custom buffer sizes in file streams and tuningtransit_events_soft_limitandtransit_events_hard_limitdefault values - Improved readability of queue allocation notification messages. Capacities are now displayed in KiB,
e.g.,
20:59:25 Quill INFO: Allocated a new SPSC queue with a capacity of 1024 KB (previously 512 KB) from thread 31158.
New Features:
- Introduced support for custom buffer sizes in file streams for
FileSinkandRotatingFileSink. Buffer size is now configurable viaFileSinkConfig::set_write_buffer_size(size_value)with a default of 64 KB. - Added an optional
fsyncinterval to control the minimum time between consecutivefsynccalls, reducing disk wear from frequent fsync operations. This option is only applicable whenfsyncis enabled. (#557) - Implemented support for appending a custom timestamp format to log filenames via
StartCustomTimestampFormat. Example usage:This will create a log file namedauto file_sink = quill::Frontend::create_or_get_sink<quill::FileSink>("logfile.log", []() { quill::FileSinkConfig cfg; cfg.set_filename_append_option(quill::FilenameAppendOption::StartCustomTimestampFormat, "%m%d"); return cfg; }());
logfile0919.log, where0919represents the month and day. - When using
%(named_args)in the pattern formatter or logging in JSON format, extra arguments without key names are now included in JSON output with keys corresponding to their positional indexes. This allows additional details to be included in the JSON while keeping the log message clean. For example (#563):This will output:LOG_INFO(hybrid_logger, "Operation {name} completed with code {code}", "Update", 123, "Data synced successfully");
And the corresponding JSON will be:Operation Update completed with code 123{"timestamp":"1726582319816776867","file_name":"json_file_logging.cpp","line":"71","thread_id":"25462","logger":"hybrid_logger","log_level":"INFO","message":"Operation {name} completed with code {code}","name":"Update","code":"123","_2":"Data synced successfully"}
- Fixed crash when using
QueueType::BoundedDroppingorQueueType::UnboundedDroppingafter a message drops. (#553) - Improved performance of
ForwardListdecoding. - Corrected reported dropped message count; previously, log flush attempts were incorrectly included.
- Removed leftover files after running some unit tests.
- Stabilized regression tests.
- Suppressed false-positive
-Wstringop-overflowwarnings (e.g., with GCC 13). - Fixed MinGW build and added MinGW builds to GitHub Actions.
-
Simplified the log tags API. The
Tagsclass has been removed. You now pass achar const*directly to the macros. Additionally, macros previously namedWITH_TAGShave been renamed to_TAGS. For example,LOG_INFO_WITH_TAGSis nowLOG_INFO_TAGS. -
Renamed
backend_cpu_affinitytocpu_affinityinBackendOptionsto improve consistency. -
Simplified project structure by removing the extra quill directory and made minor CMake improvements;
include/quillis now directly in the root. -
Added support for
std::stringwith custom allocator. (#524) -
Added a new log level
NOTICE, for capturing significant events that aren't errors or warnings. It fits betweenINFOandWARNINGfor logging important runtime events that require attention. (#526) -
Enhanced static assert error message for unsupported codecs, providing clearer guidance for STL and user-defined types.
-
Improved frontend performance by caching the
ThreadContextpointer inLoggerclass to avoid repeated function calls. On Linux, this is now further optimised with__threadfor thread-local storage, while other platforms still usethread_local. -
Minor performance enhancement in the frontend by replacing
std::vector<size_t>with anInlinedVector<uint32_t, 12>for caching sizes (e.g. string arguments). -
Fixed order of evaluation for
Codec::pair<T1,T2>::compute_encoded_size()to prevent side effects observed on MSVC -
Introduced the
add_metadata_to_multi_line_logsoption inPatternFormatter. This option, now enabled by default, appends metadata such as timestamps and log levels to every line of multiline log entries, ensuring consistent log output. To restore the previous behavior, set this option to false when creating aLoggerusingFrontend::create_or_get_logger(...). Note that this option is ignored when logging JSON using named arguments in the format message. (#534) -
JSONsinks now automatically remove any\ncharacters from format messages, ensuring the emission of validJSONmessages even when\nis present in the format. -
Replaced
staticvariables withstatic constexprin theConsoleColoursclass. -
Fixed compiler errors in a few rarely used macros. Added a comprehensive test for all macros to prevent similar issues in the future.
-
Expanded terminal list for color detection in console applications on Linux
-
Fixed an issue where
char*andchar[]types could be incorrectly selected by the Codec template inArray.h -
The library no longer defines
__STDC_WANT_LIB_EXT1__, as the bounds-checking functions from the extensions are no longer needed. -
StringFromTimeconstructor no longer relies on the system's current time, improving performance in simulations where timestamps differ from system time. (#541) -
The
Frontend::create_or_get_logger(...)function now accepts aPatternFormatterOptionsparameter, simplifying the API. This is a breaking change. To migrate quickly, wrap the existing formatting parameters in aPatternFormatterOptionsobject.Before:
quill::Logger* logger = quill::Frontend::create_or_get_logger("root", std::move(file_sink), "%(time) [%(thread_id)] %(short_source_location:<28) " "LOG_%(log_level:<9) %(logger:<12) %(message)", "%H:%M:%S.%Qns", quill::Timezone::GmtTime);After:
quill::Logger* logger = quill::Frontend::create_or_get_logger("root", std::move(file_sink), quill::PatternFormatterOptions { "%(time) [%(thread_id)] %(short_source_location:<28) " "LOG_%(log_level:<9) %(logger:<12) %(message)", "%H:%M:%S.%Qns", quill::Timezone::GmtTime});
- Fix pkg-config file on windows
- Fix pkg-config file
- Fix various compiler warnings
- Minor serialisation improvements in
Array.handChrono.h - Introduced
Backend::acquire_manual_backend_worker()as an advanced feature, enabling users to manage the backend worker on a custom thread. This feature is intended for advanced use cases where greater control over threading is required. (#519) - Add new
CsvWriterutility class for asynchronous CSV file writing. For example:#include "quill/Backend.h" #include "quill/core/FrontendOptions.h" #include "quill/CsvWriter.h" struct OrderCsvSchema { static constexpr char const* header = "order_id,symbol,quantity,price,side"; static constexpr char const* format = "{},{},{},{:.2f},{}"; }; int main() { quill::BackendOptions backend_options; quill::Backend::start(backend_options); quill::CsvWriter<OrderCsvSchema, quill::FrontendOptions> csv_writer {"orders.csv"}; csv_writer.append_row(13212123, "AAPL", 100, 210.32321, "BUY"); csv_writer.append_row(132121123, "META", 300, 478.32321, "SELL"); csv_writer.append_row(13212123, "AAPL", 120, 210.42321, "BUY"); }
-
Added a Cheat Sheet to help users get the most out of the logging library
-
Removed
ArgSizeCalculator<>,Encoder<>, andDecoder<>classes. These have been consolidated into a singleCodecclass. Users who wish to pass user-defined objects should now specialize this singleCodecclass instead of managing three separate classes. For guidance, please refer to the updated advanced example -
Added
TriviallyCopyableCodec.hto facilitate serialization for trivially copyable user-defined types. For examplestruct TCStruct { int a; double b; char c[12]; friend std::ostream& operator<<(std::ostream& os, TCStruct const& arg) { os << "a: " << arg.a << ", b: " << arg.b << ", c: " << arg.c; return os; } }; template <> struct fmtquill::formatter<TCStruct> : fmtquill::ostream_formatter { }; template <> struct quill::Codec<TCStruct> : quill::TriviallyCopyableTypeCodec<TCStruct> { }; int main() { // init code ... TCStruct tc; tc.a = 123; tc.b = 321; tc.c[0] = '\0'; LOG_INFO(logger, "{}", tc); }
-
Added support for passing arithmetic or enum c style arrays when
std/Array.his included. For example#include "quill/std/Array.h" int a[6] = {123, 456}; LOG_INFO(logger, "a {}", a);
-
Added support for
void const*formatting. For exampleint a = 123; int* b = &a; LOG_INFO(logger, "{}", fmt::ptr(b));
-
Added support for formatting
std::chrono::time_pointandstd::chrono::durationwith the inclusion ofquill/std/Chrono.h#include "quill/std/Chrono.h" std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); LOG_INFO(logger, "time is {}", now);
-
Removed unused method from
ConsoleSink
- Fix unit tests on FreeBSD (#496)
- Resolved unused variable warning on MSVC.
- Updated CMake to avoid adding
-fno-exceptionsto the entire target whenQUILL_NO_EXCEPTIONS=ON(#499) - Fix an issue where timestamps were incorrectly calculated when using
quill::Timezone::LocalTime. This bug affected timezones that did not have an exact hour difference from UTC, leading to incorrect timestamp calculations. (#498) - The newline character
\nis now considered printable by default and will no longer be sanitized. Users can now include new lines in their logs directly. In versions4.4.1and earlier,\nwas not sanitized, and this behavior is restored in this update, eliminating the need for a customcheck_printable_charfunction inBackendOptions. - On Windows, when colors are enabled in
ConsoleSink,GetConsoleScreenBufferInfomay fail in the debug console. Previously, this would result in an error being displayed but no logs being written. This issue is now resolved: the error is reported once, and logs will be written to the console without colors. - Improved performance of
StringFromTimeandTimestampFormatterused by the backend worker thread. - Replaced
std::mutexwith a spinlock, resulting in minor performance improvement for backend worker. This change also avoids including<mutex>in the frontend, particularly when following the recommended_usage example - Update bundled
libfmtto11.0.2
-
Fix build failure on Windows Arm64 (#485)
-
Previously, wide string support was included in
Codec.h. Wide string functionality has now been moved to a separate header file,WideStrings.h. On Windows, logging wide strings now requires the inclusion ofquill/std/WideStrings.h. -
Added
QUILL_IMMEDIATE_FLUSHpreprocessor variable. This variable can be defined before includingLogMacros.hor passed as a compiler flag. WhenQUILL_IMMEDIATE_FLUSHis defined, the library will flush the log on each log statement. This causes the caller thread to wait for the log to be processed and written to the log file by the backend thread before continuing, significantly impacting performance. This feature is useful for debugging the application when synchronized logs are required. (#488) -
Introduced
log_level_descriptionsandlog_level_short_codesinBackendOptionsto allow customization ofLogLeveldescriptions and short codes, replacing previously hardcoded values. This enhancement enables users to define their own descriptions and short codes for each log level. For instance, instead of displayingLOG_WARNING, it can now be configured to showLOG_WARN. (#489)quill::BackendOptions backend_options; backend_options.log_level_descriptions[static_cast<uint32_t>(quill::LogLevel::Warning)] = "WARN"; quill::Backend::start(backend_options);
-
Introduced
LOGV_LEVEL,LOGV_LEVEL_LIMIT, andLOGV_LEVEL_WITH_TAGSmacros. These new macros simplify logging by automatically printing variable names and values without explicitly specifying each variable name or using{}placeholders in the format string. Each macro can handle up to 26 arguments. The format string is concatenated at compile time, there is no runtime overhead for using these macros. For example:int a = 123; double b = 3.17; LOGV_INFO(logger, "A message with two variables", a, b)
outputs
A message with two variables [a: 123, b: 3.17] -
Introduced
LOGJ_LEVEL,LOGJ_LEVEL_LIMIT, andLOGJ_LEVEL_WITH_TAGSmacros. These new macros simplify JSON logging by automatically embedding the name of each passed variable as a named argument in the format string. Each macro can handle up to 26 arguments. The format string is concatenated at compile time, there is no runtime overhead for using these macros. For example:int var_a = 123; std::string var_b = "test"; LOGJ_INFO(logger, "A json message", var_a, var_b);
outputs
{"log_level":"INFO","message":"A json message {var_a}, {var_b}","var_a":"123","var_b":"test"} -
Enhanced the
filterfunction to also receive the formattedlog_messagealongside the log_statement, enabling the comparison and filtering oflog_messagewhile disregarding elements like timestamps from the fulllog_statement. (#493) -
Renamed
log_messagetolog_statementandshould_log_messagetoshould_log_statementinLogger -
Replaced
%(log_level_id)with%(log_level_short_code)in thePatternFormatter. -
Fix a
CMakeListserror for oldCMakeversions prior to3.19. (#491)
-
The backend now automatically sanitizes non-printable characters in log messages by converting them to their hexadecimal representation. This feature ensures logs contain only safe, readable characters. You can customize or disable this feature through the backend options by modifying the
check_printable_charcallback inBackendOptions.std::function<bool(char c)> check_printable_char = [](char c) { return c >= ' ' && c <= '~'; };
-
Added
StringRef, a utility for passing string arguments by reference without copying. Suitable for string literals or immutable strings with a guaranteed persistent lifetime. For example#include "quill/StringRef.h" static constexpr std::string_view sv {"string_view"}; LOG_INFO(logger, "{} {}", quill::utility::StringRef{sv}, quill::utility::StringRef{"string_literal"});
-
Renamed
write_log_messagetowrite_loginSink. The formattedlog_messageandprocess_idare now also provided. This enhancement supports use cases where the formattedlog_statementpassed to theSinkcan be ignored and overwritten with a custom format, allowing a singleLoggerto output different formats to various Sinks. (#476) -
Fixed a bug in JSON logging where previously cached named arguments could erroneously append to subsequent log statements. (#482)
- Fixed multiple definitions of
quill::detail::get_error_message(#469) - Fixed an issue causing a
SIGABRTwhen creating directories with a symlink folder path using GCC versions 8 or 9 (#468) - Added an assertion to prevent the use of custom
FrontendOptionstogether with defaultFrontendOptions(#453)
- Introduced
log_timestamp_ordering_grace_period parameter, replacingenable_strict_log_timestamp_orderinBackendOptions. Enables strict timestamp ordering with configurable grace period. - Fixed an issue where symbols were not properly exported with hidden visibility when compiling as a shared library. (#463)
- Move version info into quill namespace (#465)
- Upstreamed
Mesonbuild integration. See details here - Upstreamed
Bazelbuild integration. See details here
- Refactored
BacktraceStorageto simplify the code. - Fixed multiple definitions of
on_alarminSignalHandler.h - Fixed a bug in the backend thread where
flush()andrun_periodic_tasks()were skipped for certain sinks. All sinks are now correctly processed.
- Added
-Wno-gnu-zero-variadic-macro-argumentsas an interface compiler flag in CMake
- Fixed the compile-time exclusion of log levels. Renamed the
QUILL_COMPILE_OUT_LOG_LEVELpreprocessor flag toQUILL_COMPILE_ACTIVE_LOG_LEVEL. - Fixed build error when
UnboundedDroppingqueue is used. - Fixed a bug introduced in
v4.1.0, which resulted in messages being logged out of order when thetransit_events_soft_limitwas reached. Additionally, this issue affected the behavior offlush_log(), prematurely unblocking the thread before all messages were flushed. - Fixed
-Wno-unused-parameterand-Wdocumentationwarnings. - Improved backend worker
_exit()functionality and reduced code duplication in other areas of the backend worker code. - Added
signal_handler_timeout_secondsparameter, which controls the timeout duration for the signal handler. Only available on Linux platforms. - Added
sleep_duration_nsparameter to theflush_log(...)function. This parameter specifies the duration in nanoseconds to sleep between retries between checks for the flush completion and when a blocking queue is used, and it is full. The default sleep duration is 100 nanoseconds, but users can now customize this duration according to their needs. If a zero sleep duration is passed, the thread might yield instead. - Removed uses of
std::this_thread::sleep_for(...),std::string,std::vectorin the signal handler when waiting for the log to be flushed.
- Following the transition from a compiled to a header-only library, the
target_compile_optionspreviously applied to the compiled library were mistakenly propagated to all programs linking against the header-only library. This issue is now fixed by removing those flags and explicitly adding them to tests and examples. As a result, executable targets no longer inherit flags from the library. - Removed unnecessary template specializations and merged their logic into the primary template
for
ArgSizeCalculator,Encoder, andDecoderusing if constexpr. - Eliminated
<functional>header dependency in the frontend - Replaced
%(structured_keys)with%(named_args)in thePatternFormatter. This change now appends the entire key-value pair of named args to the message, not just the names. - Relocated certain classes to the
detailnamespace - Replaced
sprintfwithsnprintfto fix macOS warning. - Reviewed and removed gcc cold attribute from a few functions.
- Minor backend thread optimisations when logging c style strings or char arrays
- Improved backend thread variable and function names and fixed a bug for an edge case when the transit event hard limit is reached
This version represents a major revamp of the library, aiming to simplify and modernize it, resulting in the removal of a few features. Please read through the changes carefully before upgrading, as it is not backwards compatible with previous versions and some effort will be required to migrate.
I understand that these changes may inconvenience some existing users. However, they have been made with good intentions, aiming to improve and refine the logging library. This involved significant effort and dedication.
Bug fixes and releases for v3 will continue to be supported under the v3.x.x branch.
- This version significantly improves compile times. Taking a look at some compiler profiling for a
Releasebuild with clang 15, we can see the difference. Below are the two compiler flamegraphs for building therecommended_usageexample from the new version and thewrapper_libexample from the previous version.
The below flamegraph shows the difference in included headers between the two versions
| Version | Compiler FlameGraph |
|---|---|
| v4.0.0 | ![]() |
| v3.8.0 | ![]() |
A new compiler benchmark has been introduced. A Python script generates 2000 distinct log statements with various arguments. You can find the benchmark here. Compilation now takes only about 30 seconds, whereas the previous version required over 4 minutes.
| Version | Compiler FlameGraph |
|---|---|
| v4.0.0 | ![]() |
| v3.8.0 | ![]() |
- Minor increase in backend thread throughput compared to the previous version.
| Version | Backend Throughput |
|---|---|
| v4.0.0 | 4.56 million msgs/sec average, total time elapsed: 876 ms for 4000000 log messages |
| v3.8.0 | 4.39 million msgs/sec average, total time elapsed: 910 ms for 4000000 log messages |
- Significant boost in hot path latency when logging complex types such as
std::vector. The performance remains consistent when logging only primitive types or strings in both versions. Refer here for updated and detailed benchmarks.
- Improved compile times
The library has been restructured to minimize the number of required headers. Refactoring efforts have focused on decoupling the frontend from the backend, resulting in reduced dependencies. Accessing the frontend logging functions now does not demand inclusion of any backend logic components.
"quill/Backend.h" - It can be included once to start the backend logging thread, typically in main.cpp
or in a wrapper library.
"quill/Frontend.h"` - Used to create or obtain a `Logger*` or a `Sink`. It can be included in limited
files, since an obtained `Logger*` has pointer stability and can be passed around.
"quill/Logger.h", "quill/LogMacros.h" - These two files are the only ones needed for logging and will have
to be included in every file that requires logging functionality.
- Backend formatting for user-defined and standard library types
One of the significant changes lies in the support for formatting both user-defined and standard library types.
Previously, the backend thread handled the formatting of these types sent by the frontend. It involved making a copy for
any object passed to the LOG_ macros as an argument using the copy constructor of a complex type instead of directly
serializing the data to the SPSC queue. While this method facilitated logging copy-constructible user-defined types with
ease, it also posed numerous challenges for asynchronous logging:
- Error-Prone Asynchronous Logging: Copying and formatting user-defined types on the backend thread in an asynchronous logging setup could lead to errors. Previous versions attempted to address this issue with type trait checks, which incurred additional template instantiations and compile times.
- Uncertainty in Type Verification: It is challenging to confidently verify types, as some trivially copiable
types, such as
struct A { int* m; }, could still lead to issues due to potential modifications by the user before formatting. - Hidden Performance Penalties: Logging non-trivially copiable types could introduce hidden cache coherence
performance penalties due to memory allocations and deallocations across threads. For instance,
consider
std::vector<int>passed as a log argument. The vector is emplaced into the SPSC queue by the frontend, invoking the copy constructor dynamically allocating memory as the only members copied to SPSC queue aresize,capacity, anddata*. The backend thread reads the object, formats it, and then invokes the destructor, which in turn synchronizes the freed memory back to the frontend.
Additionally, after years of professional use and based on experience, it has been observed that user-defined types are often logged during program initialization, with fewer occurrences on the hot path where mostly built-in types are logged. In such scenarios, the overhead of string formatting on the frontend during initialization is not an issue.
In this new version, the use of the copy constructor for emplacing objects in the queue has been abandoned. Only POD
types are copied, ensuring that only raw, tangible data is handled without any underlying pointers pointing to other
memory locations. The only exception to this are the pointers to Metadata, LoggerBase and DecodeFunction
that are passed internally for each log message. Log arguments sent from the frontend must undergo
serialization beforehand. While this approach resolves the above issues, it does introduce more complexity when
dealing with user-defined or standard library types.
Built-in types and strings are logged by default, with the formatting being offloaded to the backend. Additionally,
there is built-in support for most standard library types, which can also be directly passed to the logger by
including the relevant header from quill/std.
The recommendation for user-defined types is to format them into strings before passing them to the LOG_ macros using
your preferred method. You can find an example of
this here.
It's also possible to extend the library by providing template specializations to serialize the user-defined types and offload their formatting to the backend. However, this approach should only be pursued if you cannot tolerate the formatting overhead in that part of your program. For further guidance, refer to this example.
- Header-Only library
The library is now header-only. This change simplifies exporting the library as a C++ module in the future. See here on how to build a wrapper static library which includes the backend and will minimise the compile times.
- Preprocessor flags moved to template parameters
Most preprocessor flags have been moved to template parameters, with only a few remaining as CMake options. This
change simplifies exporting the library as a C++ module in the future.
- Renamed Handlers to Sinks
To enhance clarity, handlers have been renamed to sinks.
- PatternFormatter moved to Logger
The PatternFormatter has been relocated from Sink to Logger, enabling a logger object to log in a specific
format. This allows for different formats within the same output file, a feature not previously possible.
- Split Configuration
The configuration settings have been divided into FrontendOptions and BackendOptions.
- Refactoring of backend classes
MacroMetadata and many backend classes have undergone refactoring, resulting in reduced memory requirements.
- Improved wide strings handling on Windows
The library now offers significant performance enhancements for handling wide strings on Windows platforms. It's important to note that only wide strings containing ASCII characters are supported. Previously, wide strings were converted to narrow strings at the frontend, impacting the critical path of the application. With this update, the underlying wide char buffer is copied and the conversion to UTF-8 encoding is deferred to the backend logging thread. Additionally, this update adds support for logging STL containers consisting of wide strings
- Default logger removal
The default logger, along with the configuration inheritance feature during logger creation, has been removed. Now, when
creating a new logger instance, configurations such as the Sink and log pattern format must be explicitly specified
each time. This simplifies the codebase.
- Global logger removal
The static global logger* variable that was initialised during quill::start() used to obtain the default logger has
been removed. It is possible to add this on the user side. If you require a global logger you can have a look
at this example
- Removal of printf style formatting support
The support for printf style formatting has been removed due to its limited usage and the increased complexity. Users
requiring this feature should stay on v3.x.x versions to maintain compatibility.
- Removal of external libfmt usage
The option to build the library with external libfmt has been removed. It becomes difficult to maintain and backwards
support previous versions of libfmt. Instead, libfmt is now an internal component of the library, accessible under
the namespace fmtquill. You can use the bundled version of fmtquill by including the necessary headers from
quill/bundled/fmt. Alternatively, you have the freedom to integrate your own version. Since libfmt is encapsulated
within a distinct namespace, there are no conflicts even if you link your own libfmt alongside the logging library.
- Revise include files to accommodate the removal of
Quill.h - Update the code that starts the backend thread and the logger/sink creation. You can refer to any of the updated examples, such as this one
- When logging statements involving user-defined types, make sure these types are formatted into strings using your preferred method. Refer to this link for guidance. Alternatively, if you prefer delaying the conversion to strings until the backend thread and only passing a binary copy of the user-defined type on the hot path, you can provide the necessary class template specializations for each user-defined type. See an example here
- Fix bug in
ConsoleHandlerwhen dynamic log level is used (#421) - Fix bug in
TransitEventwhen dynamic log level is used (#427) - Fix build error for Intel compiler classic (#414)
- Added
JsonConsoleHandler(#413) - Fix fold expression argument evaluation. This bug could occur when logging c style strings
- Refactored
MacroMetadataclass to reduce its size. - Renamed some attributes in the
PatternFormatterclass for clarity. If you are using a custom format pattern, update the attribute names in your code to match the new names. - Improved accuracy of log statement timestamps. Previously, the timestamp was taken after checking if the queue had enough space to push the message, which could make it less accurate. Additionally, in the case of a blocking queue, the timestamp could be later in time. Now, the timestamp is taken and stored right after the log statement is issued, before checking for the queue size.
- Reduced template instantiations during logging operations on the hot path. Fold expressions are now used for encoding/decoding arguments, minimizing template recursion overhead.
- Removed compile-time format checks due to their significant impact on template instantiations, especially considering
that only a few cases are invalid. For instance, while
fmt::format("{}", 1, 2)is considered valid,fmt::format("{} {}", 1)is deemed invalid. In cases where an invalid format string is detected, the backend worker thread catches the generated exception and logs an error. - The throughput of the backend worker thread has been improved by approximately 5%. This enhancement is reflected in the new throughput value of 4.20 million msgs/sec, compared to the previous throughput of 3.98 million msgs/sec.
- Detect
tmuxas colour terminal. (#410)
- Fixed crash triggered by insufficient space in the queue upon invocation
of
flush(). (#398) - Fixed windows clang-cl build error. (#400)
- Fixed compilation errors encountered on FreeBSD and extended
get_thread_id()support to various other BSD operating systems. (#401) - Fix open_file in the FileHandler to also create the parent path before opening the file. (#395)
- Enhance logic for backend thread's flush() invocation; it now triggers only if the handler has previously written data. (#395)
- Address an uncaught exception in the backend thread that could occur when a user manually removes the log file from the terminal while the logger is running. (#395)
- Ensure that after a logger is removed, there are no subsequent calls to the Handler's flush() or run_loop(), provided the Handler is not shared. (#395)
- Ignore the virtual destructor missing warning for the
CustomTagsclass. (#402) - Update bundled
libfmttov10.2.1
- Fixed
QUILL_LOGGER_CALL_NOFN_LIMITmacros. (#381) - Resolved a bug that caused reading destructed arguments when structured logging format was used.
- Modified member access from
privatetoprotectedinConsoleHandlerfor potential inheritance purposes. - Eliminated redundant whitespaces within
JsonFileHandler. - Fixed
JsonFileHandlerto notify the file event notifier before log message writes. - Implemented a new attribute called
%(structured_keys)within thePatternFormatterto facilitate the inclusion of keys in messages when using structured log formatting. This addition is useful for instances where logging occurs in both JSON and regular log formats, enabling the display of keys within the regular log-formatted messages. See updated example_json_structured_log.cpp
- Resolved issue with accessing the
name()method within theLoggerclass. (#378) - Fixed a compilation error in
SignalHandlerspecific to Windows whenQUILL_DISABLE_NON_PREFIXED_MACROSis defined. (#380)
- Fixed
LOG_TRACE_CFORMATmacros. - Added support for compile-time custom tags in
quill::MacroMetadatato enhance message filtering and incorporate static information. New log macros suffixed with_WITH_TAGSintroduced for this feature. Additionally,%(custom_tags)parameter added toPatternFormatter. (#349) See example_custom_tags.cpp - Improvements to reduce compilation time
- Reduce backend worker unnecessary allocation. (#368)
- Adjusted handling for empty
std::string_viewinstances, addressing an issue where logging empty strings triggered an unintendedmemcpywith zero size and a nullptr, leading to address sanitizer warnings. - Fix clang build error when using
-DQUILL_NO_EXCEPTIONS:BOOL=ON. (#357)
-
Resolved
bad_variant_accesserror occurring when using Quill as a pre-compiled library with a distinct queue type. (#276) -
Resolved a bug in
RotatingFileHandlerassociated with logfiles located outside the working directory, specifically when used with open_modea. (#340) -
Added a
name()method to the Logger class which provides the logger name. (#345) -
Fixed library and include paths in the pkg-config configuration. (#352)
-
Move
get_root_logger()definition from cpp to the header file (#348) -
Introduced support for logging character arrays. You can now log character arrays, even when they don't contain a null-terminating character. Additionally, character arrays with null characters in the middle are supported, and the logger will capture the content until the null character is encountered. (#353)
For example
union { char no_0[2]; char mid_0[6]{'1', '2', '3', '4', '\0', 6}; } char_arrays; // only output "12" even if there's no '\0' at the end LOG_INFO(logger, R"(This is a log info example for char array without '\0': {})", char_arrays.no_0); // output "1234" until the '\0' LOG_INFO(logger, R"(This is a log info example for char array with '\0' in middle: {})", char_arrays.mid_0);
-
Minor improvements in the bounded queue and throughput. (#362)
Previous: 2.21 million msgs/sec average, total time elapsed: 1809 ms for 4000000 log messages.
New: 2.24 million msgs/sec average, total time elapsed: 1787 ms for 4000000 log messages.
-
Disable
fmt::join(data, "")at compile time. (#356) -
Fix compile error in Apple Clang 12. (#360)
-
Add guards for redefined preprocessor variables.
-
Fix
uint64_ttotime_timplicit conversion error in Clang 18. -
Update bundled
libfmttov10.1.1
- Fixed
RotatingFileHandlerto prevent accidental removal of non-log files when using open modewandset_remove_old_files(true)
-
Added a
quill::get_handler(handler_name)function that allows easy lookup of an existingHandlerby name. This function proves helpful when you want to retrieve a handler and pass it to a new logger. -
Fix build failure of Intel Compiler Classic. (#332)
-
Introduced
QUILL_BLOCKING_QUEUE_RETRY_INTERVAL_NSoption for user-configurable retry interval in the blocking queue. Default value is 800 nanoseconds. (#330) -
Improved backend thread handling. Now verifies that all producer SPSC queues are empty before entering
sleep. -
Fixed a race condition and potential crash in
quill::remove_logger(Logger*)when called without priorquill::flush(). -
Added protection to prevent removal of the root logger with
quill::remove_logger(Logger*). -
Improved exception handling on the backend thread when calling
fmt::format().While compile-time checks ensure that the format string and arguments match, runtime errors can still occur. Previously, such exceptions would affect and drop subsequent log records. Now, exceptions are caught and logged in the log file and reported via the backend thread notification handler (default is
cerr).For example, if a dynamic precision is used (
LOG_INFO(logger, "Support for floats {:.{}f}", 1.23456, 3.321312)), the log file will show the following error message:LOG_INFO root [format: "Support for floats {:.{}f}", error: "precision is not integer"]Additionally, an error message will be printed to
cerrQuill ERROR: [format: "Support for floats {:.{}f}", error: "precision is not integer"] -
Fixed a bug in timestamp formatting that occasionally displayed an hour component of 0 as 24. (#329)
-
Added support for specifying a runtime log level, allowing dynamic log level configuration at runtime. The new runtime log level feature provides flexibility when needed, with a minor overhead cost. It is recommended to continue using the existing static log level macros for optimal performance. (#321)
For example
std::array<quill::LogLevel, 4> const runtime_log_levels = {quill::LogLevel::Debug, quill::LogLevel::Info, quill::LogLevel::Warning, quill::LogLevel::Error}; for (auto const& log_level : runtime_log_levels) { LOG_DYNAMIC(logger, log_level, "Runtime {} {}", "log", "level"); }
-
Added support for printf-style formatting with
_CFORMATmacros. These macros use theprintfformat string syntax, simplifying the migration of legacy codebases usingprintfstatements.For example
std::array<uint32_t, 4> arr = {1, 2, 3, 4}; LOG_INFO(logger, "This is a log info example using fmt format {}", arr); LOG_INFO_CFORMAT(logger, "printf style %s supported %d %f", "also", 5, 2.32);
-
Added a
metadata()member function to theTransitEventclass. It provides access to theMetadataobject associated with the log record, simplifying syntax for retrieving log record metadata in custom Handlers.For example
void CustomHandler::write(fmt_buffer_t const& formatted_log_message, quill::TransitEvent const& log_event) { MacroMetadata const macro_metadata = log_event.metadata(); }
-
Simplified file handler configuration. Now, instead of passing multiple arguments to the constructor, you only need to provide a single
FileHandlerConfigobject. This change makes creating file handlers objects much easier and more flexible.For example
quill::FileHandlerConfig file_handler_cfg; file_handler_cfg.set_open_mode('w'); file_handler_cfg.set_append_to_filename(quill::FilenameAppend::StartDateTime); std::shared_ptr<quill::Handler> file_handler = quill::file_handler("application.log", file_handler_cfg); quill::Logger* logger_foo = quill::create_logger("my_logger", std::move(file_handler)); LOG_INFO(my_logger, "Hello from {}", "application");
-
Combined the functionalities of
RotatingFileHandler(rotating based on file size) andTimeRotatingFileHandler(rotating on a time interval) into a single, more versatileRotatingFileHandler. Users can now conveniently rotate logs based on both file size and time intervals simultaneously. The updatedRotatingFileHandleroffers a variety of customization options for improved flexibility. For more information on available configurations, refer to theRotatingFileHandlerConfigdocumentation.For example
// Create a rotating file handler which rotates daily at 18:30 or when the file size reaches 2GB std::shared_ptr<quill::Handler> file_handler = quill::rotating_file_handler(filename, []() { quill::RotatingFileHandlerConfig cfg; cfg.set_rotation_time_daily("18:30"); cfg.set_rotation_max_file_size(2'000'000'000); return cfg; }()); // Create a logger using this handler quill::Logger* logger_bar = quill::create_logger("daily_logger", std::move(file_handler));
-
Improved compatibility with older versions of external
libfmt. Quill now compiles for all versions oflibfmt >= 8.0.0.
-
Addition of std::is_trivially_copyable to default copy loggable types. (#318)
-
By default, the static library now builds with '-fPIC' to generate position-independent code. To disable this feature, you can use the CMake option 'QUILL_DISABLE_POSITION_INDEPENDENT_CODE'.
-
The
LOG_<LEVEL>_LIMITmacros now support usingstd::chronoduration types for specifying the log interval. Instead of providing a raw number, you can use:LOG_INFO_LIMIT(std::chrono::milliseconds {100} , quill::get_logger(), "log message");
-
It is now possible to set a minimum logging interval for specific logs. For example:
for (uint64_t i = 0; i < 10; ++i) { LOG_INFO_LIMIT(2000, default_logger, "log in a loop with limit 1 message every 2000 micros for i {}", i); std::this_thread::sleep_for(std::chrono::microseconds{1000}); }
-
quill::utility::to_string()now usesfmt::to_string() -
Quill now utilizes a custom namespace (
fmtquill) for the bundled fmt library. This enables smooth integration with your own external fmt library, even if it's a different version.
- Add missing header on clang when
QUILL_X86ARCHis defined.
- Enhanced the reported message for reallocation of the unbounded queue to include the thread id.
-
The previous unbounded queue constantly reallocated memory, risking system memory exhaustion, especially when handling intensive logging from multiple threads. Starting from
v3.0.0, the default behavior has been improved to limit the queue capacity to 2 GB. When this limit is reached, the queue blocks the hot thread instead of further reallocation. To modify the default behavior, there is no need to recompile thequilllibrary. Recompile your application with one of the following header-only flags.# Previous behavior in v2.*.*: Reallocates new queues indefinitely when max capacity is reached -DCMAKE_CXX_FLAGS:STRING="-DQUILL_USE_UNBOUNDED_NO_MAX_LIMIT_QUEUE" # Default behavior in v3.*.*: Starts small, reallocates up to 2GB, then hot thread blocks -DCMAKE_CXX_FLAGS:STRING="-DQUILL_USE_UNBOUNDED_BLOCKING_QUEUE" # Starts small, reallocates up to 2GB, then hot thread drops log messages -DCMAKE_CXX_FLAGS:STRING="-DQUILL_USE_UNBOUNDED_DROPPING_QUEUE" # Fixed queue size, no reallocations, hot thread drops log messages -DCMAKE_CXX_FLAGS:STRING="-DQUILL_USE_BOUNDED_QUEUE" # Fixed queue size, no reallocations, hot thread blocks -DCMAKE_CXX_FLAGS:STRING="-DQUILL_USE_BOUNDED_BLOCKING_QUEUE"
-
Added support for huge pages on Linux. Enabling this feature allows bounded or unbounded queues to utilize huge pages, resulting in optimised memory allocation.
quill::Config cfg; cfg.enable_huge_pages_hot_path = true; quill::configure(cfg); quill::start();
-
Added support for logging
std::optional, which is also now supported inlibfmtv10.0.0.LOG_INFO(default_logger, "some optionals [{}, {}]", std::optional<std::string>{}, std::optional<std::string>{"hello"});
-
Introduced a new function
run_loopin theHandlerbase class, which allows users to override and execute periodic tasks. This enhancement provides users with the flexibility to perform various actions at regular intervals, such as batch committing data to a database. -
In scenarios where a hot thread is blocked and unable to push messages to the queue in blocking mode, this situation will now be reported through the
backend_thread_notifications_handlerto the standard error streamcerr.
- Fix increased compile times due to
x86intrinheaders. (#298) - Fix compile error when using
QUILL_X86ARCHon windows. - Fix bugs when quill is build as a shared library on windows. (#302)
-
Removed
CMAKE_INSTALL_RPATHfrom cmake. (#284) -
Fix compile warning on Apple M1. (#291)
-
Update bundled
libfmttov10.0.0 -
Fix for
CMAKE_MODULE_PATH(#295) -
Fixed a bug in
TimeRotatingFileHandlerwhenquill::FilenameAppend::Noneis used. (#296) -
Fixed
TimeRotatingFileHandlerandRotatingFileHandlerto work when/dev/nullis used as a filename (#297) -
Added
NullHandlerthat can be used to discard the logs. For example:int main() { quill::start(); std::shared_ptr<quill::Handler> file_handler = quill::null_handler(); quill::Logger* logger_bar = quill::create_logger("nullhandler", std::move(file_handler)); for (uint32_t i = 0; i < 150; ++i) { LOG_INFO(logger_bar, "Hello"); }
Fixes
- Fixed a bug in TimeRotatingFileHandler. (#287)
Improvements
- Renamed
backend_thread_error_handlertobackend_thread_notifications_handlerinConfig.h. Previously this handler was used only to report errors from the backend worker thread to the user. This callback will also now report info messages to the user. - Report unbounded spsc queue reallocation via
the
backend_thread_notifications_handler. (#286) - Report bounded spsc queue dropped messages via the
backend_thread_notifications_handler.
Breaking Changes
(see improvements section for more details)
- If you were previously compiling with
-DQUILL_USE_BOUNDED_QUEUEorQUILL_X86ARCHyou should now pass the flag to you target as it is not propagated by CMake anymore. - There is a change in the API in
Quill.hinstead ofquill::Handler*you should now usestd::shared_ptr< quill::Handler >and also move it to the created logger.
Improvements
- Add
append_to_filenameparameter when creatingquill::time_rotating_file_handlerandquill::rotating_file_handler - Fix
Handlersfailing to find the file when the working directory of the application is changed in runtime. (#247) - When the given output directory of a log file passed to a
Handlerdoes not exist, it will now get automatically created. - Support Windows 10 LTSB 2016, 1607 and Server 2016. (#251)
- Add back
backend_thread_sleep_durationinConfig.h(#256) - For
quill::rotating_file_handler(...)andquill::time_rotating_file_handler(...)thebackup_countargument is now default tostd::numeric_limits<std::uint32_t>::max() - When the logging file is deleted from the command line while the logger is still using it, then a new file will be reopened for writing.
- Added
quill::Clockwhich enables taking and converting TSC timestamps to system clock timestamps. WhenTimestampClockType::Tscis used as the default clock type inConfig.hthis class can also be used to generate timestamps that are in sync with the timestamps in the log file. (#264) - Both
UnboundedandBoundedqueue modes can now be used without having to recompilequilllibrary. This is still not a runtime option, you still need to recompile your target and passQUILL_USE_BOUNDED_QUEUEas a flag. See example_bounded_queue_message_dropping.cpp - Added
QUILL_USE_BOUNDED_BLOCKING_QUEUEoption that makes possible to use a bounded queue which blocks the hot thread rather than dropping messages (#270) See example_bounded_queue_blocking.cpp - Renamed
backend_thread_max_transit_eventstobackend_thread_transit_events_soft_limitin Config.h (#270) - Added
backend_thread_transit_events_hard_limitin Config.h (#270) - Added
backend_thread_use_transit_bufferin Config.h (#270) - CMake:
QUILL_X86ARCHandQUILL_USE_BOUNDED_QUEUEoptions have been removed. The users can decide on enabling these options on their side and quill doesn't need to be recompiled as a library. For example :target_compile_definitions(<target> PUBLIC QUILL_X86ARCH QUILL_USE_BOUNDED_QUEUE)
- Added
quill::remove_logger(Logger* logger)inQuill.h. This makes it possible to remove a logger in a thread safe way. When a logger is removed any associatedFileHandlerswith that logger will also be removed and the files will also be closed as long as they are not being used by another logger. The logger is asynchronously removed by the logging thread after all the messages are written. To achieve this the API had to change to return astd::shared_ptr< quill::Handler >instead ofquill::Handler*. See example_file_callbacks.cpp - Added
quill::wake_up_logging_thread()inQuill.h. This thread safe function can be used to wake up the backend logging thread on demand. (#280) - Round up queue capacity to the nearest power of 2. (#282)
Fixes
- Remove references to build directory path from the compiled library's symbols. (#221)
- Fix when compiled as shared library with hidden visibility. (#222)
- Fix equal timestamp log messages appearing out of order. (#223)
- Reduce padding in some structs.
- Fix 'rename_file' throwing an exception while being marked
as
noexcept. (#230) - Fix crash with
std::bad_allocand compiler warnings in gcc7.3.1. (#235) - The additional compiler definitions will now be propagated to the parent targets when enabling options in CMake. (#235)
Improvements
-
Improved performance and throughput of the backend logging thread by approximately ~25%
-
Add missing
quill::json_file_handler(...)that creates aJsonFileHandlerinQuill.h. -
Simplified and refactored the logic in
BoundedQueue. -
Added the option
do_fsyncwhich also callsfsync()during the handler flush to all file handlers. -
Replace
backend_thread_sleep_durationwithbackend_thread_yieldinConfig.h -
Remove trailing spaces in log levels strings. (#237)
-
The default log pattern has changed to
"%(ascii_time) [%(thread)] %(fileline:<28) LOG_%(level_name:<9) %(logger_name:<12) %(message)") -
Added file event notifiers, to get callbacks from quill before/after log file has been opened or closed. (#193) This is useful for cleanup procedures or for adding something to the start/end of the log files. for example
int main() { quill::start(); quill::FileEventNotifier fen; fen.before_open = [](quill::fs::path const& filename) { std::cout << "before opening " << filename << std::endl; }; fen.after_open = [](quill::fs::path const& filename, FILE* f) { std::cout << "after opening " << filename << std::endl; }; fen.before_close = [](quill::fs::path const& filename, FILE* f) { std::cout << "before closing " << filename << std::endl; }; fen.after_close = [](quill::fs::path const& filename) { std::cout << "after closing " << filename << std::endl; }; quill::Handler* file_handler = quill::file_handler("myfile.log", "w", quill::FilenameAppend::None, std::move(fen)); quill::Logger* mylogger = quill::create_logger("mylogger", file_handler); LOG_INFO(mylogger, "Hello world"); }
-
Added
QUILL_X86ARCHinTweakme.h. When enabled it will attempt to minimize the cache pollution on x86 cpus that support the instructions_mm_prefetch,_mm_clflushand_mm_clflushopt.To compile when this flag is enabled you should also pass
-marchto the compiler which is required, you can set this to your oldest cpu architecture among your systems.To enable this option,
DQUILL_X86ARCHmust always be defined in quill library and also in your executable, for examplecmake -DCMAKE_CXX_FLAGS:STRING="-DQUILL_X86ARCH -march=native" -
Added
quill:get_root_logger()which gives quick access to the root logger object and can be used directly in the hot path. This gives applications that only wish to use the root logger the convenience of not having to store and passLogger*objects anymore. for example quill existing log macros can be overwritten to not require aLogger*anymore#define MY_LOG_INFO(fmt, ...) QUILL_LOG_INFO(quill::get_root_logger(), fmt, ##__VA_ARGS__)
-
Added
QUILL_ROOT_LOGGER_ONLYinTweakme.h. Define ths if you only plan to use the singlerootlogger object, When this is defined it will replace the LOG_ macros with the equivalent LOG_ macros but without the need of passingLogger*objects anymore. for example#define QUILL_ROOT_LOGGER_ONLY #include "quill/Quill.h" int main() { quill::start(); // because we defined QUILL_ROOT_LOGGER_ONLY we do not have to pass a logger* anymore, the root logger is always used LOG_INFO("Hello {}", "world"); LOG_ERROR("This is a log error example {}", 7); }
Fixes
- Fix filepath on Windows when MinGW is used. (#212)
Improvements
- Removed the creation of
static Metadataobjects during initialisation time. #define QUILL_QUEUE_CAPACITYhas been removed.- Added Config option
default_queue_capacitythat can be used to specify the initial capacity of the queue. - When Unbounded queue is used the newly allocated queue will now have enough space to fit any object. (#215)
Improvements
- Reduced the allocations performed by the backend worker thread as the same objects are now being reused rather than destroyed.
Summary of changes since v2.3.2
In version 2.3.2 when multiple threads performed heavy logging, the backend logging thread incorrectly gave
priority to the logs of the same threads. That made logs from the remaining threads to appear much later or sometimes
never in the log files.
There was a series of fixes and releases to address this.
Below is the summary of the changes from v2.3.2
-
Previously when multiple threads were logging, the backend logging thread would first try to read the log messages of the same thread until its queue was completely empty before reading the log messages of the next thread. When one of the threads was logging a lot, it could result in only displaying the log of that thread, hiding the logs of the other threads. This has now been fixed and all log messages from all threads are read fairly.
-
Optimise the backend logging thread to read all log messages from each queue. Ensure all queues from all active threads are fairly read.
-
fmt::basic_memory_bufferbuffer stack size has been reduced. The backend thread shows better performance with a reduced stack size. This also reduces the risk of a stack overflow when too many log messages are cached.lllllllllll -
Reduced the allocations performed by the backend worker thread as the same objects are now being reused rather than destroyed.
-
Added a config option
backend_thread_strict_log_timestamp_order. This option enables an extra timestamp check on the backend logging thread when each message is popped from the queues. It prevents a rare situation where log messages from different threads could appear in the log file in the wrong order. This flag is now enabled by default. -
Added a config option
backend_thread_empty_all_queues_before_exit. This option makes the backend logging thread to wait until all the queues are empty before exiting. This ensures no log messages are lost when the application exists. This flag is now enabled by default.
Improvements
- Performance improvements for the backend logging thread
Fixes
- Fixes an assertion that was triggered in debug mode due to changes in v2.4.1
Improvements
- Previously the backend worker thread would read all the log messages from the queue but not read the log messages when the buffer had wrapped around. It will now read all the messages.
- Removed the
min_available_bytescache from the SPSC queue as an optimisation. It is not needed anymore as we now read all messages at once instead of reading message by message.
Improvements
-
Added a config option
backend_thread_strict_log_timestamp_order. This option enables an extra timestamp check on the backend logging thread when each message is popped from the queues. It prevents a rare situation where log messages from different threads could appear in the log file in the wrong order. This flag is now enabled by default. -
Added a config option
backend_thread_empty_all_queues_before_exit. This option makes the backend logging thread to wait until all the queues are empty before exiting. This ensures no log messages are lost when the application exists. This flag is now enabled by default.
Improvements
- Optimise the backend logging thread to read multiple log messages from the same queue, but still fairly read each queue from all active threads.
Fixes
- Previously when multiple threads were logging, Quill backend logging thread would first try reading the log messages of one thread until the queue was completely empty before reading the log messages of the next thread. When one of the threads was logging a lot, it could result in only displaying the log of that thread, hiding the logs of the other threads. This has now been fixed and all log messages from all threads are read fairly.
Fixes
- Fix code not compiling with treat warnings as errors set on Windows. (#198)
Fixes
- Optimise logging queue cache alignment of variables. It seems that v2.3.0 made the hot path slower by ~5 ns per message. This has been fixed in this version and the performance is now the same as in the previous versions.
Improvements
-
Cache the available bytes for reading in the logging queue. This is meant to offer some minor performance improvement to the backend logging thread. #185
-
Fixed static code analysis and clang '-Wdocumentation' warnings.
-
The
Handler.hAPI has changed in this version to support structured logs. If you have implemented your own customHandleryou will have to change it to follow the new API. -
This version adds support for writing structured logs. Structured logs provide easier search through events. Structured logging is automatically enabled when named arguments are provided to the format string. Structured logs are only supported by the new
quill::JsonFileHandlerhandler. The already existingFileHandlerandConsoleHandlerare compatible with named arguments, but they will ignore them and output the log in its original format, as defined by the pattern formatter. Structured logs are not supported for wide characters at the moment. See example_json_structured_log.cpp
For example :
quill::start();
quill::Handler* json_handler =
quill::create_handler<quill::JsonFileHandler>("json_output.log", "w");
// create another logger tha logs e.g. to stdout and to the json file at the same time
quill::Logger* logger = quill::create_logger("dual_logger", {quill::stdout_handler(), json_handler});
for (int i = 2; i < 4; ++i)
{
LOG_INFO(logger, "{method} to {endpoint} took {elapsed} ms", "POST", "http://", 10 * i);
}- Will write to stdout (stdout_handler) :
23:37:19.850432433 [11811] example_json_structured_log.cpp:39 LOG_INFO dual_logger - POST to http:// took 20 ms
23:37:19.850440154 [11811] example_json_structured_log.cpp:39 LOG_INFO dual_logger - POST to http:// took 30 ms
- Will produce a JSON file (json_handler) :
{ "timestamp": "23:37:19.850432433", "file": "example_json_structured_log.cpp", "line": "39", "thread_id": "11811", "logger": "dual_logger", "level": "Info", "message": "{method} to {endpoint} took {elapsed} ms", "method": "POST", "endpoint": "http://", "elapsed": "20" }
{ "timestamp": "23:37:19.850440154", "file": "example_json_structured_log.cpp", "line": "39", "thread_id": "11811", "logger": "dual_logger", "level": "Info", "message": "{method} to {endpoint} took {elapsed} ms", "method": "POST", "endpoint": "http://", "elapsed": "30" }
Improvements
- Previously storing the default root logger by calling
quill::get_logger()followed byquill::configure(cfg)would invalidate the pointer to the default root logger returned by the former function. This has now been fixed and the obtainedLogger*pointer is still valid. - Disable
fmt::streamed(). (#189) - Update bundled fmt to 9.1.0
logger->should_log(level)is removed. A compile time check was added tologger->should_log<level>(). (#187)
Improvements
This version includes breaking changes to the API. Those changes are related to how quill is configured,
before calling quill::start() to start the backend thread.
Check the updated examples.
Config.h - contains runtime configuration options
TweakMe.h - contains compile time configuration
For example quill::set_default_logger_handler(...) has been removed. To set a default filehandler :
// create a handler
quill::Handler* file_handler = quill::file_handler("test.log", "w");
file_handler->set_pattern(
"%(ascii_time) [%(thread)] %(fileline:<28) %(level_name) %(logger_name:<12) - %(message)",
"%Y-%m-%d %H:%M:%S.%Qms", quill::Timezone::GmtTime);
// set the handler as the default handler for any newly created logger in the config
quill::Config cfg;
cfg.default_handlers.emplace_back(file_handler);
// configure must always be called prior to `start()`
quill::configure(cfg);
quill::start();- Removed some API functions from
Quill.hthat were previously used for configuration. Instead,quill::Configobject has to be created. For examplequill::config::set_backend_thread_cpu_affinity(1);has been removed and instead the following code is needed :
quill::Config cfg;
cfg.backend_thread_cpu_affinity = 1;
quill::configure(cfg);QUILL_CHRONO_CLOCKhas been moved fromTweakMe.htoConfig.h. It is now possible to switch betweenrdtscandsystemclocks without re-compiling. See example_trivial_system_clock.cppQUILL_RDTSC_RESYNC_INTERVALhas been moved fromTweakMe.htoConfig.h.- It is now possible to log user timestamps rather than the system's. This feature is useful for time simulations. See example_custom_clock.cpp and example_custom_clock_advanced.cpp
- Previously the logger names were limited to a maximum of 22 characters. This limitation has been removed.
- Added support for gcc 7.5.0. (#178)
- Updated bundled fmt to 9.0.0
Fixes
- Fix crash when a
std::stringcontaining null-terminated characters is passed to the logger. (#176)
Improvements
- Add a flag to RotatingFileHandler to disable removing the old files when
wmode is used.
From version v2 and onwards only c++17 is supported.
This version is a major refactor.
Fixes
- RotatingFileHandler will now correctly rotate the files when append mode is used (#123)
Improvements
- Reduced and simplified codebase.
- Improved backend worker thread performance.
QUILL_DUAL_QUEUE_MODEhas been removed. A single queue now handles every case.QUILL_STRINGhas been removed. That macro is no longer required when passing a format string to the PatternFormatter.
Differences
v1.7compiles with c++14,v2only compiles for c++17.v1.7on Windows supports wide character logging,v2has limited wide character support such as loggingwchar_t,std::wstring,std::wstring_view. For example, loggingstd::vector<std::wstring>is not supported.v1.7on Windows requires the filepath used for the handlers as a wide strings,v2supports only filenames as narrow strings.
Improvements/Fixes
- Fix crash on windows when a long wstring (>500 chars) is logged (#173)
- Fix compiler error when trying to compile with -DQUILL_DISABLE_NON_PREFIXED_MACROS (#174)
- Fix a compile warning in clang (#175)
Improvements/Fixes
- Fix compile error when C++20 is used on windows (#162)
Improvements/Fixes
- Fix support for wide characters on Windows (#168)
- Fix compilation error when
Quill::Logger*is stored as a class member in templated classes - Add
FilenameAppend::DateTimeas an option when creating a file handler
New Features
- Add a new function
quill::get_all_loggers()that returns all the existing loggers. (#114) - Add
%(level_id)to pattern formatter. (#136) - Users can now specialise
copy_loggable<T>to mark user defined types as safe to copy. (#132)
Improvements/Fixes
- Fix initializations for C++17.
- Fix compiler warning in
check_format()function. - Replace
QUILL_DUAL_QUEUE_MODEwithQUILL_DISABLE_DUAL_QUEUE_MODE. - Update bundled fmt to 8.1.1
- Minor performance and accuracy improvements to rdtsc clock used by the backend thread.
- Fix compile error when C++20 is used. (#162)
- Fix
get_page_size()to only call sysconf once. (#160) - Fix incorrect timestamps in the log file when the system clock is updated. (#127)
- Previously if
quill:start(true)was called more than once in the application, the signal handlers would get initialised again. Now any subsequent calls toquill:start(true)will now have no effect (#167) - Previously when the max limit of rotated files in
RotatingFileHandlerwas reached, quill would stop rotating and instead keep logging everything into the last log file. Now when the maximum limit of files is reached, quill will now keep rotating by replacing the oldest logs. (#157) - Improve the backend logging thread responsiveness when variables are logged in loops without any delay from multiple threads. (#116)
- Fix some undefined behaviour issues reported via the AddressSantizer on the backend logging thread. (#166)
Improvements/Fixes
- Add support for
%(thread_name)in PatternFormatter. (#97) - Add missing header needed for recent versions of fmt. (#95)
- Force flush all active handlers on application exit.
- Update bundled fmt to 8.0.1
Fixes
- Fix WIN32 compilation error when
NOMINMAXis already defined. - Fix
stringtowstringMinGW conversion. (#92) - Log enums via the main queue. (#90)
- Fix windows compiler error when
min/maxmacros are defined. (#94)
Improvements/Fixes
- Fix windows C++20 build. (#83)
- Fix ARM build on windows.
- Fix
example_backtraceand minor bug when destructing with empty backtrace.
New Features
- Dual queue mode offering even lower latencies on hot paths. See Dual Queue Mode.
- Added a signal handler for linux and windows. The signal handler flushes the log when the app crashes or exits. (#1)
- Added support for custom handlers. (#75)
- Quill now compiles and runs on Cygwin.
Improvements/Fixes
- The queue from the caller to the backend worker thread has been reworked. The new queue generates slightly better assembly than the previous one. Quill does no longer depend on mapping the same region of physical memory twice.
- Replaced an assertion check that could trigger incorrectly. (#68)
- Fixed build on
ARM_ARCH < 6. (#78) - Fixed compile errors when
QUILL_NOEXCEPTIONS,CMAKE_CXX_STANDARD 20,QUILL_USE_BOUNDED_QUEUEare set. - The unit tests have been moved to a separate binary with their own
main(). This increased build times when building the tests, but the failures are now easier to debug on different CI platforms and the tests can also run faster in parallel. - Fixed minor compiler warnings on windows.
- Upgraded bundled libfmt to
7.1.3
Note
- If a custom queue capacity is defined using
#define QUILL_QUEUE_CAPACITYafter1.6.0the whole library needs to be recompiled.
- Removed the use of
fmt::format()inFileUtilities.cppas a workaround to the link errors in fmt v7. Use the header only version of libfmt when external libfmt is defiend is no longer required.
- When QUILL_FMT_EXTERNAL is defined,
quillwill use the header only version oflibfmt. This is a workaround to the link errors after libftm v7
- Upgraded bundled libfmt to
7.1.2 - Added
Filters. The filter class can be used for filtering log records. Filters can be added to handler instances. See example_filters.cpp - It is now possible to set the log level severity on the handler objects. See example_filters.cpp (#49)
- Timestamp formatting optimisation for the backend worker thread.
- Free list allocator optimisation for the backend worker thread.
- Fixed PatternFormatter ignoring a portion of the pattern was ignored, when no format specifiers were present. (#56)
- When
%(function_name)is used in PatternFormatter the namespace delimiter is replaced from::to.(Windows only). (#61) - Arguments passed to the logger are no longer being evaluated when the log statement is not logged. (#67)
- PatternFormatter enhancement. It is now possible to pass {fmt} string syntax
to
QUILL_STRING. The default PatternFormatter string has been changed to:"%(ascii_time) [%(thread)] %(fileline:<28) LOG_%(level_name) %(logger_name:<12) - %(message)". This results to the following log being properly aligned despite the different lengths of each filename and logger name.
22:31:07.995438465 [2666041] file1.h:11 LOG_INFO logger1 - Log from file.
22:31:07.995445699 [2666041] long_file2.h:11 LOG_INFO logger_fl2 - Log from other file.
22:31:07.995457144 [2666041] a_longer_file_3.hpp:11 LOG_INFO logger_fl2_l - Log from other file.
22:31:07.995462471 [2666041] example_trivial.cpp:30 LOG_TRACE_L3 root - This is a log trace l3 example 1
- Do not force
quillto always build asstaticlibrary in cmake. - Minor fix when
quillis compiled with no exceptions. - Add the option to disable the non prefixed macro definitions if
QUILL_DISABLE_NON_PREFIXED_MACROSis defined. (#40)
- Added support for printing colour codes in the terminal. See ConsoleHandler
- RotatingFileHandler improvements and minor change in API. See RotatingFileHandler
- DailyFileHandler is removed and replaced by TimeRotatingFileHandler. See TimeRotatingFileHandler
- Added backtrace logging. Log messages can be stored in a buffer and flushed later on demand. See Backtrace Logging
- Added bundled
doctest2.4.0 - Migrated all tests from
gtesttodoctest. - Upgraded bundled libfmt to
7.0.3
- Upgraded bundled libfmt to
7.0.2 - Fixed compile error with libfmt versions >
7.0.0
- Add a CMake option
QUILL_USE_BOUNDED_QUEUEfor bounded queue. - Fixed a clang 10 warning
- Fixed MinGw build
- Minor CMake fixes when
QUILL_FMT_EXTERNALoption is used.
New Features
- Added option
QUILL_NO_EXCEPTIONSto disable exceptions, std::abort() is called instead of an exception. (#16) - Exceptions thrown in the backend worker thread, will now call a user provided error handler callback to handle the error. (#21)
- Compile time checks for unsafe to copy user defined types. Non trivial user defined types must be explicitly tagged as
safe to copy with the use of
QUILL_COPY_LOGGABLE;. Otherwise they have to be formatted and passed as a string to the logger by the user. The old unsafe mode is still usable by#define QUILL_MODE_UNSAFE(#20) - Added
QUILL_USE_BOUNDED_QUEUE. In this mode no new queues get allocated but instead log messages get lost. Number of lost messages is reported to stderr. - Minor hot path optimisation. The pointer to the metadata for each log message is no logger copied to the queue but passed as a template argument instead.
- Added a latency benchmark, easily extendable for any logger
Improvements/Fixes
QUILL_RDTSC_CLOCKoption is replaced byQUILL_CHRONO_CLOCKwhich is by OFF by default.- Improve compiler error message when trying to log a non copy constructible user defined type
- Fix buffer reallocation bug on TimestampFormatter. In previous versions any timestamp format set to 'set_pattern' expanding to a string longer than 32 bytes would cause a crash. (#24)
- The backend logging thread will now copy all messages from the SPSC queue to a local priority queue. This keeps the SPSC less empty avoiding a potential allocation on the hot path.
std::string_viewis now promoted tostd::stringto take a deep copy- The queue capacity has been moved from
configtoTweakme.h. - Multiple formats patterns support for
stdoutandstderrhandlers. See example_stdout_multiple_formatters.cpp quill::start()will now block until the backend worker has started.- Upgraded bundled libfmt to
6.2.1
- CMake changes to support package installation in conan.
- Support for
arm/arm64. (#19) - Add a cmake option
QUILL_ENABLE_INSTALLto enable cpack.
- Improved
QUILL_RDTSC_CLOCKtweak option. It is now possible to switch between usingrdtscorstd::chronoclock without having to recompile quill as library.
- Linking and including an external version of
fmtis now supported. SeeTweakMe.h - Fixed compiler warnings when using clang's
-Wdocumentation. (#12) - Fixed a bug that wouldn't report a compile-time error for invalid format strings. (#13)
- Added process ID to Formatter. (#14)
- Enhanced timestamp formatting. The
timestamp_formatstring passed inhandler->set_pattern(format_pattern, timestamp_format, timezone)now accepts three additional specifiers%Qms,%Qus,%Qusthat can be used to format the fractional seconds. See here. (#15)
- Daily file handler. The file handler rollover every 24 hours
- Rotating file handler. The file handler will rollover based on the size of the file
- MinGW compatibility
- Added a CMake option
QUILL_VERBOSE_MAKEFILE. Building Quill as a master project now defaults to non verbose makefile output unless-DQUILL_VERBOSE_MAKEFILE=ONis passed to CMake. (#6) - Flush policy improvement. Previously Quill backend worker thread would never
flush. This made watching the live log of the application harder because the user has to wait for the operating system to flush orquill::flush()had to be called on the caller threads. This has now been fixed, when the backend thread worker has no more log messages to process it will automaticallyflush. (#8) - The log level names have been changed from
"LOG_INFO","LOG_DEBUG", etc to"INFO","DEBUG", etc .. The default formatter string is now using"LOG_"%(level_name)instead of%(level_name)therefore there is now change in the behaviour. This change gives a lot of more flexibility to users who prefer to see e.g.INFOinstead ofLOG_INFOin the logs. (#7) - An option has been added to append the date to the filename when using a
FileHandler
quill::file_handler(filename, mode, FilenameAppend);. (#7) - It is now possible to specify the timezone of each handler timestamp. A new parameter is added
to
file_handler->set_pattern(...). SeePatternFormatter::Timezone. (#7) - Rename
emitas it can conflict with Qt macros. (#4) - Upgraded
libfmtto6.2.0.
- Initial release.
- Using
libfmtto6.1.2.


