#include <iostream>
#include <string>
#include <optional>
+#include <fmt/chrono.h>
#if FMT_VERSION >= 90000
#include <fmt/ostream.h>
#endif
ostream& operator<<(ostream& m, const chrono::duration<Rep, Period>& t);
}
-#if FMT_VERSION >= 90000
-template<typename Clock>
-struct fmt::formatter<std::chrono::time_point<Clock>> : fmt::ostream_formatter {};
-#endif
+// concept helpers for the formatters:
+
+template <typename TimeP>
+concept SteadyTimepoint = TimeP::clock::is_steady;
+
+template <typename TimeP>
+concept UnsteadyTimepoint = ! TimeP::clock::is_steady;
+
+namespace fmt {
+template <UnsteadyTimepoint T>
+struct formatter<T> {
+ constexpr auto parse(fmt::format_parse_context& ctx) { return ctx.begin(); }
+ template <typename FormatContext>
+ auto format(const T& t, FormatContext& ctx) const
+ {
+ struct tm bdt;
+ time_t tt = T::clock::to_time_t(t);
+ localtime_r(&tt, &bdt);
+ char tz[32] = {0};
+ strftime(tz, sizeof(tz), "%z", &bdt);
+
+ return fmt::format_to(
+ ctx.out(), "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}:{:06}{}",
+ (bdt.tm_year + 1900), (bdt.tm_mon + 1), bdt.tm_mday, bdt.tm_hour,
+ bdt.tm_min, bdt.tm_sec,
+ duration_cast<std::chrono::microseconds>(
+ t.time_since_epoch() % std::chrono::seconds(1))
+ .count(),
+ tz);
+ }
+};
+
+template <SteadyTimepoint T>
+struct formatter<T> {
+ constexpr auto parse(fmt::format_parse_context& ctx) { return ctx.begin(); }
+ template <typename FormatContext>
+ auto format(const T& t, FormatContext& ctx) const
+ {
+ return fmt::format_to(
+ ctx.out(), "{}s",
+ std::chrono::duration<double>(t.time_since_epoch()).count());
+ }
+};
+} // namespace fmt
#endif // COMMON_CEPH_TIME_H
concept HasDoFormatTo = requires(T x, std::back_insert_iterator<fmt::memory_buffer> out) {
{ x.do_format_to(out, true) } -> std::same_as<decltype(out)>;
};
-template <HasDoFormatTo T> struct fmt::formatter<T> : fmt::formatter<std::string_view> {
+namespace fmt {
+// placed in the fmt namespace due to an ADL bug in g++ < 12
+// (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92944).
+template <HasDoFormatTo T> struct formatter<T> : formatter<std::string_view> {
template <typename FormatContext>
auto format(const T& staged_iterator, FormatContext& ctx) {
return staged_iterator.do_format_to(ctx.out(), true);
}
};
+}
}
}
+namespace fmt {
+// placed in the fmt namespace due to an ADL bug in g++ < 12
+// (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92944).
+// Specifically - gcc pre-12 can't handle two templated specializations of
+// the formatter if in two different namespaces.
template <std::derived_from<Message> M>
-struct fmt::formatter<M> {
- constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
+struct formatter<M> {
+ constexpr auto parse(fmt::format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const M& m, FormatContext& ctx) const {
std::ostringstream oss;
}
}
};
+} // namespace fmt
#endif
DECLARE_LOCALS; // 'scrbr' & 'pg_id' aliases
dout(10) << "ReservingReplicas::react(const ReservationTimeout&)" << dendl;
- dout(10)
- << "PgScrubber: " << scrbr->get_spgid()
- << " timeout on reserving replicas (since " << entered_at
- << ")" << dendl;
- scrbr->get_clog()->warn()
- << "osd." << scrbr->get_whoami()
- << " PgScrubber: " << scrbr->get_spgid()
- << " timeout on reserving replicsa (since " << entered_at
- << ")";
-
+ const auto msg = fmt::format(
+ "PgScrubber: {} timeout on reserving replicas (since {})",
+ scrbr->get_spgid(), entered_at);
+ dout(5) << msg << dendl;
+ scrbr->get_clog()->warn() << "osd." << scrbr->get_whoami() << " " << msg;
scrbr->on_replica_reservation_timeout();
return discard_event();
}