From b0c5db6ad682abb665793304919819432f2c9b57 Mon Sep 17 00:00:00 2001 From: Odysseas Georgoudis Date: Sat, 24 Aug 2024 22:39:40 +0100 Subject: [PATCH] add PatternFormatterOptions --- CHANGELOG.md | 24 +++- CMakeLists.txt | 1 + .../quill_backend_throughput.cpp | 5 +- .../quill_backend_throughput_no_buffering.cpp | 5 +- .../qwrapper/include/qwrapper/qwrapper.cpp | 7 +- .../quill_hot_path_rdtsc_clock.cpp | 5 +- .../quill_hot_path_system_clock.cpp | 6 +- docs/examples.rst | 4 +- docs/formatters.rst | 4 +- docs/json_logging.rst | 8 +- docs/log_tagging.rst | 4 +- docs/sink_types.rst | 6 +- docs/timestamp_types.rst | 8 +- .../include/quill_wrapper/quill_wrapper.cpp | 7 +- examples/file_logging.cpp | 8 +- examples/json_console_logging.cpp | 3 +- examples/json_file_logging.cpp | 8 +- .../include/quill_wrapper/quill_wrapper.cpp | 8 +- examples/rotating_file_logging.cpp | 8 +- .../quill_wrapper_shared.cpp | 8 +- .../ConsoleSinkWithFormatter.h | 5 +- .../RotatingFileSinkWithFormatter.h | 6 +- .../single_logger_multiple_sink_formats_1.cpp | 6 +- .../single_logger_multiple_sink_formats_2.cpp | 5 +- examples/system_clock_logging.cpp | 6 +- examples/tags_logging.cpp | 7 +- examples/user_clock_source.cpp | 6 +- include/quill/CsvWriter.h | 10 +- include/quill/Frontend.h | 39 ++----- include/quill/Logger.h | 7 +- include/quill/backend/BackendWorker.h | 14 +-- include/quill/backend/PatternFormatter.h | 64 ++--------- include/quill/core/LoggerBase.h | 16 +-- include/quill/core/LoggerManager.h | 8 +- include/quill/core/PatternFormatterOptions.h | 105 ++++++++++++++++++ .../ConsoleSinkStderrMultipleFormatsTest.cpp | 3 +- .../ConsoleSinkStdoutMultipleFormatsTest.cpp | 3 +- .../FlushMultipleLoggers.cpp | 2 +- .../integration_tests/JsonFileLoggingTest.cpp | 5 +- .../JsonMultilineMetadataTest.cpp | 14 ++- .../JsonVariedParamsLoggingTest.cpp | 2 +- .../MultiFrontendThreadsTest.cpp | 8 +- .../MultilineMetadataTest.cpp | 14 ++- test/integration_tests/TagsLoggingTest.cpp | 5 +- .../integration_tests/UserClockSourceTest.cpp | 7 +- .../UserDefinedTypeLoggingTest.cpp | 5 +- test/unit_tests/LoggerManagerTest.cpp | 14 ++- test/unit_tests/LoggerTest.cpp | 10 +- test/unit_tests/PatternFormatterTest.cpp | 65 +++++------ 49 files changed, 340 insertions(+), 258 deletions(-) create mode 100644 include/quill/core/PatternFormatterOptions.h diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d34b4ad..18651429 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -98,10 +98,30 @@ output. To restore the previous behavior, set this option to false when creating a `Logger` using `Frontend::create_or_get_logger(...)`. Note that this option is ignored when logging JSON using named arguments in the format message. ([#534](https://github.com/odygrd/quill/pull/534)) -- The functions `Frontend::create_or_get_logger(...)` now takes an additional - parameter, `add_metadata_to_multi_line_logs`. - `JSON` sinks now automatically remove any `\n` characters from format messages, ensuring the emission of valid `JSON` messages even when `\n` is present in the format. +- The `Frontend::create_or_get_logger(...)` function now accepts a `PatternFormatterOptions` parameter, simplifying the + API. This is a breaking change. To migrate quickly, wrap the existing formatting parameters in a + `PatternFormatterOptions` object. + + **Before:** + ```c++ + 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:** + + ```c++ + 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}); + ``` ## v6.1.2 diff --git a/CMakeLists.txt b/CMakeLists.txt index d46db7bc..3305d4a9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -199,6 +199,7 @@ set(HEADER_FILES include/quill/core/LogLevel.h include/quill/core/MacroMetadata.h include/quill/core/MathUtils.h + include/quill/core/PatternFormatterOptions.h include/quill/core/QuillError.h include/quill/core/Rdtsc.h include/quill/core/SinkManager.h diff --git a/benchmarks/backend_throughput/quill_backend_throughput.cpp b/benchmarks/backend_throughput/quill_backend_throughput.cpp index 08c3b67e..36fea05e 100644 --- a/benchmarks/backend_throughput/quill_backend_throughput.cpp +++ b/benchmarks/backend_throughput/quill_backend_throughput.cpp @@ -37,8 +37,9 @@ int main() quill::Logger* logger = quill::Frontend::create_or_get_logger( "bench_logger", std::move(file_sink), - "%(time) [%(thread_id)] %(short_source_location) %(log_level) %(message)", "%H:%M:%S.%Qns", - quill::Timezone::LocalTime, false); + quill::PatternFormatterOptions{ + "%(time) [%(thread_id)] %(short_source_location) %(log_level) %(message)", "%H:%M:%S.%Qns", + quill::Timezone::LocalTime, false}); quill::Frontend::preallocate(); diff --git a/benchmarks/backend_throughput/quill_backend_throughput_no_buffering.cpp b/benchmarks/backend_throughput/quill_backend_throughput_no_buffering.cpp index b227d171..9e47e084 100644 --- a/benchmarks/backend_throughput/quill_backend_throughput_no_buffering.cpp +++ b/benchmarks/backend_throughput/quill_backend_throughput_no_buffering.cpp @@ -38,8 +38,9 @@ int main() quill::Logger* logger = quill::Frontend::create_or_get_logger( "bench_logger", std::move(file_sink), - "%(time) [%(thread_id)] %(short_source_location) %(log_level) %(message)", "%H:%M:%S.%Qns", - quill::Timezone::LocalTime, false); + quill::PatternFormatterOptions{ + "%(time) [%(thread_id)] %(short_source_location) %(log_level) %(message)", "%H:%M:%S.%Qns", + quill::Timezone::LocalTime, false}); ; quill::Frontend::preallocate(); diff --git a/benchmarks/compile_time/qwrapper/include/qwrapper/qwrapper.cpp b/benchmarks/compile_time/qwrapper/include/qwrapper/qwrapper.cpp index 2a217ebb..ede57975 100644 --- a/benchmarks/compile_time/qwrapper/include/qwrapper/qwrapper.cpp +++ b/benchmarks/compile_time/qwrapper/include/qwrapper/qwrapper.cpp @@ -11,8 +11,9 @@ void setup_quill(char const* log_file) auto console_sink = quill::Frontend::create_or_get_sink("s1"); - quill::Frontend::create_or_get_logger("root", std::move(console_sink), - "%(time) [%(thread_id)] %(short_source_location:<28) " + quill::Frontend::create_or_get_logger( + "root", std::move(console_sink), + quill::PatternFormatterOptions{"%(time) [%(thread_id)] %(short_source_location:<28) " "LOG_%(log_level:<9) %(logger:<12) %(message)", - "%H:%M:%S.%Qns", quill::Timezone::GmtTime); + "%H:%M:%S.%Qns", quill::Timezone::GmtTime}); } \ No newline at end of file diff --git a/benchmarks/hot_path_latency/quill_hot_path_rdtsc_clock.cpp b/benchmarks/hot_path_latency/quill_hot_path_rdtsc_clock.cpp index 52ca6884..e9dad066 100644 --- a/benchmarks/hot_path_latency/quill_hot_path_rdtsc_clock.cpp +++ b/benchmarks/hot_path_latency/quill_hot_path_rdtsc_clock.cpp @@ -56,8 +56,9 @@ void quill_benchmark(std::vector const& thread_count_array, Logger* logger = Frontend::create_or_get_logger( "bench_logger", std::move(file_sink), - "%(time) [%(thread_id)] %(short_source_location) %(log_level) %(message)", "%H:%M:%S.%Qns", - quill::Timezone::LocalTime, false); + quill::PatternFormatterOptions{ + "%(time) [%(thread_id)] %(short_source_location) %(log_level) %(message)", "%H:%M:%S.%Qns", + quill::Timezone::LocalTime, false}); /** LOGGING THREAD FUNCTIONS - on_start, on_exit, log_func must be implemented **/ /** those run on a several thread(s). It can be one or multiple threads based on THREAD_LIST_COUNT config */ diff --git a/benchmarks/hot_path_latency/quill_hot_path_system_clock.cpp b/benchmarks/hot_path_latency/quill_hot_path_system_clock.cpp index d1b2d412..a25f5ebe 100644 --- a/benchmarks/hot_path_latency/quill_hot_path_system_clock.cpp +++ b/benchmarks/hot_path_latency/quill_hot_path_system_clock.cpp @@ -56,8 +56,10 @@ void quill_benchmark(std::vector const& thread_count_array, Logger* logger = Frontend::create_or_get_logger( "bench_logger", std::move(file_sink), - "%(time) [%(thread_id)] %(short_source_location) %(log_level) %(message)", "%H:%M:%S.%Qns", - quill::Timezone::LocalTime, false, quill::ClockSourceType::System); + quill::PatternFormatterOptions{ + "%(time) [%(thread_id)] %(short_source_location) %(log_level) %(message)", "%H:%M:%S.%Qns", + quill::Timezone::LocalTime, false}, + quill::ClockSourceType::System); /** LOGGING THREAD FUNCTIONS - on_start, on_exit, log_func must be implemented **/ /** those run on a several thread(s). It can be one or multiple threads based on THREAD_LIST_COUNT config */ diff --git a/docs/examples.rst b/docs/examples.rst index ee944af7..7c2e1332 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -92,9 +92,9 @@ Logging to file quill::Logger* logger = quill::Frontend::create_or_get_logger("root", std::move(file_sink), - "%(time) [%(thread_id)] %(short_source_location:<28) " + quill::PatternFormatterOptions { "%(time) [%(thread_id)] %(short_source_location:<28) " "LOG_%(log_level:<9) %(logger:<12) %(message)", - "%H:%M:%S.%Qns", quill::Timezone::GmtTime); + "%H:%M:%S.%Qns", quill::Timezone::GmtTime }); // set the log level of the logger to debug (default is info) logger->set_log_level(quill::LogLevel::Debug); diff --git a/docs/formatters.rst b/docs/formatters.rst index 49266740..63ebb7b6 100644 --- a/docs/formatters.rst +++ b/docs/formatters.rst @@ -96,6 +96,6 @@ Customizing Log Message Formats quill::Logger* logger = quill::Frontend::create_or_get_logger("root", std::move(sink), - "%(time) [%(thread_id)] %(short_source_location:<28) " + quill::PatternFormatterOptions { "%(time) [%(thread_id)] %(short_source_location:<28) " "LOG_%(log_level:<9) %(logger:<12) %(message)", - "%H:%M:%S.%Qns", quill::Timezone::GmtTime); \ No newline at end of file + "%H:%M:%S.%Qns", quill::Timezone::GmtTime }); \ No newline at end of file diff --git a/docs/json_logging.rst b/docs/json_logging.rst index 6ff64906..bef1d34e 100644 --- a/docs/json_logging.rst +++ b/docs/json_logging.rst @@ -30,7 +30,7 @@ Logging Json to Console // When logging json, it is ideal to set the logging pattern to empty to avoid unnecessary message formatting. quill::Logger* logger = quill::Frontend::create_or_get_logger( - "json_logger", std::move(json_sink), "", "%H:%M:%S.%Qns", quill::Timezone::GmtTime); + "json_logger", std::move(json_sink), quill::PatternFormatterOptions { "", "%H:%M:%S.%Qns", quill::Timezone::GmtTime }); int var_a = 123; std::string var_b = "test"; @@ -70,7 +70,7 @@ Logging Json to File // When logging json, it is ideal to set the logging pattern to empty to avoid unnecessary message formatting. quill::Logger* logger = quill::Frontend::create_or_get_logger( - "json_logger", std::move(json_sink), "", "%H:%M:%S.%Qns", quill::Timezone::GmtTime); + "json_logger", std::move(json_sink), quill::PatternFormatterOptions { "", "%H:%M:%S.%Qns", quill::Timezone::GmtTime }); int var_a = 123; std::string var_b = "test"; @@ -117,8 +117,8 @@ Combining JSON and Standard Log Patterns // We set a custom format pattern here to also include the named_args quill::Logger* hybrid_logger = quill::Frontend::create_or_get_logger( "hybrid_logger", {std::move(json_sink), std::move(console_sink)}, - "%(time) [%(thread_id)] %(short_source_location:<28) LOG_%(log_level:<9) %(logger:<20) " - "%(message) [%(named_args)]"); + quill::PatternFormatterOptions { "%(time) [%(thread_id)] %(short_source_location:<28) LOG_%(log_level:<9) %(logger:<20) " + "%(message) [%(named_args)]" }); for (int i = 2; i < 4; ++i) { diff --git a/docs/log_tagging.rst b/docs/log_tagging.rst index 50c34402..62b45b8a 100644 --- a/docs/log_tagging.rst +++ b/docs/log_tagging.rst @@ -41,9 +41,9 @@ To include tags in your log statements, use the `_TAGS` macros. You will also ne quill::Logger* logger = quill::Frontend::create_or_get_logger( "root", std::move(console_sink), - "%(time) [%(thread_id)] %(short_source_location:<28) %(log_level:<9) " + quill::PatternFormatterOptions { "%(time) [%(thread_id)] %(short_source_location:<28) %(log_level:<9) " "%(tags)%(message)", - "%Y-%m-%d %H:%M:%S.%Qms", quill::Timezone::GmtTime); + "%Y-%m-%d %H:%M:%S.%Qms", quill::Timezone::GmtTime }); LOG_INFO_TAGS(logger, TAGS("random"), "Debug with tags"); LOG_INFO_TAGS(logger, TAGS(TAG_2), "Info with tags"); diff --git a/docs/sink_types.rst b/docs/sink_types.rst index f59cde9b..a4f3ecbe 100644 --- a/docs/sink_types.rst +++ b/docs/sink_types.rst @@ -98,7 +98,7 @@ The :cpp:class:`quill::JsonFileSink` and :cpp:class:`quill::JsonConsoleSink` ena // When using the JsonFileSink, it is ideal to set the logging pattern to empty to avoid unnecessary message formatting. quill::Logger* json_logger = quill::Frontend::create_or_get_logger( - "json_logger", std::move(json_sink), "", "%H:%M:%S.%Qns", quill::Timezone::GmtTime); + "json_logger", std::move(json_sink), quill::PatternFormatterOptions { "", "%H:%M:%S.%Qns", quill::Timezone::GmtTime }); for (int i = 0; i < 2; ++i) { @@ -113,8 +113,8 @@ The :cpp:class:`quill::JsonFileSink` and :cpp:class:`quill::JsonConsoleSink` ena // We set a custom format pattern here to also include the named_args quill::Logger* hybrid_logger = quill::Frontend::create_or_get_logger( "hybrid_logger", {std::move(json_sink_2), std::move(console_sink)}, - "%(time) [%(thread_id)] %(short_source_location:<28) LOG_%(log_level:<9) %(logger:<20) " - "%(message) [%(named_args)]"); + quill::PatternFormatterOptions { "%(time) [%(thread_id)] %(short_source_location:<28) LOG_%(log_level:<9) %(logger:<20) " + "%(message) [%(named_args)]" }); for (int i = 0; i < 2; ++i) { diff --git a/docs/timestamp_types.rst b/docs/timestamp_types.rst index a6e0fff3..ae5af5d7 100644 --- a/docs/timestamp_types.rst +++ b/docs/timestamp_types.rst @@ -83,8 +83,8 @@ Providing a Custom Timestamp auto console_sink = quill::Frontend::create_or_get_sink("sink_id_1"); quill::Logger* logger = quill::Frontend::create_or_get_logger( "root", std::move(console_sink), - "%(time) %(short_source_location:<28) LOG_%(log_level:<9) %(logger:<12) %(message)", - "%D %H:%M:%S.%Qns", quill::Timezone::LocalTime, quill::ClockSourceType::User, &simulated_clock); + quill::PatternFormatterOptions { "%(time) %(short_source_location:<28) LOG_%(log_level:<9) %(logger:<12) %(message)", + "%D %H:%M:%S.%Qns", quill::Timezone::LocalTime }, quill::ClockSourceType::User, &simulated_clock); // Set our timestamp to Sunday 12 June 2022 simulated_clock.set_timestamp(std::chrono::seconds{1655007309}); @@ -122,9 +122,9 @@ To achieve this, you can use the :cpp:class:`quill::BackendTscClock`. See the ex // Ensure at least one logger with quill::ClockSourceType::Tsc is created for BackendTscClock to function quill::Logger* logger = quill::Frontend::create_or_get_logger( "root", std::move(console_sink), - "%(time) [%(thread_id)] %(short_source_location:<28) LOG_%(log_level:<9) %(logger:<12) " + quill::PatternFormatterOptions { "%(time) [%(thread_id)] %(short_source_location:<28) LOG_%(log_level:<9) %(logger:<12) " "%(message)", - "%H:%M:%S.%Qns", quill::Timezone::LocalTime, quill::ClockSourceType::Tsc); + "%H:%M:%S.%Qns", quill::Timezone::LocalTime }, quill::ClockSourceType::Tsc); // Log an informational message which will also init the backend RdtscClock LOG_INFO(logger, "This is a log info example with number {}", 123); diff --git a/examples/advanced/quill_wrapper/include/quill_wrapper/quill_wrapper.cpp b/examples/advanced/quill_wrapper/include/quill_wrapper/quill_wrapper.cpp index ebe30161..1fe08c44 100644 --- a/examples/advanced/quill_wrapper/include/quill_wrapper/quill_wrapper.cpp +++ b/examples/advanced/quill_wrapper/include/quill_wrapper/quill_wrapper.cpp @@ -14,8 +14,9 @@ void setup_quill(char const* log_file) auto console_sink = quill::Frontend::create_or_get_sink("console_sink"); // Create and store the logger - quill::Frontend::create_or_get_logger("root", std::move(console_sink), - "%(time) [%(thread_id)] %(short_source_location:<28) " + quill::Frontend::create_or_get_logger( + "root", std::move(console_sink), + quill::PatternFormatterOptions{"%(time) [%(thread_id)] %(short_source_location:<28) " "LOG_%(log_level:<9) %(logger:<12) %(message)", - "%H:%M:%S.%Qns", quill::Timezone::GmtTime); + "%H:%M:%S.%Qns", quill::Timezone::GmtTime}); } \ No newline at end of file diff --git a/examples/file_logging.cpp b/examples/file_logging.cpp index a4763ec7..8545be02 100644 --- a/examples/file_logging.cpp +++ b/examples/file_logging.cpp @@ -44,11 +44,11 @@ int main() }(), quill::FileEventNotifier{}); - quill::Logger* logger = - quill::Frontend::create_or_get_logger("root", std::move(file_sink), - "%(time) [%(thread_id)] %(short_source_location:<28) " + 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); + "%H:%M:%S.%Qns", quill::Timezone::GmtTime}); // set the log level of the logger to debug (default is info) logger->set_log_level(quill::LogLevel::Debug); diff --git a/examples/json_console_logging.cpp b/examples/json_console_logging.cpp index 5df9643d..c548e263 100644 --- a/examples/json_console_logging.cpp +++ b/examples/json_console_logging.cpp @@ -19,7 +19,8 @@ int main() // When logging json, it is ideal to set the logging pattern to empty to avoid unnecessary message formatting. quill::Logger* logger = quill::Frontend::create_or_get_logger( - "json_logger", std::move(json_sink), "", "%H:%M:%S.%Qns", quill::Timezone::GmtTime); + "json_logger", std::move(json_sink), + quill::PatternFormatterOptions{"", "%H:%M:%S.%Qns", quill::Timezone::GmtTime}); int var_a = 123; std::string var_b = "test"; diff --git a/examples/json_file_logging.cpp b/examples/json_file_logging.cpp index 051808b8..73f2cb40 100644 --- a/examples/json_file_logging.cpp +++ b/examples/json_file_logging.cpp @@ -38,7 +38,8 @@ int main() // When using the JsonFileSink, it is ideal to set the logging pattern to empty to avoid unnecessary message formatting. quill::Logger* json_logger = quill::Frontend::create_or_get_logger( - "json_logger", std::move(json_sink), "", "%H:%M:%S.%Qns", quill::Timezone::GmtTime); + "json_logger", std::move(json_sink), + quill::PatternFormatterOptions{"", "%H:%M:%S.%Qns", quill::Timezone::GmtTime}); for (int i = 0; i < 2; ++i) { @@ -53,8 +54,9 @@ int main() // We set a custom format pattern here to also include the named_args quill::Logger* hybrid_logger = quill::Frontend::create_or_get_logger( "hybrid_logger", {std::move(json_sink_2), std::move(console_sink)}, - "%(time) [%(thread_id)] %(short_source_location:<28) LOG_%(log_level:<9) %(logger:<20) " - "%(message) [%(named_args)]"); + quill::PatternFormatterOptions{ + "%(time) [%(thread_id)] %(short_source_location:<28) LOG_%(log_level:<9) %(logger:<20) " + "%(message) [%(named_args)]"}); for (int i = 2; i < 4; ++i) { diff --git a/examples/recommended_usage/quill_wrapper/include/quill_wrapper/quill_wrapper.cpp b/examples/recommended_usage/quill_wrapper/include/quill_wrapper/quill_wrapper.cpp index af057c9b..de8e9f21 100644 --- a/examples/recommended_usage/quill_wrapper/include/quill_wrapper/quill_wrapper.cpp +++ b/examples/recommended_usage/quill_wrapper/include/quill_wrapper/quill_wrapper.cpp @@ -27,9 +27,9 @@ void setup_quill(char const* log_file) quill::FileEventNotifier{}); // Create and store the logger - global_logger_a = - quill::Frontend::create_or_get_logger("root", std::move(file_sink), - "%(time) [%(thread_id)] %(short_source_location:<28) " + global_logger_a = 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); + "%H:%M:%S.%Qns", quill::Timezone::GmtTime}); } \ No newline at end of file diff --git a/examples/rotating_file_logging.cpp b/examples/rotating_file_logging.cpp index da3c1732..4fcbfbec 100644 --- a/examples/rotating_file_logging.cpp +++ b/examples/rotating_file_logging.cpp @@ -31,11 +31,11 @@ int main() return cfg; }()); - quill::Logger* logger = - quill::Frontend::create_or_get_logger("root", std::move(rotating_file_sink), - "%(time) [%(thread_id)] %(short_source_location:<28) " + quill::Logger* logger = quill::Frontend::create_or_get_logger( + "root", std::move(rotating_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); + "%H:%M:%S.%Qns", quill::Timezone::GmtTime}); for (int i = 0; i < 20; ++i) { diff --git a/examples/shared_library/quill_wrapper_shared/include/quill_wrapper_shared/quill_wrapper_shared.cpp b/examples/shared_library/quill_wrapper_shared/include/quill_wrapper_shared/quill_wrapper_shared.cpp index 45f1a135..9030a8d5 100644 --- a/examples/shared_library/quill_wrapper_shared/include/quill_wrapper_shared/quill_wrapper_shared.cpp +++ b/examples/shared_library/quill_wrapper_shared/include/quill_wrapper_shared/quill_wrapper_shared.cpp @@ -17,9 +17,9 @@ void setup_quill() auto console_sink = quill::Frontend::create_or_get_sink("sink_id_1"); // Create and store the logger - global_logger_a = - quill::Frontend::create_or_get_logger("root", std::move(console_sink), - "%(time) [%(thread_id)] %(short_source_location:<28) " + global_logger_a = quill::Frontend::create_or_get_logger( + "root", std::move(console_sink), + quill::PatternFormatterOptions{"%(time) [%(thread_id)] %(short_source_location:<28) " "LOG_%(log_level:<9) %(logger:<12) %(message)", - "%H:%M:%S.%Qns", quill::Timezone::GmtTime); + "%H:%M:%S.%Qns", quill::Timezone::GmtTime}); } \ No newline at end of file diff --git a/examples/single_logger_multiple_sink_formats/ConsoleSinkWithFormatter.h b/examples/single_logger_multiple_sink_formats/ConsoleSinkWithFormatter.h index 812072eb..6a097f8c 100644 --- a/examples/single_logger_multiple_sink_formats/ConsoleSinkWithFormatter.h +++ b/examples/single_logger_multiple_sink_formats/ConsoleSinkWithFormatter.h @@ -12,10 +12,9 @@ class ConsoleSinkWithFormatter : public quill::ConsoleSink { public: - ConsoleSinkWithFormatter(std::string const& format_pattern, std::string const& time_format, - quill::Timezone timestamp_timezone = quill::Timezone::LocalTime, + ConsoleSinkWithFormatter(quill::PatternFormatterOptions const& pattern_formater_options, bool enable_colours = true, std::string const& stream = "stdout") - : quill::ConsoleSink(enable_colours, stream), _formatter(format_pattern, time_format, timestamp_timezone) + : quill::ConsoleSink(enable_colours, stream), _formatter(pattern_formater_options) { } diff --git a/examples/single_logger_multiple_sink_formats/RotatingFileSinkWithFormatter.h b/examples/single_logger_multiple_sink_formats/RotatingFileSinkWithFormatter.h index a7c01787..81d52498 100644 --- a/examples/single_logger_multiple_sink_formats/RotatingFileSinkWithFormatter.h +++ b/examples/single_logger_multiple_sink_formats/RotatingFileSinkWithFormatter.h @@ -13,11 +13,9 @@ class RotatingFileSinkWithFormatter : public quill::RotatingFileSink { public: RotatingFileSinkWithFormatter(quill::fs::path const& filename, quill::RotatingFileSinkConfig const& config, - std::string const& format_pattern, std::string const& time_format, - quill::Timezone timestamp_timezone = quill::Timezone::LocalTime, + quill::PatternFormatterOptions const& pattern_formatter_options, quill::FileEventNotifier file_event_notifier = quill::FileEventNotifier{}) - : quill::RotatingFileSink(filename, config, file_event_notifier), - _formatter(format_pattern, time_format, timestamp_timezone) + : quill::RotatingFileSink(filename, config, file_event_notifier), _formatter(pattern_formatter_options) { } diff --git a/examples/single_logger_multiple_sink_formats/single_logger_multiple_sink_formats_1.cpp b/examples/single_logger_multiple_sink_formats/single_logger_multiple_sink_formats_1.cpp index 0ccfe05f..d85ae315 100644 --- a/examples/single_logger_multiple_sink_formats/single_logger_multiple_sink_formats_1.cpp +++ b/examples/single_logger_multiple_sink_formats/single_logger_multiple_sink_formats_1.cpp @@ -38,14 +38,16 @@ int main() cfg.set_rotation_max_file_size(1024 * 1024); return cfg; }(), - file_log_pattern, file_time_format); + quill::PatternFormatterOptions{file_log_pattern, file_time_format}); + rotating_file_sink->set_log_level_filter(quill::LogLevel::Info); // The Logger is using the console_log_pattern by default // To output our custom format to the file we use our own RotatingFileSinkWithFormatter that is // overwriting the default format quill::Logger* logger = quill::Frontend::create_or_get_logger( - "root", {std::move(console_sink), std::move(rotating_file_sink)}, console_log_pattern, console_time_format); + "root", {std::move(console_sink), std::move(rotating_file_sink)}, + quill::PatternFormatterOptions{console_log_pattern, console_time_format}); logger->set_log_level(quill::LogLevel::Debug); diff --git a/examples/single_logger_multiple_sink_formats/single_logger_multiple_sink_formats_2.cpp b/examples/single_logger_multiple_sink_formats/single_logger_multiple_sink_formats_2.cpp index 1aaec67c..c3a1db82 100644 --- a/examples/single_logger_multiple_sink_formats/single_logger_multiple_sink_formats_2.cpp +++ b/examples/single_logger_multiple_sink_formats/single_logger_multiple_sink_formats_2.cpp @@ -21,7 +21,7 @@ int main() "%(time) [PID %(process_id)] [%(log_level)] [%(logger)] - %(message)"; std::string console_time_format = "%Y-%m-%d %H:%M:%S.%Qms"; auto console_sink = quill::Frontend::create_or_get_sink( - "sink_id_1", console_log_pattern, console_time_format); + "sink_id_1", quill::PatternFormatterOptions{console_log_pattern, console_time_format}); console_sink->set_log_level_filter(quill::LogLevel::Warning); // File sink @@ -45,7 +45,8 @@ int main() // To output our custom format to the file we use our own ConsoleSinkWithFormatter that is // overwriting the default format quill::Logger* logger = quill::Frontend::create_or_get_logger( - "root", {std::move(console_sink), std::move(rotating_file_sink)}, file_log_pattern, file_time_format); + "root", {std::move(console_sink), std::move(rotating_file_sink)}, + quill::PatternFormatterOptions{file_log_pattern, file_time_format}); logger->set_log_level(quill::LogLevel::Debug); diff --git a/examples/system_clock_logging.cpp b/examples/system_clock_logging.cpp index d7236b1c..05287535 100644 --- a/examples/system_clock_logging.cpp +++ b/examples/system_clock_logging.cpp @@ -22,8 +22,10 @@ int main() auto console_sink = quill::Frontend::create_or_get_sink("sink_id_1"); quill::Logger* logger = quill::Frontend::create_or_get_logger( - "root", std::move(console_sink), "%(time) [%(process_id)] [%(thread_id)] %(logger) - %(message)", - "%D %H:%M:%S.%Qms %z", quill::Timezone::GmtTime, false, quill::ClockSourceType::System); + "root", std::move(console_sink), + quill::PatternFormatterOptions{"%(time) [%(process_id)] [%(thread_id)] %(logger) - %(message)", + "%D %H:%M:%S.%Qms %z", quill::Timezone::GmtTime, false}, + quill::ClockSourceType::System); // Change the LogLevel to print everything logger->set_log_level(quill::LogLevel::TraceL3); diff --git a/examples/tags_logging.cpp b/examples/tags_logging.cpp index 1ddbf67c..5bf3fec3 100644 --- a/examples/tags_logging.cpp +++ b/examples/tags_logging.cpp @@ -28,9 +28,10 @@ int main() quill::Logger* logger = quill::Frontend::create_or_get_logger( "root", std::move(console_sink), - "%(time) [%(thread_id)] %(short_source_location:<28) %(log_level:<9) " - "%(tags)%(message)", - "%Y-%m-%d %H:%M:%S.%Qms", quill::Timezone::GmtTime); + quill::PatternFormatterOptions{ + "%(time) [%(thread_id)] %(short_source_location:<28) %(log_level:<9) " + "%(tags)%(message)", + "%Y-%m-%d %H:%M:%S.%Qms", quill::Timezone::GmtTime}); LOG_INFO_TAGS(logger, TAGS("random"), "Debug with tags"); LOG_INFO_TAGS(logger, TAGS(TAG_2), "Info with tags"); diff --git a/examples/user_clock_source.cpp b/examples/user_clock_source.cpp index 4d9c82fe..4a6d4ab3 100644 --- a/examples/user_clock_source.cpp +++ b/examples/user_clock_source.cpp @@ -63,8 +63,10 @@ int main() quill::Logger* logger = quill::Frontend::create_or_get_logger( "root", std::move(console_sink), - "%(time) %(short_source_location:<28) LOG_%(log_level:<9) %(logger:<12) %(message)", - "%D %H:%M:%S.%Qns", quill::Timezone::LocalTime, false, quill::ClockSourceType::User, &simulated_clock); + quill::PatternFormatterOptions{ + "%(time) %(short_source_location:<28) LOG_%(log_level:<9) %(logger:<12) %(message)", + "%D %H:%M:%S.%Qns", quill::Timezone::LocalTime, false}, + quill::ClockSourceType::User, &simulated_clock); // Change the LogLevel to print everything logger->set_log_level(quill::LogLevel::TraceL3); diff --git a/include/quill/CsvWriter.h b/include/quill/CsvWriter.h index fabc6397..7378668c 100644 --- a/include/quill/CsvWriter.h +++ b/include/quill/CsvWriter.h @@ -61,7 +61,7 @@ class CsvWriter cfg.set_filename_append_option(filename_append); return cfg; }()), - "%(message)", "", Timezone::GmtTime); + quill::PatternFormatterOptions{"%(message)", "", Timezone::GmtTime}); _logger->template log_statement(quill::LogLevel::None, &header_metadata, TCsvSchema::header); } @@ -74,8 +74,9 @@ class CsvWriter */ CsvWriter(std::string const& unique_name, std::shared_ptr sink) { - _logger = Frontend::create_or_get_logger(unique_name + "_csv", std::move(sink), "%(message)", - "", Timezone::GmtTime); + _logger = + Frontend::create_or_get_logger(unique_name + "_csv", std::move(sink), + quill::PatternFormatterOptions{"%(message)", "", Timezone::GmtTime}); _logger->template log_statement(quill::LogLevel::None, &header_metadata, TCsvSchema::header); } @@ -88,7 +89,8 @@ class CsvWriter */ CsvWriter(std::string const& unique_name, std::initializer_list> sinks) { - _logger = Frontend::create_or_get_logger(unique_name + "_csv", sinks, "%(message)", "", Timezone::GmtTime); + _logger = Frontend::create_or_get_logger( + unique_name + "_csv", sinks, quill::PatternFormatterOptions{"%(message)", "", Timezone::GmtTime}); _logger->template log_statement(quill::LogLevel::None, &header_metadata, TCsvSchema::header); } diff --git a/include/quill/Frontend.h b/include/quill/Frontend.h index cb70af1a..a16b4344 100644 --- a/include/quill/Frontend.h +++ b/include/quill/Frontend.h @@ -11,6 +11,7 @@ #include "quill/core/Common.h" #include "quill/core/FrontendOptions.h" #include "quill/core/LoggerManager.h" +#include "quill/core/PatternFormatterOptions.h" #include "quill/core/QuillError.h" #include "quill/core/SinkManager.h" #include "quill/core/ThreadContextManager.h" @@ -78,32 +79,22 @@ class FrontendImpl * * @param logger_name The name of the logger. * @param sink A shared pointer to the sink to associate with the logger. - * @param format_pattern The format pattern for log messages. - * @param time_pattern The time pattern for log timestamps. - * @param timestamp_timezone The timezone for log timestamps. - * @param add_metadata_to_multi_line_logs If true, ensures that metadata (such as timestamps and log levels) is appended to every line in multi-line log entries, maintaining consistency in log outputs. - * Note: This option is ignored when logging `JSON` with named arguments in the format message. - * Note: This option only applies to multi-line log entries. It can be disabled if you prefer not to append metadata or if your logs are exclusively single-line entries. + * @param pattern_formatter_options Contains the formatting configuration for PatternFormatter * @param clock_source The clock source for log timestamps. * @param user_clock A pointer to a custom user clock. * * @return Logger* A pointer to the created or retrieved logger. */ - static logger_t* create_or_get_logger( - std::string const& logger_name, std::shared_ptr sink, - std::string const& format_pattern = - "%(time) [%(thread_id)] %(short_source_location:<28) LOG_%(log_level:<9) %(logger:<12) " - "%(message)", - std::string const& time_pattern = "%H:%M:%S.%Qns", - Timezone timestamp_timezone = Timezone::LocalTime, bool add_metadata_to_multi_line_logs = true, - ClockSourceType clock_source = ClockSourceType::Tsc, UserClockSource* user_clock = nullptr) + static logger_t* create_or_get_logger(std::string const& logger_name, std::shared_ptr sink, + PatternFormatterOptions const& pattern_formatter_options = PatternFormatterOptions{}, + ClockSourceType clock_source = ClockSourceType::Tsc, UserClockSource* user_clock = nullptr) { std::vector> sinks; sinks.push_back(static_cast&&>(sink)); return _cast_to_logger(detail::LoggerManager::instance().create_or_get_logger( - logger_name, static_cast>&&>(sinks), format_pattern, - time_pattern, timestamp_timezone, add_metadata_to_multi_line_logs, clock_source, user_clock)); + logger_name, static_cast>&&>(sinks), + pattern_formatter_options, clock_source, user_clock)); } /** @@ -111,28 +102,18 @@ class FrontendImpl * * @param logger_name The name of the logger. * @param sinks An initializer list of shared pointers to sinks to associate with the logger. - * @param format_pattern The format pattern for log messages. - * @param time_pattern The time pattern for log timestamps. - * @param timestamp_timezone The timezone for log timestamps. - * @param add_metadata_to_multi_line_logs If true, ensures that metadata (such as timestamps and log levels) is appended to every line in multi-line log entries, maintaining consistency in log outputs. - * Note: This option is ignored when logging `JSON` with named arguments in the format message. - * Note: This option only applies to multi-line log entries. It can be disabled if you prefer not to append metadata or if your logs are exclusively single-line entries. + * @param pattern_formatter_options Contains the formatting configuration for PatternFormatter * @param clock_source The clock source for log timestamps. * @param user_clock A pointer to a custom user clock. * @return Logger* A pointer to the created or retrieved logger. */ static logger_t* create_or_get_logger( std::string const& logger_name, std::initializer_list> sinks, - std::string const& format_pattern = - "%(time) [%(thread_id)] %(short_source_location:<28) LOG_%(log_level:<9) %(logger:<12) " - "%(message)", - std::string const& time_pattern = "%H:%M:%S.%Qns", - Timezone timestamp_timezone = Timezone::LocalTime, bool add_metadata_to_multi_line_logs = true, + PatternFormatterOptions const& pattern_formatter_options = PatternFormatterOptions{}, ClockSourceType clock_source = ClockSourceType::Tsc, UserClockSource* user_clock = nullptr) { return _cast_to_logger(detail::LoggerManager::instance().create_or_get_logger( - logger_name, std::vector>{sinks}, format_pattern, time_pattern, - timestamp_timezone, add_metadata_to_multi_line_logs, clock_source, user_clock)); + logger_name, std::vector>{sinks}, pattern_formatter_options, clock_source, user_clock)); } /** diff --git a/include/quill/Logger.h b/include/quill/Logger.h index 00bc8b7b..e3177d92 100644 --- a/include/quill/Logger.h +++ b/include/quill/Logger.h @@ -312,12 +312,11 @@ class LoggerImpl : public detail::LoggerBase /***/ LoggerImpl(std::string logger_name, std::vector> sinks, - std::string format_pattern, std::string time_pattern, Timezone timestamp_timezone, - bool add_metadata_to_multi_line_logs, ClockSourceType clock_source, UserClockSource* user_clock) + PatternFormatterOptions pattern_formatter_options, ClockSourceType clock_source, + UserClockSource* user_clock) : detail::LoggerBase(static_cast(logger_name), static_cast>&&>(sinks), - static_cast(format_pattern), static_cast(time_pattern), - timestamp_timezone, add_metadata_to_multi_line_logs, clock_source, user_clock) + static_cast(pattern_formatter_options), clock_source, user_clock) { if (this->user_clock) diff --git a/include/quill/backend/BackendWorker.h b/include/quill/backend/BackendWorker.h index 336b302e..ec50c297 100644 --- a/include/quill/backend/BackendWorker.h +++ b/include/quill/backend/BackendWorker.h @@ -493,13 +493,7 @@ class BackendWorker [transit_event](LoggerBase* logger) { if (logger->pattern_formatter && - (logger->pattern_formatter->format_pattern() == transit_event->logger_base->format_pattern) && - (logger->pattern_formatter->get_add_metadata_to_multi_line_logs() == - transit_event->logger_base->add_metadata_to_multi_line_logs) && - (logger->pattern_formatter->timestamp_formatter().time_format() == - transit_event->logger_base->time_pattern) && - (logger->pattern_formatter->timestamp_formatter().timestamp_timezone() == - transit_event->logger_base->timezone)) + (logger->pattern_formatter->get_options() == transit_event->logger_base->pattern_formatter_options)) { // hold a copy of the shared_ptr of the same formatter transit_event->logger_base->pattern_formatter = logger->pattern_formatter; @@ -512,9 +506,7 @@ class BackendWorker if (!transit_event->logger_base->pattern_formatter) { // Didn't find an existing formatter need to create a new pattern formatter - transit_event->logger_base->pattern_formatter = std::make_shared( - transit_event->logger_base->format_pattern, transit_event->logger_base->time_pattern, - transit_event->logger_base->timezone, transit_event->logger_base->add_metadata_to_multi_line_logs); + transit_event->logger_base->pattern_formatter = std::make_shared(transit_event->logger_base->pattern_formatter_options); } } @@ -817,7 +809,7 @@ class BackendWorker detail::log_level_to_string(transit_event.log_level(), _options.log_level_short_codes.data(), _options.log_level_short_codes.size()); - if (transit_event.logger_base->pattern_formatter->get_add_metadata_to_multi_line_logs() && + if (transit_event.logger_base->pattern_formatter->get_options().add_metadata_to_multi_line_logs && (!transit_event.named_args || transit_event.named_args->empty())) { // This is only supported when named_args are not used diff --git a/include/quill/backend/PatternFormatter.h b/include/quill/backend/PatternFormatter.h index 0dc60c4c..fca99276 100644 --- a/include/quill/backend/PatternFormatter.h +++ b/include/quill/backend/PatternFormatter.h @@ -11,6 +11,7 @@ #include "quill/core/Attributes.h" #include "quill/core/Common.h" #include "quill/core/MacroMetadata.h" +#include "quill/core/PatternFormatterOptions.h" #include "quill/core/QuillError.h" #include @@ -67,44 +68,16 @@ class PatternFormatter /** Main PatternFormatter class **/ public: /** - * Constructor for a PatterFormatter with a custom format - * @param format_pattern format_pattern a format string. + * Constructor for a PatternFormatter with custom formatting options. * - * The following attribute names can be used with the corresponding placeholder in a %-style format string. - * @note: The same attribute can not be used twice in the same format pattern + * @param options The PatternFormatterOptions object containing the formatting configuration. + * @see PatternFormatterOptions for detailed information on available options. * - * %(time) - Human-readable timestamp representing when the log statement was created. - * %(file_name) - Name of the source file where the logging call was issued. - * %(full_path) - Full path of the source file where the logging call was issued. - * %(caller_function) - Name of the function containing the logging call. - * %(log_level) - Textual representation of the logging level for the message. - * %(log_level_short_code) - Abbreviated log level name. - * %(line_number) - Line number in the source file where the logging call was issued. - * %(logger) - Name of the logger used to log the call. - * %(message) - The logged message itself. - * %(thread_id) - ID of the thread in which the logging call was made. - * %(thread_name) - Name of the thread. Must be set before the first log statement on that thread. - * %(process_id) - ID of the process in which the logging call was made. - * %(source_location) - Full source file path and line number as a single string. - * %(short_source_location) - Shortened source file name and line number as a single string. - * %(tags) - Additional custom tags appended to the message when _TAGS macros are used. - * %(named_args) - Key-value pairs appended to the message. Only applicable when the message has named args; remains empty otherwise. - * - * @param time_format The format of the date. Same as strftime() format with extra specifiers `%Qms` `%Qus` `Qns` - * @param timestamp_timezone The timezone of the timestamp, local_time or gmt_time - * @param add_metadata_to_multi_line_logs If true, ensures that metadata (e.g., timestamp, log level) is added to every line of multiline log entries, maintaining consistency across all log outputs. - * - * @throws on invalid format string + * @throws std::invalid_argument if the format string in options is invalid */ - explicit PatternFormatter( - std::string format_pattern = - "%(time) [%(thread_id)] %(short_source_location:<28) LOG_%(log_level:<9) " - "%(logger:<12) %(message)", - std::string const& time_format = "%H:%M:%S.%Qns", - Timezone timestamp_timezone = Timezone::LocalTime, bool add_metadata_to_multi_line_logs = true) - : _format_pattern(std::move(format_pattern)), - _add_metadata_to_multi_line_logs(add_metadata_to_multi_line_logs), - _timestamp_formatter(time_format, timestamp_timezone) + explicit PatternFormatter(PatternFormatterOptions options) + : _options(std::move(options)), + _timestamp_formatter(_options.timestamp_pattern, _options.timestamp_timezone) { _set_pattern(); } @@ -127,7 +100,7 @@ class PatternFormatter std::string_view log_level_short_code, MacroMetadata const& log_statement_metadata, std::vector> const* named_args, std::string_view log_msg) { - if (_format_pattern.empty()) + if (_options.format_pattern.empty()) { // No formatting is needed when the format pattern is empty. // For example, in JsonFileSink, we can retrieve the MacroMetadata and the named arguments as @@ -253,19 +226,7 @@ class PatternFormatter } /***/ - QUILL_NODISCARD detail::TimestampFormatter const& timestamp_formatter() const noexcept - { - return _timestamp_formatter; - } - - /***/ - QUILL_NODISCARD std::string const& format_pattern() const noexcept { return _format_pattern; } - - /***/ - QUILL_NODISCARD bool get_add_metadata_to_multi_line_logs() const noexcept - { - return _add_metadata_to_multi_line_logs; - } + QUILL_NODISCARD PatternFormatterOptions const& get_options() const noexcept { return _options; } private: void _set_pattern() @@ -273,7 +234,7 @@ class PatternFormatter // the order we pass the arguments here must match with the order of Attribute enum using namespace fmtquill::literals; std::tie(_fmt_format, _order_index) = _generate_fmt_format_string( - _is_set_in_pattern, _format_pattern, "time"_a = "", "file_name"_a = "", + _is_set_in_pattern, _options.format_pattern, "time"_a = "", "file_name"_a = "", "caller_function"_a = "", "log_level"_a = "", "log_level_short_code"_a = "", "line_number"_a = "", "logger"_a = "", "full_path"_a = "", "thread_id"_a = "", "thread_name"_a = "", "process_id"_a = "", "source_location"_a = "", @@ -500,14 +461,13 @@ class PatternFormatter } private: - std::string _format_pattern; + PatternFormatterOptions _options; std::string _fmt_format; /** Each named argument in the format_pattern is mapped in order to this array **/ std::array _order_index{}; std::array, Attribute::ATTR_NR_ITEMS> _args{}; std::bitset _is_set_in_pattern; - bool _add_metadata_to_multi_line_logs; /** class responsible for formatting the timestamp */ detail::TimestampFormatter _timestamp_formatter; diff --git a/include/quill/core/LoggerBase.h b/include/quill/core/LoggerBase.h index 316a7394..c7737b8b 100644 --- a/include/quill/core/LoggerBase.h +++ b/include/quill/core/LoggerBase.h @@ -8,6 +8,7 @@ #include "quill/core/Attributes.h" #include "quill/core/Common.h" #include "quill/core/LogLevel.h" +#include "quill/core/PatternFormatterOptions.h" #include "quill/core/QuillError.h" #include "quill/core/ThreadContextManager.h" @@ -35,14 +36,10 @@ class LoggerBase public: /***/ LoggerBase(std::string logger_name, std::vector> sinks, - std::string format_pattern, std::string time_pattern, Timezone timezone, bool add_metadata_to_multi_line_logs, - ClockSourceType clock_source, UserClockSource* user_clock) - : format_pattern(static_cast(format_pattern)), - time_pattern(static_cast(time_pattern)), - logger_name(static_cast(logger_name)), + PatternFormatterOptions pattern_formatter_options, ClockSourceType clock_source, UserClockSource* user_clock) + : logger_name(static_cast(logger_name)), user_clock(user_clock), - timezone(timezone), - add_metadata_to_multi_line_logs(add_metadata_to_multi_line_logs), + pattern_formatter_options(static_cast(pattern_formatter_options)), clock_source(clock_source) { #ifndef NDEBUG @@ -131,12 +128,9 @@ class LoggerBase std::shared_ptr pattern_formatter; /* The backend thread will set this once, we never access it on the frontend */ std::shared_ptr backtrace_storage; /* The backend thread will construct this, we never access it on the frontend */ std::vector> sinks; /* Set by the frontend and accessed by the backend */ - std::string format_pattern; /* Set by the frontend and accessed by the backend to initialise PatternFormatter */ - std::string time_pattern; /* Set by the frontend and accessed by the backend to initialise PatternFormatter */ std::string logger_name; /* Set by the frontend, accessed by the frontend AND backend */ UserClockSource* user_clock{nullptr}; /* A non owned pointer to a custom timestamp clock, valid only when provided. used by frontend only */ - Timezone timezone; /* Set by the frontend and accessed by the backend to initialise PatternFormatter */ - bool add_metadata_to_multi_line_logs; /* Set by the frontend and accessed by the backend to initialise PatternFormatter */ + PatternFormatterOptions pattern_formatter_options; /* Set by the frontend and accessed by the backend to initialise PatternFormatter */ ClockSourceType clock_source; /* Set by the frontend and accessed by the frontend AND backend */ std::atomic log_level{LogLevel::Info}; /* used by frontend only */ std::atomic backtrace_flush_level{LogLevel::None}; /** Updated by the frontend at any time, accessed by the backend */ diff --git a/include/quill/core/LoggerManager.h b/include/quill/core/LoggerManager.h index 4c161f1f..bb60f5ed 100644 --- a/include/quill/core/LoggerManager.h +++ b/include/quill/core/LoggerManager.h @@ -8,6 +8,7 @@ #include "quill/core/Attributes.h" #include "quill/core/Common.h" #include "quill/core/LoggerBase.h" +#include "quill/core/PatternFormatterOptions.h" #include "quill/core/Spinlock.h" #include @@ -114,8 +115,7 @@ class LoggerManager /***/ template LoggerBase* create_or_get_logger(std::string const& logger_name, std::vector> sinks, - std::string const& format_pattern, - std::string const& time_pattern, Timezone timestamp_timezone, bool add_metadata_to_multi_line_logs, + PatternFormatterOptions const& pattern_formatter_options, ClockSourceType clock_source, UserClockSource* user_clock) { LockGuard const lock{_spinlock}; @@ -126,8 +126,8 @@ class LoggerManager { // If logger pointer is null, create a new logger instance. std::unique_ptr new_logger{ - new TLogger{logger_name, static_cast>&&>(sinks), format_pattern, - time_pattern, timestamp_timezone, add_metadata_to_multi_line_logs, clock_source, user_clock}}; + new TLogger{logger_name, static_cast>&&>(sinks), + pattern_formatter_options, clock_source, user_clock}}; _insert_logger(static_cast&&>(new_logger)); diff --git a/include/quill/core/PatternFormatterOptions.h b/include/quill/core/PatternFormatterOptions.h new file mode 100644 index 00000000..3ab5649b --- /dev/null +++ b/include/quill/core/PatternFormatterOptions.h @@ -0,0 +1,105 @@ +/** + * Copyright(c) 2020-present, Odysseas Georgoudis & quill contributors. + * Distributed under the MIT License (http://opensource.org/licenses/MIT) + */ + +#pragma once + +#include "quill/core/Attributes.h" +#include "quill/core/Common.h" +#include +#include + +QUILL_BEGIN_NAMESPACE + +/** + * @brief Configuration options for the PatternFormatter. + * + * This class encapsulates the configuration options used to customize + * the formatting of log messages. + */ +class PatternFormatterOptions +{ +public: + /***/ + explicit PatternFormatterOptions(std::string format_pattern = + "%(time) [%(thread_id)] %(short_source_location:<28) " + "LOG_%(log_level:<9) %(logger:<12) %(message)", + std::string timestamp_pattern = "%H:%M:%S.%Qns", + Timezone timestamp_timezone = Timezone::LocalTime, + bool add_metadata_to_multi_line_logs = true) + : format_pattern(static_cast(format_pattern)), + timestamp_pattern(static_cast(timestamp_pattern)), + timestamp_timezone(timestamp_timezone), + add_metadata_to_multi_line_logs(add_metadata_to_multi_line_logs) + { + } + + /** + * @brief The format pattern for log messages. + * + * This string defines the overall structure of each log message. + * + * It can include various placeholders that will be replaced with actual values when formatting the log message. + * + * %(time) - Human-readable timestamp representing when the log statement was created. + * %(file_name) - Name of the source file where the logging call was issued. + * %(full_path) - Full path of the source file where the logging call was issued. + * %(caller_function) - Name of the function containing the logging call. + * %(log_level) - Textual representation of the logging level for the message. + * %(log_level_short_code) - Abbreviated log level name. + * %(line_number) - Line number in the source file where the logging call was issued. + * %(logger) - Name of the logger used to log the call. + * %(message) - The logged message itself. + * %(thread_id) - ID of the thread in which the logging call was made. + * %(thread_name) - Name of the thread. Must be set before the first log statement on that thread. + * %(process_id) - ID of the process in which the logging call was made. + * %(source_location) - Full source file path and line number as a single string. + * %(short_source_location) - Shortened source file name and line number as a single string. + * %(tags) - Additional custom tags appended to the message when _TAGS macros are used. + * %(named_args) - Key-value pairs appended to the message. Only applicable when the message has named args; remains empty otherwise. + * + * @warning The same attribute cannot be used twice in the same format pattern. + */ + std::string format_pattern; + + /** + * @brief The format pattern for timestamps. + * + * This string defines how timestamps are formatted in log messages. + * It follows the strftime() format with additional specifiers: + * - %Qms : Milliseconds + * - %Qus : Microseconds + * - %Qns : Nanoseconds + */ + std::string timestamp_pattern; + + /** + * @brief The timezone to use for timestamps. + * + * Determines whether timestamps are formatted in local time or GMT. + */ + Timezone timestamp_timezone; + + /** + * @brief Whether to add metadata to each line of multi-line log messages. + * + * If true, ensures that metadata (e.g., timestamp, log level) is added + * to every line of multi-line log entries, maintaining consistency + * across all log outputs. + */ + bool add_metadata_to_multi_line_logs; + + /***/ + bool operator==(const PatternFormatterOptions& other) const + { + return format_pattern == other.format_pattern && timestamp_pattern == other.timestamp_pattern && + timestamp_timezone == other.timestamp_timezone && + add_metadata_to_multi_line_logs == other.add_metadata_to_multi_line_logs; + } + + /***/ + bool operator!=(const PatternFormatterOptions& other) const { return !(*this == other); } +}; + +QUILL_END_NAMESPACE \ No newline at end of file diff --git a/test/integration_tests/ConsoleSinkStderrMultipleFormatsTest.cpp b/test/integration_tests/ConsoleSinkStderrMultipleFormatsTest.cpp index 292a390b..b1025206 100644 --- a/test/integration_tests/ConsoleSinkStderrMultipleFormatsTest.cpp +++ b/test/integration_tests/ConsoleSinkStderrMultipleFormatsTest.cpp @@ -32,8 +32,7 @@ TEST_CASE("console_sink_stderr_multiple_formats") auto console_sink = Frontend::create_or_get_sink("console_sink", using_colours, stream); Logger* logger_a = Frontend::create_or_get_logger(logger_name_a, console_sink); - Logger* logger_b = Frontend::create_or_get_logger(logger_name_b, console_sink, - "%(logger) - %(message) (%(caller_function))"); + Logger* logger_b = Frontend::create_or_get_logger(logger_name_b, console_sink, quill::PatternFormatterOptions{"%(logger) - %(message) (%(caller_function))"}); console_sink.reset(); diff --git a/test/integration_tests/ConsoleSinkStdoutMultipleFormatsTest.cpp b/test/integration_tests/ConsoleSinkStdoutMultipleFormatsTest.cpp index dee257b5..f344bc32 100644 --- a/test/integration_tests/ConsoleSinkStdoutMultipleFormatsTest.cpp +++ b/test/integration_tests/ConsoleSinkStdoutMultipleFormatsTest.cpp @@ -32,8 +32,7 @@ TEST_CASE("console_sink_stdout_multiple_formats") auto console_sink = Frontend::create_or_get_sink("console_sink", using_colours, stream); Logger* logger_a = Frontend::create_or_get_logger(logger_name_a, console_sink); - Logger* logger_b = Frontend::create_or_get_logger(logger_name_b, console_sink, - "%(logger) - %(message) (%(caller_function))"); + Logger* logger_b = Frontend::create_or_get_logger(logger_name_b, console_sink, quill::PatternFormatterOptions{"%(logger) - %(message) (%(caller_function))"}); console_sink.reset(); diff --git a/test/integration_tests/FlushMultipleLoggers.cpp b/test/integration_tests/FlushMultipleLoggers.cpp index bffdc984..3f0f19ab 100644 --- a/test/integration_tests/FlushMultipleLoggers.cpp +++ b/test/integration_tests/FlushMultipleLoggers.cpp @@ -88,7 +88,7 @@ quill::Logger* create_logger() quill::Logger* new_logger = quill::Frontend::create_or_get_logger( "logger_" + log_index, std::move(file_sink), - "[%(time)] [%(log_level)] [" + log_index + ":%(tags):%(caller_function)]: %(message)"); + quill::PatternFormatterOptions{"[%(time)] [%(log_level)] [" + log_index + ":%(tags):%(caller_function)]: %(message)"}); return new_logger; } diff --git a/test/integration_tests/JsonFileLoggingTest.cpp b/test/integration_tests/JsonFileLoggingTest.cpp index 3fa9df14..bcc37498 100644 --- a/test/integration_tests/JsonFileLoggingTest.cpp +++ b/test/integration_tests/JsonFileLoggingTest.cpp @@ -89,8 +89,9 @@ TEST_CASE("json_file_logging") Logger* logger = Frontend::create_or_get_logger( logger_name_prefix + std::to_string(i), std::initializer_list>{std::move(json_file_sink), std::move(file_sink)}, - "%(time) [%(thread_id)] %(short_source_location:<28) LOG_%(log_level:<9) %(logger:<12) " - "%(message) [%(named_args)]"); + quill::PatternFormatterOptions{ + "%(time) [%(thread_id)] %(short_source_location:<28) LOG_%(log_level:<9) %(logger:<12) " + "%(message) [%(named_args)]"}); if (i == 0) { diff --git a/test/integration_tests/JsonMultilineMetadataTest.cpp b/test/integration_tests/JsonMultilineMetadataTest.cpp index f0c13c41..3b894a29 100644 --- a/test/integration_tests/JsonMultilineMetadataTest.cpp +++ b/test/integration_tests/JsonMultilineMetadataTest.cpp @@ -49,15 +49,17 @@ TEST_CASE("json_multi_line_metadata") Logger* logger_a = Frontend::create_or_get_logger( logger_name_a, std::initializer_list>{json_file_sink, file_sink}, - "%(time) [%(thread_id)] %(short_source_location:<28) LOG_%(log_level:<9) %(logger:<12) " - "%(message) %(caller_function)", - "%H:%M:%S.%Qns", Timezone::LocalTime, true); + PatternFormatterOptions{ + "%(time) [%(thread_id)] %(short_source_location:<28) LOG_%(log_level:<9) %(logger:<12) " + "%(message) %(caller_function)", + "%H:%M:%S.%Qns", Timezone::LocalTime, true}); Logger* logger_b = Frontend::create_or_get_logger( logger_name_b, std::initializer_list>{json_file_sink, file_sink}, - "%(time) [%(thread_id)] %(short_source_location:<28) LOG_%(log_level:<9) %(logger:<12) " - "%(message) %(caller_function)", - "%H:%M:%S.%Qns", Timezone::LocalTime, false); + PatternFormatterOptions{ + "%(time) [%(thread_id)] %(short_source_location:<28) LOG_%(log_level:<9) %(logger:<12) " + "%(message) %(caller_function)", + "%H:%M:%S.%Qns", Timezone::LocalTime, false}); LOG_INFO(logger_a, "This is a multiline info message.\nLine 2: {val_1}.\nLine 3: {val_2}.", "data1", "data2"); diff --git a/test/integration_tests/JsonVariedParamsLoggingTest.cpp b/test/integration_tests/JsonVariedParamsLoggingTest.cpp index 37897b10..f07ffdcd 100644 --- a/test/integration_tests/JsonVariedParamsLoggingTest.cpp +++ b/test/integration_tests/JsonVariedParamsLoggingTest.cpp @@ -85,7 +85,7 @@ TEST_CASE("json_varied_params_logging") Logger* logger = Frontend::create_or_get_logger("root", std::move(json_file_sink), - "LOG_%(log_level:<9) %(logger:<12) %(message) [%(named_args)]"); + quill::PatternFormatterOptions{"LOG_%(log_level:<9) %(logger:<12) %(message) [%(named_args)]"}); for (size_t i = 0; i < number_of_messages; ++i) { diff --git a/test/integration_tests/MultiFrontendThreadsTest.cpp b/test/integration_tests/MultiFrontendThreadsTest.cpp index f54e3238..aa9ad209 100644 --- a/test/integration_tests/MultiFrontendThreadsTest.cpp +++ b/test/integration_tests/MultiFrontendThreadsTest.cpp @@ -48,9 +48,11 @@ TEST_CASE("multi_frontend_threads") Logger* logger = Frontend::create_or_get_logger( logger_name_prefix + std::to_string(i), std::move(file_sink), - "%(time) [%(thread_id)] %(short_source_location:<28) LOG_%(log_level:<9) %(logger:<12) " - "%(message)", - "%Y-%m-%d %H:%M:%S.%Qns", Timezone::GmtTime, false, ClockSourceType::System); + quill::PatternFormatterOptions{ + "%(time) [%(thread_id)] %(short_source_location:<28) LOG_%(log_level:<9) %(logger:<12) " + "%(message)", + "%Y-%m-%d %H:%M:%S.%Qns", Timezone::GmtTime, false}, + ClockSourceType::System); for (size_t j = 0; j < number_of_messages; ++j) { diff --git a/test/integration_tests/MultilineMetadataTest.cpp b/test/integration_tests/MultilineMetadataTest.cpp index 269063d1..9a1de75c 100644 --- a/test/integration_tests/MultilineMetadataTest.cpp +++ b/test/integration_tests/MultilineMetadataTest.cpp @@ -37,15 +37,17 @@ TEST_CASE("multi_line_metadata") Logger* logger_a = Frontend::create_or_get_logger( logger_name_a, file_sink, - "%(time) [%(thread_id)] %(short_source_location:<28) LOG_%(log_level:<9) %(logger:<12) " - "%(message) %(caller_function)", - "%H:%M:%S.%Qns", Timezone::LocalTime, true); + PatternFormatterOptions{ + "%(time) [%(thread_id)] %(short_source_location:<28) LOG_%(log_level:<9) %(logger:<12) " + "%(message) %(caller_function)", + "%H:%M:%S.%Qns", Timezone::LocalTime, true}); Logger* logger_b = Frontend::create_or_get_logger( logger_name_b, file_sink, - "%(time) [%(thread_id)] %(short_source_location:<28) LOG_%(log_level:<9) %(logger:<12) " - "%(message) %(caller_function)", - "%H:%M:%S.%Qns", Timezone::LocalTime, false); + PatternFormatterOptions{ + "%(time) [%(thread_id)] %(short_source_location:<28) LOG_%(log_level:<9) %(logger:<12) " + "%(message) %(caller_function)", + "%H:%M:%S.%Qns", Timezone::LocalTime, false}); LOG_INFO(logger_a, "This is a multiline info message.\nLine 2: {}.\nLine 3: {}.", "data1", "data2"); diff --git a/test/integration_tests/TagsLoggingTest.cpp b/test/integration_tests/TagsLoggingTest.cpp index a38f8010..7400010f 100644 --- a/test/integration_tests/TagsLoggingTest.cpp +++ b/test/integration_tests/TagsLoggingTest.cpp @@ -41,8 +41,9 @@ TEST_CASE("tags_logging") Logger* logger = Frontend::create_or_get_logger( logger_name, std::move(file_sink), - "%(time) [%(thread_id)] %(short_source_location:<28) LOG_%(log_level:<9) " - "%(logger:<12) [ %(tags)] %(message)\""); + PatternFormatterOptions{ + "%(time) [%(thread_id)] %(short_source_location:<28) LOG_%(log_level:<9) " + "%(logger:<12) [ %(tags)] %(message)"}); logger->set_log_level(quill::LogLevel::TraceL3); diff --git a/test/integration_tests/UserClockSourceTest.cpp b/test/integration_tests/UserClockSourceTest.cpp index b675e2de..207b4388 100644 --- a/test/integration_tests/UserClockSourceTest.cpp +++ b/test/integration_tests/UserClockSourceTest.cpp @@ -70,9 +70,10 @@ TEST_CASE("user_clock_source") Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink), - "%(time) %(log_level) %(logger:<16) %(message)", // format - "%Y-%m-%d %H:%M:%S.%Qms", // timestamp format - quill::Timezone::GmtTime, false, ClockSourceType::User, &uct); + PatternFormatterOptions{"%(time) %(log_level) %(logger:<16) %(message)", // format + "%Y-%m-%d %H:%M:%S.%Qms", // timestamp format + quill::Timezone::GmtTime, false}, + ClockSourceType::User, &uct); for (size_t i = 0; i < number_of_messages; ++i) { diff --git a/test/integration_tests/UserDefinedTypeLoggingTest.cpp b/test/integration_tests/UserDefinedTypeLoggingTest.cpp index b0f7fe9b..6aa572c2 100644 --- a/test/integration_tests/UserDefinedTypeLoggingTest.cpp +++ b/test/integration_tests/UserDefinedTypeLoggingTest.cpp @@ -157,8 +157,9 @@ TEST_CASE("custom_type_defined_type_logging") Logger* logger = Frontend::create_or_get_logger( logger_name, std::move(file_sink), - "%(time) [%(thread_id)] %(short_source_location:<28) LOG_%(log_level:<9) " - "%(logger:<12) %(message)"); + PatternFormatterOptions{ + "%(time) [%(thread_id)] %(short_source_location:<28) LOG_%(log_level:<9) " + "%(logger:<12) %(message)"}); logger->set_log_level(quill::LogLevel::TraceL3); diff --git a/test/unit_tests/LoggerManagerTest.cpp b/test/unit_tests/LoggerManagerTest.cpp index 75422d1f..604428c6 100644 --- a/test/unit_tests/LoggerManagerTest.cpp +++ b/test/unit_tests/LoggerManagerTest.cpp @@ -21,15 +21,17 @@ TEST_CASE("create_get_remove_logger") LoggerBase* logger_1 = lm.create_or_get_logger( "logger_1", std::move(sinks), - "%(time) [%(thread_id)] %(short_source_location:<28) " - "LOG_%(log_level:<9) %(logger:<12) %(message)", - "%H:%M:%S.%Qns", quill::Timezone::GmtTime, false, ClockSourceType::Tsc, nullptr); + PatternFormatterOptions{"%(time) [%(thread_id)] %(short_source_location:<28) " + "LOG_%(log_level:<9) %(logger:<12) %(message)", + "%H:%M:%S.%Qns", quill::Timezone::GmtTime, false}, + ClockSourceType::Tsc, nullptr); LoggerBase* logger_2 = lm.create_or_get_logger( "logger_2", std::initializer_list>{sink}, - "[%(thread_id)] %(short_source_location:<28) " - "LOG_%(log_level:<9) %(logger:<12) %(message)", - "%H:%M:%S.%Qns", quill::Timezone::GmtTime, false, ClockSourceType::Tsc, nullptr); + PatternFormatterOptions{"[%(thread_id)] %(short_source_location:<28) " + "LOG_%(log_level:<9) %(logger:<12) %(message)", + "%H:%M:%S.%Qns", quill::Timezone::GmtTime, false}, + ClockSourceType::Tsc, nullptr); REQUIRE_EQ(logger_1->get_logger_name(), "logger_1"); REQUIRE_EQ(logger_2->get_logger_name(), "logger_2"); diff --git a/test/unit_tests/LoggerTest.cpp b/test/unit_tests/LoggerTest.cpp index d2eb1acd..02bbfbfa 100644 --- a/test/unit_tests/LoggerTest.cpp +++ b/test/unit_tests/LoggerTest.cpp @@ -22,9 +22,10 @@ TEST_CASE("check_logger") Logger* logger_1 = static_cast(lm.create_or_get_logger( "logger_1", std::move(sinks), - "%(time) [%(thread_id)] %(short_source_location:<28) " + PatternFormatterOptions{"%(time) [%(thread_id)] %(short_source_location:<28) " "LOG_%(log_level:<9) %(logger:<12) %(message)", - "%H:%M:%S.%Qns", quill::Timezone::GmtTime, false, ClockSourceType::Tsc, nullptr)); + "%H:%M:%S.%Qns", quill::Timezone::GmtTime, false}, + ClockSourceType::Tsc, nullptr)); // Check default log level REQUIRE_EQ(logger_1->get_log_level(), LogLevel::Info); @@ -48,9 +49,10 @@ TEST_CASE("logger_should_log") Logger* logger_1 = static_cast(lm.create_or_get_logger( "logger_1", std::move(sinks), - "%(time) [%(thread_id)] %(short_source_location:<28) " + PatternFormatterOptions{"%(time) [%(thread_id)] %(short_source_location:<28) " "LOG_%(log_level:<9) %(logger:<12) %(message)", - "%H:%M:%S.%Qns", quill::Timezone::GmtTime, false, ClockSourceType::Tsc, nullptr)); + "%H:%M:%S.%Qns", quill::Timezone::GmtTime, false}, + ClockSourceType::Tsc, nullptr)); REQUIRE_UNARY_FALSE(logger_1->should_log_statement()); REQUIRE(logger_1->should_log_statement()); diff --git a/test/unit_tests/PatternFormatterTest.cpp b/test/unit_tests/PatternFormatterTest.cpp index 67bbaa03..0950c4e1 100644 --- a/test/unit_tests/PatternFormatterTest.cpp +++ b/test/unit_tests/PatternFormatterTest.cpp @@ -17,7 +17,7 @@ std::string_view process_id = "123"; TEST_CASE("default_pattern_formatter") { - PatternFormatter default_pattern_formatter; + PatternFormatter default_pattern_formatter{PatternFormatterOptions{}}; uint64_t const ts{1579815761000023021}; char const* thread_id = "31341"; @@ -54,8 +54,8 @@ TEST_CASE("default_pattern_formatter") TEST_CASE("custom_pattern_message_only") { // Message only - PatternFormatter custom_pattern_formatter{"%(log_level_short_code) %(message)", "%H:%M:%S.%Qns", - Timezone::GmtTime}; + PatternFormatter custom_pattern_formatter{PatternFormatterOptions{ + "%(log_level_short_code) %(message)", "%H:%M:%S.%Qns", Timezone::GmtTime, false}}; uint64_t const ts{1579815761000023000}; char const* thread_id = "31341"; @@ -88,10 +88,10 @@ TEST_CASE("custom_pattern_message_only") TEST_CASE("custom_pattern_timestamp_precision_nanoseconds") { // Custom pattern with part 1 and part 3 - PatternFormatter custom_pattern_formatter{ + PatternFormatter custom_pattern_formatter{PatternFormatterOptions{ "%(time) [%(thread_id)] %(file_name):%(line_number) LOG_%(log_level) %(logger) " "%(message) [%(caller_function)]", - "%m-%d-%Y %H:%M:%S.%Qns", Timezone::GmtTime}; + "%m-%d-%Y %H:%M:%S.%Qns", Timezone::GmtTime, false}}; uint64_t const ts{1579815761000023000}; char const* thread_id = "31341"; @@ -126,10 +126,10 @@ TEST_CASE("custom_pattern_timestamp_precision_nanoseconds") TEST_CASE("custom_pattern_timestamp_precision_microseconds") { - PatternFormatter custom_pattern_formatter{ + PatternFormatter custom_pattern_formatter{PatternFormatterOptions{ "%(time) [%(thread_id)] %(file_name):%(line_number) LOG_%(log_level) %(logger) " "%(message) [%(caller_function)]", - "%m-%d-%Y %H:%M:%S.%Qus", Timezone::GmtTime}; + "%m-%d-%Y %H:%M:%S.%Qus", Timezone::GmtTime, false}}; uint64_t const ts{1579815761020123000}; char const* thread_id = "31341"; @@ -164,10 +164,10 @@ TEST_CASE("custom_pattern_timestamp_precision_microseconds") TEST_CASE("custom_pattern_timestamp_precision_milliseconds") { - PatternFormatter custom_pattern_formatter{ + PatternFormatter custom_pattern_formatter{PatternFormatterOptions{ "%(time) [%(thread_id)] %(file_name):%(line_number) LOG_%(log_level) %(logger) " "%(message) [%(caller_function)]", - "%m-%d-%Y %H:%M:%S.%Qms", Timezone::GmtTime}; + "%m-%d-%Y %H:%M:%S.%Qms", Timezone::GmtTime, false}}; uint64_t const ts{1579815761099000000}; char const* thread_id = "31341"; @@ -202,10 +202,10 @@ TEST_CASE("custom_pattern_timestamp_precision_milliseconds") TEST_CASE("custom_pattern_timestamp_precision_none") { - PatternFormatter custom_pattern_formatter{ + PatternFormatter custom_pattern_formatter{PatternFormatterOptions{ "%(time) [%(thread_id)] %(file_name):%(line_number) LOG_%(log_level) %(logger) " "%(message) [%(caller_function)]", - "%m-%d-%Y %H:%M:%S", Timezone::GmtTime}; + "%m-%d-%Y %H:%M:%S", Timezone::GmtTime, false}}; uint64_t const ts{1579815761099220000}; char const* thread_id = "31341"; @@ -241,10 +241,10 @@ TEST_CASE("custom_pattern_timestamp_precision_none") TEST_CASE("custom_pattern_timestamp_strftime_reallocation_on_format_string_2") { // set a timestamp_format that will cause timestamp _formatted_date to re-allocate. - PatternFormatter custom_pattern_formatter{ + PatternFormatter custom_pattern_formatter{PatternFormatterOptions{ "%(time) [%(thread_id)] %(file_name):%(line_number) LOG_%(log_level) %(logger) " "%(message) [%(caller_function)]", - "%FT%T.%Qus%FT%T", Timezone::GmtTime}; + "%FT%T.%Qus%FT%T", Timezone::GmtTime, false}}; uint64_t const ts{1579815761099220000}; char const* thread_id = "31341"; @@ -283,10 +283,10 @@ TEST_CASE("custom_pattern_timestamp_strftime_reallocation_on_format_string_2") TEST_CASE("custom_pattern_timestamp_strftime_reallocation_when_adding_fractional_seconds") { // set a timestamp_format that will cause timestamp _formatted_date to re-allocate. - PatternFormatter custom_pattern_formatter{ + PatternFormatter custom_pattern_formatter{PatternFormatterOptions{ "%(time) [%(thread_id)] %(file_name):%(line_number) LOG_%(log_level) %(logger) " "%(message) [%(caller_function)]", - "%FT%T.%T.%Qus%FT%T", Timezone::GmtTime}; + "%FT%T.%T.%Qus%FT%T", Timezone::GmtTime, false}}; uint64_t const ts{1579815761099220000}; char const* thread_id = "31341"; @@ -326,17 +326,18 @@ TEST_CASE("custom_pattern_timestamp_strftime_reallocation_when_adding_fractional TEST_CASE("invalid_pattern") { // missing %) - REQUIRE_THROWS_AS( - PatternFormatter("%(time [%(thread_id)] %(file_name):%(line_number) %(log_level) %(logger) " - "%(message) [%(caller_function)]", - "%H:%M:%S.%Qns", Timezone::GmtTime), - quill::QuillError); + REQUIRE_THROWS_AS(PatternFormatter(PatternFormatterOptions{ + "%(time [%(thread_id)] %(file_name):%(line_number) %(log_level) %(logger) " + "%(message) [%(caller_function)]", + "%H:%M:%S.%Qns", Timezone::GmtTime, false}), + quill::QuillError); // invalid attribute %(invalid) REQUIRE_THROWS_AS( - PatternFormatter("%(invalid) [%(thread_id)] %(file_name):%(line_number) %(log_level) %(logger) " - "%(message) [%(caller_function)]", - "%H:%M:%S.%Qns", Timezone::GmtTime), + PatternFormatter(PatternFormatterOptions{ + "%(invalid) [%(thread_id)] %(file_name):%(line_number) %(log_level) %(logger) " + "%(message) [%(caller_function)]", + "%H:%M:%S.%Qns", Timezone::GmtTime, false}), quill::QuillError); } #endif @@ -344,9 +345,9 @@ TEST_CASE("invalid_pattern") TEST_CASE("custom_pattern") { // Custom pattern with part 1 and part 2 - PatternFormatter custom_pattern_formatter{ + PatternFormatter custom_pattern_formatter{PatternFormatterOptions{ "%(time) [%(thread_id)] %(file_name):%(line_number) LOG_%(log_level) %(logger) %(message)", - "%m-%d-%Y %H:%M:%S.%Qns", Timezone::GmtTime}; + "%m-%d-%Y %H:%M:%S.%Qns", Timezone::GmtTime, false}}; uint64_t const ts{1579815761000023000}; char const* thread_id = "31341"; @@ -373,7 +374,7 @@ TEST_CASE("custom_pattern") std::string const formatted_string = fmtquill::to_string(formatted_buffer); std::string const expected_string = - "01-23-2020 21:42:41.000023000 [31341] PatternFormatterTest.cpp:354 LOG_DEBUG test_logger " + "01-23-2020 21:42:41.000023000 [31341] PatternFormatterTest.cpp:355 LOG_DEBUG test_logger " "This the 1234 formatter pattern\n"; REQUIRE_EQ(formatted_string, expected_string); @@ -384,8 +385,8 @@ TEST_CASE("custom_pattern_part_3_no_format_specifiers") // Custom pattern with a part 3 that has no format specifiers: // Part 1 - "|{}|{}|" // Part 3 - "|EOM|" - PatternFormatter custom_pattern_formatter{"|LOG_%(log_level)|%(logger)|%(message)|EOM|", - "%H:%M:%S", Timezone::GmtTime}; + PatternFormatter custom_pattern_formatter{PatternFormatterOptions{ + "|LOG_%(log_level)|%(logger)|%(message)|EOM|", "%H:%M:%S", Timezone::GmtTime, false}}; uint64_t const ts{1579815761000023000}; char const* thread_id = "31341"; @@ -419,7 +420,7 @@ TEST_CASE("custom_pattern_part_3_no_format_specifiers") TEST_CASE("empty_format_pattern") { - PatternFormatter empty_formatter{"", "%H:%M:%S", Timezone::GmtTime}; + PatternFormatter empty_formatter{PatternFormatterOptions{"", "%H:%M:%S", Timezone::GmtTime, false}}; uint64_t const ts{1579815761000023000}; char const* thread_id = "31341"; @@ -453,10 +454,10 @@ TEST_CASE("empty_format_pattern") TEST_CASE("pattern_timestamp_move_constructor") { // Custom pattern with part 1 and part 3 - PatternFormatter pattern_formatter{ + PatternFormatter pattern_formatter{PatternFormatterOptions{ "%(time) [%(thread_id)] %(file_name):%(line_number) LOG_%(log_level) %(logger) " "%(message) [%(caller_function)]", - "%m-%d-%Y %H:%M:%S.%Qns", Timezone::GmtTime}; + "%m-%d-%Y %H:%M:%S.%Qns", Timezone::GmtTime, false}}; PatternFormatter pattern_formatter_move{std::move(pattern_formatter)}; @@ -485,7 +486,7 @@ TEST_CASE("pattern_timestamp_move_constructor") std::string const formatted_string = fmtquill::to_string(formatted_buffer); std::string const expected_string = - "01-23-2020 21:42:41.000023000 [31341] PatternFormatterTest.cpp:466 LOG_DEBUG test_logger " + "01-23-2020 21:42:41.000023000 [31341] PatternFormatterTest.cpp:467 LOG_DEBUG test_logger " "This the 1234 formatter pattern [DOCTEST_ANON_FUNC_27]\n"; REQUIRE_EQ(formatted_string, expected_string);