From a58d07aaa39b7852fc6c79563c2ae8c92d853d4d Mon Sep 17 00:00:00 2001 From: Casey Bodley Date: Mon, 24 Jun 2024 11:23:36 -0400 Subject: [PATCH] dout: add macros for libfmt-style logging new dout macros use fmt::print() to write output directly to the underlying ostream. this enables libfmt's printf-style formatting syntax for ceph log output, without the string allocation overhead of: dout(10) << fmt::format("str={} count={}", str, count) << dendl; which becomes: dout_fmt(10, "str={} count={}", str, count); Signed-off-by: Casey Bodley --- src/common/dout_fmt.h | 56 +++++++++++++++++++++++++++++++ src/test/common/CMakeLists.txt | 4 +++ src/test/common/test_dout_fmt.cc | 57 ++++++++++++++++++++++++++++++++ 3 files changed, 117 insertions(+) create mode 100644 src/common/dout_fmt.h create mode 100644 src/test/common/test_dout_fmt.cc diff --git a/src/common/dout_fmt.h b/src/common/dout_fmt.h new file mode 100644 index 00000000000..c22fdf30cfe --- /dev/null +++ b/src/common/dout_fmt.h @@ -0,0 +1,56 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab ft=cpp + +/* + * Ceph - scalable distributed file system + * + * Copyright contributors to the Ceph project + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#pragma once + +#include +#include +#include +#include "dout.h" + +/// \file dout_fmt.h +/// +/// \brief dout macros to format log statements with libfmt +/// +/// A set of dout macros taking a format string and its corresponding argument +/// list. Log output is written directly to the underlying std::ostream by +/// fmt::print() rather than exposing the stream for ostream operator +/// chaining. + +// work around "warning: value computed is not used" with default dout_prefix +inline void dout_fmt_use_prefix(std::ostream&) {} + +#define lsubdout_fmt(cct, sub, v, ...) \ + dout_impl(cct, ceph_subsys_##sub, v) \ + dout_fmt_use_prefix(dout_prefix); \ + fmt::print(*_dout, __VA_ARGS__); \ + *_dout << dendl + +#define ldout_fmt(cct, v, ...) \ + dout_impl(cct, dout_subsys, v) \ + dout_fmt_use_prefix(dout_prefix); \ + fmt::print(*_dout, __VA_ARGS__); \ + *_dout << dendl + +#define dout_fmt(v, ...) \ + ldout_fmt((dout_context), v, __VA_ARGS__) + +#define ldpp_dout_fmt(dpp, v, ...) \ + if (decltype(auto) pdpp = (dpp); pdpp) { /* workaround -Wnonnull-compare for 'this' */ \ + dout_impl(pdpp->get_cct(), ceph::dout::need_dynamic(pdpp->get_subsys()), v) \ + pdpp->gen_prefix(*_dout); \ + fmt::print(*_dout, __VA_ARGS__); \ + *_dout << dendl; \ + } diff --git a/src/test/common/CMakeLists.txt b/src/test/common/CMakeLists.txt index 428ef7b0147..11a7ea0e20c 100644 --- a/src/test/common/CMakeLists.txt +++ b/src/test/common/CMakeLists.txt @@ -312,6 +312,10 @@ target_link_libraries(unittest_dns_resolve global) add_ceph_unittest(unittest_dns_resolve) endif() +add_executable(unittest_dout_fmt test_dout_fmt.cc $) +target_link_libraries(unittest_dout_fmt global) +add_ceph_unittest(unittest_dout_fmt) + # We're getting an ICE when trying to compile this test using mingw-gcc and # recent Boost versions. Note that mingw-llvm works fine. if (NOT WIN32 OR (NOT(CMAKE_CXX_COMPILER_ID STREQUAL GNU))) diff --git a/src/test/common/test_dout_fmt.cc b/src/test/common/test_dout_fmt.cc new file mode 100644 index 00000000000..7d6b519fe35 --- /dev/null +++ b/src/test/common/test_dout_fmt.cc @@ -0,0 +1,57 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab ft=cpp + +/* + * Ceph - scalable distributed file system + * + * Copyright contributors to the Ceph project + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#include "common/dout_fmt.h" +#include + +TEST(DoutFmt, SubDout) +{ + // expect level 0 to always be gathered + lsubdout_fmt(g_ceph_context, test, 0, "{}: {}", "value", 42); + // expect level 99 to be compiled out + lsubdout_fmt(g_ceph_context, test, 99, "{}: {}", "value", 42); +} + +#define dout_subsys ceph_subsys_test + +TEST(DoutFmt, Dout) +{ + ldout_fmt(g_ceph_context, 0, "{}: {}", "value", 42); + ldout_fmt(g_ceph_context, 99, "{}: {}", "value", 42); +} + +#define dout_context g_ceph_context + +TEST(DoutFmt, DoutContext) +{ + dout_fmt(0, "{}: {}", "value", 42); + dout_fmt(99, "{}: {}", "value", 42); +} + +#undef dout_prefix +#define dout_prefix *_dout << "prefix: " + +TEST(DoutFmt, DoutPrefix) +{ + ldout_fmt(g_ceph_context, 0, "{}: {}", "value", 42); + ldout_fmt(g_ceph_context, 99, "{}: {}", "value", 42); +} + +TEST(DoutFmt, DppDout) +{ + const DoutPrefix dpp{g_ceph_context, dout_subsys, "prefix: "}; + ldpp_dout_fmt(&dpp, 0, "{}: {}", "value", 42); + ldpp_dout_fmt(&dpp, 99, "{}: {}", "value", 42); +} -- 2.39.5