diff --git a/include/seastar/util/backtrace.hh b/include/seastar/util/backtrace.hh index 5a4dbad54e..ec4b959734 100644 --- a/include/seastar/util/backtrace.hh +++ b/include/seastar/util/backtrace.hh @@ -84,18 +84,20 @@ public: using vector_type = boost::container::static_vector; private: vector_type _frames; - size_t _hash; - char _delimeter; + size_t _hash = 0; + char _delimeter = ' '; private: size_t calculate_hash() const noexcept; public: - simple_backtrace(vector_type f, char delimeter = ' ') noexcept : _frames(std::move(f)), _hash(calculate_hash()), _delimeter(delimeter) {} - simple_backtrace(char delimeter = ' ') noexcept : simple_backtrace({}, delimeter) {} + simple_backtrace(vector_type f) noexcept : _frames(std::move(f)), _hash(calculate_hash()) {} + simple_backtrace() noexcept = default; + [[deprecated]] simple_backtrace(vector_type f, char delimeter) : _frames(std::move(f)), _hash(calculate_hash()), _delimeter(delimeter) {} + [[deprecated]] simple_backtrace(char delimeter) : _delimeter(delimeter) {} size_t hash() const noexcept { return _hash; } char delimeter() const noexcept { return _delimeter; } - friend std::ostream& operator<<(std::ostream& out, const simple_backtrace&); + friend fmt::formatter; bool operator==(const simple_backtrace& o) const noexcept { return _hash == o._hash && _frames == o._frames; @@ -116,7 +118,7 @@ public: : _task_type(&ti) { } - friend std::ostream& operator<<(std::ostream& out, const task_entry&); + friend fmt::formatter; bool operator==(const task_entry& o) const noexcept { return *_task_type == *o._task_type; @@ -151,7 +153,7 @@ public: size_t hash() const noexcept { return _hash; } char delimeter() const noexcept { return _main.delimeter(); } - friend std::ostream& operator<<(std::ostream& out, const tasktrace&); + friend fmt::formatter; bool operator==(const tasktrace& o) const noexcept; @@ -182,10 +184,22 @@ struct hash { } -#if FMT_VERSION >= 90000 -template <> struct fmt::formatter : fmt::ostream_formatter {}; -template <> struct fmt::formatter : fmt::ostream_formatter {}; -#endif +template <> struct fmt::formatter { + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + auto format(const seastar::frame&, fmt::format_context& ctx) const -> decltype(ctx.out()); +}; +template <> struct fmt::formatter { + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + auto format(const seastar::simple_backtrace&, fmt::format_context& ctx) const -> decltype(ctx.out()); +}; +template <> struct fmt::formatter { + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + auto format(const seastar::tasktrace&, fmt::format_context& ctx) const -> decltype(ctx.out()); +}; +template <> struct fmt::formatter { + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + auto format(const seastar::task_entry&, fmt::format_context& ctx) const -> decltype(ctx.out()); +}; namespace seastar { diff --git a/src/util/backtrace.cc b/src/util/backtrace.cc index cadf841e98..9b3a0bc944 100644 --- a/src/util/backtrace.cc +++ b/src/util/backtrace.cc @@ -33,6 +33,7 @@ module; #include #include #include +#include #ifdef SEASTAR_MODULE module seastar; @@ -111,37 +112,23 @@ size_t simple_backtrace::calculate_hash() const noexcept { } std::ostream& operator<<(std::ostream& out, const frame& f) { - if (!f.so->name.empty()) { - out << f.so->name << "+"; - } - out << format("0x{:x}", f.addr); + fmt::print(out, "{}", f); return out; } std::ostream& operator<<(std::ostream& out, const simple_backtrace& b) { - char delim[2] = {'\0', '\0'}; - for (auto f : b._frames) { - out << delim << f; - delim[0] = b.delimeter(); - } + fmt::print(out, "{}", b); return out; } std::ostream& operator<<(std::ostream& out, const tasktrace& b) { - out << b._main; - for (auto&& e : b._prev) { - out << "\n --------"; - std::visit(make_visitor([&] (const shared_backtrace& sb) { - out << '\n' << sb; - }, [&] (const task_entry& f) { - out << "\n " << f; - }), e); - } + fmt::print(out, "{}", b); return out; } std::ostream& operator<<(std::ostream& out, const task_entry& e) { - return out << seastar::pretty_type_name(*e._task_type); + fmt::print(out, "{}", e); + return out; } tasktrace current_tasktrace() noexcept { @@ -195,3 +182,43 @@ bool tasktrace::operator==(const tasktrace& o) const noexcept { tasktrace::~tasktrace() {} } // namespace seastar + +namespace fmt { + +auto formatter::format(const seastar::frame& f, format_context& ctx) const + -> decltype(ctx.out()) { + auto out = ctx.out(); + if (!f.so->name.empty()) { + out = fmt::format_to(out, "{}+", f.so->name); + } + return fmt::format_to(out, "0x{:x}", f.addr); +} + +auto formatter::format(const seastar::simple_backtrace& b, format_context& ctx) const + -> decltype(ctx.out()) { + return fmt::format_to(ctx.out(), "{}", fmt::join(b._frames, " ")); +} + +auto formatter::format(const seastar::tasktrace& b, format_context& ctx) const + -> decltype(ctx.out()) { + auto out = ctx.out(); + out = fmt::format_to(out, "{}", b._main); + for (auto&& e : b._prev) { + out = fmt::format_to(out, "\n --------"); + out = std::visit(seastar::make_visitor( + [&] (const seastar::shared_backtrace& sb) { + return fmt::format_to(out, "\n{}", sb); + }, + [&] (const seastar::task_entry& f) { + return fmt::format_to(out, "\n {}", f); + }), e); + } + return out; +} + +auto formatter::format(const seastar::task_entry& e, format_context& ctx) const + -> decltype(ctx.out()) { + return fmt::format_to(ctx.out(), "{}", seastar::pretty_type_name(*e._task_type)); +} + +}