From 5d7e4c7b62237fd259fd6f39532f807bbb47b5b2 Mon Sep 17 00:00:00 2001 From: Sascha Montellese Date: Thu, 13 Jul 2017 17:04:43 +0200 Subject: [PATCH] support variable format padding --- .../spdlog/details/pattern_formatter_impl.h | 233 ++++++++++++++++-- include/spdlog/formatter.h | 14 +- include/spdlog/tweakme.h | 6 + tests/padding.cpp | 34 +++ tests/tests.vcxproj | 1 + tests/tests.vcxproj.filters | 3 + 6 files changed, 267 insertions(+), 24 deletions(-) create mode 100644 tests/padding.cpp diff --git a/include/spdlog/details/pattern_formatter_impl.h b/include/spdlog/details/pattern_formatter_impl.h index c1ce7191..8f9ef8e4 100644 --- a/include/spdlog/details/pattern_formatter_impl.h +++ b/include/spdlog/details/pattern_formatter_impl.h @@ -27,9 +27,61 @@ namespace details class flag_formatter { public: +#ifdef SPDLOG_ENABLE_PATTERN_PADDING + flag_formatter() + {} +#endif virtual ~flag_formatter() {} virtual void format(details::log_msg& msg, const std::tm& tm_time) = 0; + +#ifdef SPDLOG_ENABLE_PATTERN_PADDING +protected: + explicit flag_formatter(const format_padding& padding) + : _padding(padding) + {} +#endif + + inline bool has_padding() const + { +#ifndef SPDLOG_ENABLE_PATTERN_PADDING + return false; +#else + return _padding._width > 0; +#endif + } + + template + void format_pad(details::log_msg& msg, T val) + { + if (!has_padding()) + msg.formatted << val; +#ifdef SPDLOG_ENABLE_PATTERN_PADDING + else + { + auto spec = fmt::pad(val, _padding._width, _padding._char); + spec.align_ = _padding._alignment; + msg.formatted << spec; + } +#endif + } + +#ifdef SPDLOG_ENABLE_PATTERN_PADDING + template<> + void format_pad(details::log_msg& msg, std::string str) + { + if (!has_padding()) + msg.formatted << str; + else + { + auto spec = fmt::pad(str.c_str(), _padding._width, _padding._char); + spec.align_ = _padding._alignment; + msg.formatted << spec; + } + } + + const format_padding _padding; +#endif }; /////////////////////////////////////////////////////////////////////// @@ -39,9 +91,16 @@ namespace { class name_formatter:public flag_formatter { +#ifdef SPDLOG_ENABLE_PATTERN_PADDING +public: + name_formatter(const format_padding& padding) + : flag_formatter(padding) + {} +#endif + void format(details::log_msg& msg, const std::tm&) override { - msg.formatted << *msg.logger_name; + format_pad(msg, *msg.logger_name); } }; } @@ -49,18 +108,32 @@ class name_formatter:public flag_formatter // log level appender class level_formatter:public flag_formatter { +#ifdef SPDLOG_ENABLE_PATTERN_PADDING +public: + level_formatter(const format_padding& padding) + : flag_formatter(padding) + {} +#endif + void format(details::log_msg& msg, const std::tm&) override { - msg.formatted << level::to_str(msg.level); + format_pad(msg, level::to_str(msg.level)); } }; // short log level appender class short_level_formatter:public flag_formatter { +#ifdef SPDLOG_ENABLE_PATTERN_PADDING +public: + short_level_formatter(const format_padding& padding) + : flag_formatter(padding) + {} +#endif + void format(details::log_msg& msg, const std::tm&) override { - msg.formatted << level::to_short_str(msg.level); + format_pad(msg, level::to_short_str(msg.level)); } }; @@ -87,9 +160,16 @@ static const days_array& days() } class a_formatter:public flag_formatter { +#ifdef SPDLOG_ENABLE_PATTERN_PADDING +public: + a_formatter(const format_padding& padding) + : flag_formatter(padding) + {} +#endif + void format(details::log_msg& msg, const std::tm& tm_time) override { - msg.formatted << days()[tm_time.tm_wday]; + format_pad(msg, days()[tm_time.tm_wday]); } }; // message counter formatter @@ -97,7 +177,7 @@ class i_formatter SPDLOG_FINAL:public flag_formatter { void format(details::log_msg& msg, const std::tm&) override { - msg.formatted << '#' << msg.msg_id; + msg.formatted << '#' << msg.msg_id; // TODO } }; //Full weekday name @@ -108,9 +188,16 @@ static const days_array& full_days() } class A_formatter SPDLOG_FINAL :public flag_formatter { +#ifdef SPDLOG_ENABLE_PATTERN_PADDING +public: + A_formatter(const format_padding& padding) + : flag_formatter(padding) + {} +#endif + void format(details::log_msg& msg, const std::tm& tm_time) override { - msg.formatted << full_days()[tm_time.tm_wday]; + format_pad(msg, full_days()[tm_time.tm_wday]); } }; @@ -123,9 +210,16 @@ static const months_array& months() } class b_formatter:public flag_formatter { +#ifdef SPDLOG_ENABLE_PATTERN_PADDING +public: + b_formatter(const format_padding& padding) + : flag_formatter(padding) + {} +#endif + void format(details::log_msg& msg, const std::tm& tm_time) override { - msg.formatted << months()[tm_time.tm_mon]; + format_pad(msg, months()[tm_time.tm_mon]); } }; @@ -137,9 +231,16 @@ static const months_array& full_months() } class B_formatter SPDLOG_FINAL :public flag_formatter { +#ifdef SPDLOG_ENABLE_PATTERN_PADDING +public: + B_formatter(const format_padding& padding) + : flag_formatter(padding) + {} +#endif + void format(details::log_msg& msg, const std::tm& tm_time) override { - msg.formatted << full_months()[tm_time.tm_mon]; + format_pad(msg, full_months()[tm_time.tm_mon]); } }; @@ -384,18 +485,32 @@ private: // Thread id class t_formatter SPDLOG_FINAL:public flag_formatter { +#ifdef SPDLOG_ENABLE_PATTERN_PADDING +public: + t_formatter(const format_padding& padding) + : flag_formatter(padding) + {} +#endif + void format(details::log_msg& msg, const std::tm&) override { - msg.formatted << msg.thread_id; + format_pad(msg, msg.thread_id); } }; // Current pid class pid_formatter SPDLOG_FINAL:public flag_formatter { +#ifdef SPDLOG_ENABLE_PATTERN_PADDING +public: + pid_formatter(const format_padding& padding) + : flag_formatter(padding) + {} +#endif + void format(details::log_msg& msg, const std::tm&) override { - msg.formatted << details::os::pid(); + format_pad(msg, details::os::pid()); } }; @@ -511,9 +626,20 @@ inline void spdlog::pattern_formatter::compile_pattern(const std::string& patter if (user_chars) //append user chars found so far _formatters.push_back(std::move(user_chars)); - if (++it != end) - handle_flag(*it); - else +#ifdef SPDLOG_ENABLE_PATTERN_PADDING + format_padding padding; +#endif + while (++it != end) + { +#ifndef SPDLOG_ENABLE_PATTERN_PADDING + if (handle_flag(*it)) +#else + if (handle_flag(*it, padding)) +#endif + break; + } + + if (it == end) break; } else // chars not following the % sign should be displayed as is @@ -529,25 +655,64 @@ inline void spdlog::pattern_formatter::compile_pattern(const std::string& patter } } -inline void spdlog::pattern_formatter::handle_flag(char flag) + +#ifndef SPDLOG_ENABLE_PATTERN_PADDING +inline bool spdlog::pattern_formatter::handle_flag(char flag) +#else +inline bool spdlog::pattern_formatter::handle_flag(char flag, format_padding& padding) +#endif { +#ifdef SPDLOG_ENABLE_PATTERN_PADDING + // handle format padding left alignment + if (flag == '-') + { + padding._alignment = fmt::ALIGN_LEFT; + return false; + } + // handle format specifiers for padding + if (flag >= '0' && flag <= '9') + { + if (flag == '0' && padding._char == ' ') + padding._char = '0'; + else + padding._width = padding._width * 10 + (flag - '0'); + return false; + } +#endif + switch (flag) { // logger name case 'n': - _formatters.push_back(std::unique_ptr(new details::name_formatter())); + _formatters.push_back(std::unique_ptr(new details::name_formatter( +#ifdef SPDLOG_ENABLE_PATTERN_PADDING + padding +#endif + ))); break; case 'l': - _formatters.push_back(std::unique_ptr(new details::level_formatter())); + _formatters.push_back(std::unique_ptr(new details::level_formatter( +#ifdef SPDLOG_ENABLE_PATTERN_PADDING + padding +#endif + ))); break; case 'L': - _formatters.push_back(std::unique_ptr(new details::short_level_formatter())); + _formatters.push_back(std::unique_ptr(new details::short_level_formatter( +#ifdef SPDLOG_ENABLE_PATTERN_PADDING + padding +#endif + ))); break; case('t'): - _formatters.push_back(std::unique_ptr(new details::t_formatter())); + _formatters.push_back(std::unique_ptr(new details::t_formatter( +#ifdef SPDLOG_ENABLE_PATTERN_PADDING + padding +#endif + ))); break; case('v'): @@ -555,20 +720,36 @@ inline void spdlog::pattern_formatter::handle_flag(char flag) break; case('a'): - _formatters.push_back(std::unique_ptr(new details::a_formatter())); + _formatters.push_back(std::unique_ptr(new details::a_formatter( +#ifdef SPDLOG_ENABLE_PATTERN_PADDING + padding +#endif + ))); break; case('A'): - _formatters.push_back(std::unique_ptr(new details::A_formatter())); + _formatters.push_back(std::unique_ptr(new details::A_formatter( +#ifdef SPDLOG_ENABLE_PATTERN_PADDING + padding +#endif + ))); break; case('b'): case('h'): - _formatters.push_back(std::unique_ptr(new details::b_formatter())); + _formatters.push_back(std::unique_ptr(new details::b_formatter( +#ifdef SPDLOG_ENABLE_PATTERN_PADDING + padding +#endif + ))); break; case('B'): - _formatters.push_back(std::unique_ptr(new details::B_formatter())); + _formatters.push_back(std::unique_ptr(new details::B_formatter( +#ifdef SPDLOG_ENABLE_PATTERN_PADDING + padding +#endif + ))); break; case('c'): _formatters.push_back(std::unique_ptr(new details::c_formatter())); @@ -649,7 +830,11 @@ inline void spdlog::pattern_formatter::handle_flag(char flag) break; case ('P'): - _formatters.push_back(std::unique_ptr(new details::pid_formatter())); + _formatters.push_back(std::unique_ptr(new details::pid_formatter( +#ifdef SPDLOG_ENABLE_PATTERN_PADDING + padding +#endif + ))); break; #if defined(SPDLOG_ENABLE_MESSAGE_COUNTER) @@ -663,6 +848,8 @@ inline void spdlog::pattern_formatter::handle_flag(char flag) _formatters.push_back(std::unique_ptr(new details::ch_formatter(flag))); break; } + + return true; } inline std::tm spdlog::pattern_formatter::get_time(details::log_msg& msg) diff --git a/include/spdlog/formatter.h b/include/spdlog/formatter.h index 6bba9025..02474c95 100644 --- a/include/spdlog/formatter.h +++ b/include/spdlog/formatter.h @@ -25,6 +25,14 @@ public: virtual void format(details::log_msg& msg) = 0; }; +#ifdef SPDLOG_ENABLE_PATTERN_PADDING +struct format_padding { + fmt::Alignment _alignment = fmt::ALIGN_RIGHT; + char _char = ' '; + unsigned _width = 0; +}; +#endif + class pattern_formatter SPDLOG_FINAL : public formatter { @@ -38,7 +46,11 @@ private: const pattern_time_type _pattern_time; std::vector> _formatters; std::tm get_time(details::log_msg& msg); - void handle_flag(char flag); +#ifndef SPDLOG_ENABLE_PATTERN_PADDING + bool handle_flag(char flag); +#else + bool handle_flag(char flag, format_padding& padding); +#endif void compile_pattern(const std::string& pattern); }; } diff --git a/include/spdlog/tweakme.h b/include/spdlog/tweakme.h index 53f5cf7e..01f75dfd 100644 --- a/include/spdlog/tweakme.h +++ b/include/spdlog/tweakme.h @@ -138,4 +138,10 @@ // // #define SPDLOG_LEVEL_NAMES { " TRACE", " DEBUG", " INFO", // " WARNING", " ERROR", "CRITICAL", "OFF" }; +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment to enable logger pattern padding. +// +// #define SPDLOG_ENABLE_PATTERN_PADDING /////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/tests/padding.cpp b/tests/padding.cpp new file mode 100644 index 00000000..d9143e29 --- /dev/null +++ b/tests/padding.cpp @@ -0,0 +1,34 @@ + +#include "includes.h" + +#ifdef SPDLOG_ENABLE_PATTERN_PADDING +template +std::string log_formatted(const T& what, const std::string& pattern = "%v") +{ + + std::ostringstream oss; + auto oss_sink = std::make_shared(oss); + + spdlog::logger oss_logger("oss", oss_sink); + oss_logger.set_level(spdlog::level::info); + oss_logger.set_pattern(pattern); + oss_logger.info(what); + + return oss.str().substr(0, oss.str().length() - spdlog::details::os::eol_size); +} + +TEST_CASE("padding", "[padding]") +{ + REQUIRE(log_formatted("Hello") == "Hello"); + REQUIRE(log_formatted("Hello", "%l %v") == "info Hello"); + REQUIRE(log_formatted("Hello", "%6l %v") == " info Hello"); + REQUIRE(log_formatted("Hello", "%-6l %v") == "info Hello"); + REQUIRE(log_formatted("Hello", "%06l %v") == "00info Hello"); + REQUIRE(log_formatted("Hello", "%-06l %v") == "info00 Hello"); + REQUIRE(log_formatted("Hello", "%12l %v") == " info Hello"); + REQUIRE(log_formatted("Hello", "%-12l %v") == "info Hello"); + REQUIRE(log_formatted("Hello", "%012l %v") == "00000000info Hello"); + REQUIRE(log_formatted("Hello", "%012l %v") == "00000000info Hello"); + REQUIRE(log_formatted("Hello", "%-012l %v") == "info00000000 Hello"); +} +#endif diff --git a/tests/tests.vcxproj b/tests/tests.vcxproj index f5c854db..186efbce 100644 --- a/tests/tests.vcxproj +++ b/tests/tests.vcxproj @@ -131,6 +131,7 @@ + diff --git a/tests/tests.vcxproj.filters b/tests/tests.vcxproj.filters index b5612d0c..7f8e4b29 100644 --- a/tests/tests.vcxproj.filters +++ b/tests/tests.vcxproj.filters @@ -39,6 +39,9 @@ Source Files + + Source Files +