diff --git a/include/spdlog/details/pattern_formatter-inl.h b/include/spdlog/details/pattern_formatter-inl.h index 8bee8a51..83d0283b 100644 --- a/include/spdlog/details/pattern_formatter-inl.h +++ b/include/spdlog/details/pattern_formatter-inl.h @@ -39,47 +39,50 @@ public: : padinfo_(padinfo) , dest_(dest) { - - if (padinfo_.width_ <= wrapped_size) + remaining_pad_ = static_cast(padinfo.width_) - static_cast(wrapped_size); + if (remaining_pad_ <= 0) { - total_pad_ = 0; return; } - total_pad_ = padinfo.width_ - wrapped_size; if (padinfo_.side_ == padding_info::left) { - pad_it(total_pad_); - total_pad_ = 0; + pad_it(remaining_pad_); + remaining_pad_ = 0; } else if (padinfo_.side_ == padding_info::center) { - auto half_pad = total_pad_ / 2; - auto reminder = total_pad_ & 1; + auto half_pad = remaining_pad_ / 2; + auto reminder = remaining_pad_ & 1; pad_it(half_pad); - total_pad_ = half_pad + reminder; // for the right side + remaining_pad_ = half_pad + reminder; // for the right side } } ~scoped_padder() { - if (total_pad_) + if (remaining_pad_ >= 0) { - pad_it(total_pad_); + pad_it(remaining_pad_); + } + else if (padinfo_.truncate_) + { + long new_size = static_cast(dest_.size()) + remaining_pad_; + dest_.resize(static_cast(new_size)); } } private: - void pad_it(size_t count) + void pad_it(long count) { // count = std::min(count, spaces_.size()); - assert(count <= spaces_.size()); + // assert(count <= spaces_.size()); fmt_helper::append_string_view(string_view_t(spaces_.data(), count), dest_); } const padding_info &padinfo_; memory_buf_t &dest_; - size_t total_pad_; + long remaining_pad_; string_view_t spaces_{" ", 64}; }; @@ -1209,7 +1212,7 @@ SPDLOG_INLINE void pattern_formatter::handle_flag_(char flag, details::padding_i } } -// Extract given pad spec (e.g. %8X) +// Extract given pad spec (e.g. %8X, %=8X, %-8!X, %8!X, %=8!X, %-8!X, %+8!X) // Advance the given it pass the end of the padding spec found (if any) // Return padding. SPDLOG_INLINE details::padding_info pattern_formatter::handle_padspec_(std::string::const_iterator &it, std::string::const_iterator end) @@ -1240,7 +1243,7 @@ SPDLOG_INLINE details::padding_info pattern_formatter::handle_padspec_(std::stri if (it == end || !std::isdigit(static_cast(*it))) { - return padding_info{0, side}; + return padding_info{}; // no padding if no digit found here } auto width = static_cast(*it) - '0'; @@ -1249,7 +1252,20 @@ SPDLOG_INLINE details::padding_info pattern_formatter::handle_padspec_(std::stri auto digit = static_cast(*it) - '0'; width = width * 10 + digit; } - return details::padding_info{std::min(width, max_width), side}; + + // search for the optional truncate marker '!' + bool truncate; + if (it != end && *it == '!') + { + truncate = true; + ++it; + } + else + { + truncate = false; + } + + return details::padding_info{std::min(width, max_width), side, truncate}; } SPDLOG_INLINE void pattern_formatter::compile_pattern_(const std::string &pattern) diff --git a/include/spdlog/details/pattern_formatter.h b/include/spdlog/details/pattern_formatter.h index b03d3394..fa134ada 100644 --- a/include/spdlog/details/pattern_formatter.h +++ b/include/spdlog/details/pattern_formatter.h @@ -29,17 +29,21 @@ struct padding_info }; padding_info() = default; - padding_info(size_t width, padding_info::pad_side side) + padding_info(size_t width, padding_info::pad_side side, bool truncate) : width_(width) , side_(side) + , truncate_(truncate) + , enabled_(true) {} bool enabled() const { - return width_ != 0; + return enabled_; } const size_t width_ = 0; const pad_side side_ = left; + bool truncate_ = false; + bool enabled_ = false; }; class flag_formatter diff --git a/tests/test_pattern_formatter.cpp b/tests/test_pattern_formatter.cpp index 9bf8d4b1..6aff454c 100644 --- a/tests/test_pattern_formatter.cpp +++ b/tests/test_pattern_formatter.cpp @@ -1,4 +1,5 @@ #include "includes.h" +#include "test_sink.h" using spdlog::memory_buf_t; @@ -138,58 +139,111 @@ TEST_CASE("color range test6", "[pattern_formatter]") TEST_CASE("level_left_padded", "[pattern_formatter]") { REQUIRE(log_to_str("Some message", "[%8l] %v", spdlog::pattern_time_type::local, "\n") == "[ info] Some message\n"); + REQUIRE(log_to_str("Some message", "[%8!l] %v", spdlog::pattern_time_type::local, "\n") == "[ info] Some message\n"); } TEST_CASE("level_right_padded", "[pattern_formatter]") { REQUIRE(log_to_str("Some message", "[%-8l] %v", spdlog::pattern_time_type::local, "\n") == "[info ] Some message\n"); + REQUIRE(log_to_str("Some message", "[%-8!l] %v", spdlog::pattern_time_type::local, "\n") == "[info ] Some message\n"); } TEST_CASE("level_center_padded", "[pattern_formatter]") { REQUIRE(log_to_str("Some message", "[%=8l] %v", spdlog::pattern_time_type::local, "\n") == "[ info ] Some message\n"); + REQUIRE(log_to_str("Some message", "[%=8!l] %v", spdlog::pattern_time_type::local, "\n") == "[ info ] Some message\n"); } TEST_CASE("short level_left_padded", "[pattern_formatter]") { REQUIRE(log_to_str("Some message", "[%3L] %v", spdlog::pattern_time_type::local, "\n") == "[ I] Some message\n"); + REQUIRE(log_to_str("Some message", "[%3!L] %v", spdlog::pattern_time_type::local, "\n") == "[ I] Some message\n"); } TEST_CASE("short level_right_padded", "[pattern_formatter]") { REQUIRE(log_to_str("Some message", "[%-3L] %v", spdlog::pattern_time_type::local, "\n") == "[I ] Some message\n"); + REQUIRE(log_to_str("Some message", "[%-3!L] %v", spdlog::pattern_time_type::local, "\n") == "[I ] Some message\n"); } TEST_CASE("short level_center_padded", "[pattern_formatter]") { REQUIRE(log_to_str("Some message", "[%=3L] %v", spdlog::pattern_time_type::local, "\n") == "[ I ] Some message\n"); + REQUIRE(log_to_str("Some message", "[%=3!L] %v", spdlog::pattern_time_type::local, "\n") == "[ I ] Some message\n"); } TEST_CASE("left_padded_short", "[pattern_formatter]") { REQUIRE(log_to_str("Some message", "[%3n] %v", spdlog::pattern_time_type::local, "\n") == "[pattern_tester] Some message\n"); + REQUIRE(log_to_str("Some message", "[%3!n] %v", spdlog::pattern_time_type::local, "\n") == "[pat] Some message\n"); } TEST_CASE("right_padded_short", "[pattern_formatter]") { REQUIRE(log_to_str("Some message", "[%-3n] %v", spdlog::pattern_time_type::local, "\n") == "[pattern_tester] Some message\n"); + REQUIRE(log_to_str("Some message", "[%-3!n] %v", spdlog::pattern_time_type::local, "\n") == "[pat] Some message\n"); } TEST_CASE("center_padded_short", "[pattern_formatter]") { REQUIRE(log_to_str("Some message", "[%=3n] %v", spdlog::pattern_time_type::local, "\n") == "[pattern_tester] Some message\n"); + REQUIRE(log_to_str("Some message", "[%=3!n] %v", spdlog::pattern_time_type::local, "\n") == "[pat] Some message\n"); } TEST_CASE("left_padded_huge", "[pattern_formatter]") { REQUIRE(log_to_str("Some message", "[%-300n] %v", spdlog::pattern_time_type::local, "\n") == - "[pattern_tester ] Some message\n"); + "[pattern_tester ] Some message\n"); + + REQUIRE(log_to_str("Some message", "[%-300!n] %v", spdlog::pattern_time_type::local, "\n") == + "[pattern_tester ] Some message\n"); } TEST_CASE("left_padded_max", "[pattern_formatter]") { REQUIRE(log_to_str("Some message", "[%-64n] %v", spdlog::pattern_time_type::local, "\n") == - "[pattern_tester ] Some message\n"); + "[pattern_tester ] Some message\n"); + + REQUIRE(log_to_str("Some message", "[%-64!n] %v", spdlog::pattern_time_type::local, "\n") == + "[pattern_tester ] Some message\n"); +} + +// Test padding + truncate flag + +TEST_CASE("paddinng_truncate", "[pattern_formatter]") +{ + REQUIRE(log_to_str("123456", "%6!v", spdlog::pattern_time_type::local, "\n") == "123456\n"); + REQUIRE(log_to_str("123456", "%5!v", spdlog::pattern_time_type::local, "\n") == "12345\n"); + REQUIRE(log_to_str("123456", "%7!v", spdlog::pattern_time_type::local, "\n") == " 123456\n"); + + REQUIRE(log_to_str("123456", "%-6!v", spdlog::pattern_time_type::local, "\n") == "123456\n"); + REQUIRE(log_to_str("123456", "%-5!v", spdlog::pattern_time_type::local, "\n") == "12345\n"); + REQUIRE(log_to_str("123456", "%-7!v", spdlog::pattern_time_type::local, "\n") == "123456 \n"); + + REQUIRE(log_to_str("123456", "%=6!v", spdlog::pattern_time_type::local, "\n") == "123456\n"); + REQUIRE(log_to_str("123456", "%=5!v", spdlog::pattern_time_type::local, "\n") == "12345\n"); + REQUIRE(log_to_str("123456", "%=7!v", spdlog::pattern_time_type::local, "\n") == "123456 \n"); + + REQUIRE(log_to_str("123456", "%0!v", spdlog::pattern_time_type::local, "\n") == "\n"); +} + +TEST_CASE("paddinng_truncate_funcname", "[pattern_formatter]") +{ + spdlog::sinks::test_sink_st test_sink; + + const char* pattern = "%v [%5!!]"; + auto formatter = std::unique_ptr(new spdlog::pattern_formatter(pattern)); + test_sink.set_formatter(std::move(formatter)); + + spdlog::details::log_msg msg1{spdlog::source_loc{"ignored", 1, "func"}, "test_logger", spdlog::level::info, "message"}; + test_sink.log(msg1); + + spdlog::details::log_msg msg2{spdlog::source_loc{"ignored", 1, "function"}, "test_logger", spdlog::level::info, "message"}; + test_sink.log(msg2); + + auto lines = test_sink.lines(); + REQUIRE(lines[0] == "message [ func]"); + REQUIRE(lines[1] == "message [funct]"); } TEST_CASE("clone-default-formatter", "[pattern_formatter]")