summaryrefslogtreecommitdiff
path: root/http/logging.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'http/logging.hpp')
-rw-r--r--http/logging.hpp273
1 files changed, 178 insertions, 95 deletions
diff --git a/http/logging.hpp b/http/logging.hpp
index 368548f9c0..bf5e42eb79 100644
--- a/http/logging.hpp
+++ b/http/logging.hpp
@@ -2,16 +2,119 @@
#include "bmcweb_config.h"
-#include <algorithm>
-#include <array>
-#include <cstdio>
-#include <cstdlib>
-#include <ctime>
-#include <filesystem>
+#include <boost/system/error_code.hpp>
+#include <boost/url/pct_string_view.hpp>
+#include <boost/url/string_view.hpp>
+#include <boost/url/url.hpp>
+#include <nlohmann/json.hpp>
+
+#include <bit>
+#include <format>
#include <iostream>
-#include <sstream>
-#include <string>
+#include <source_location>
#include <string_view>
+#include <system_error>
+
+// Clang-tidy would rather these be static, but using static causes the template
+// specialization to not function. Ignore the warning.
+// NOLINTBEGIN(readability-convert-member-functions-to-static, cert-dcl58-cpp)
+template <>
+struct std::formatter<boost::system::error_code>
+{
+ constexpr auto parse(std::format_parse_context& ctx)
+ {
+ return ctx.begin();
+ }
+
+ auto format(const boost::system::error_code& ec, auto& ctx) const
+ {
+ return std::format_to(ctx.out(), "{}", ec.what());
+ }
+};
+
+template <>
+struct std::formatter<boost::urls::pct_string_view>
+{
+ constexpr auto parse(std::format_parse_context& ctx)
+ {
+ return ctx.begin();
+ }
+ auto format(const boost::urls::pct_string_view& msg, auto& ctx) const
+ {
+ return std::format_to(ctx.out(), "{}",
+ std::string_view(msg.data(), msg.size()));
+ }
+};
+
+template <>
+struct std::formatter<boost::urls::url>
+{
+ constexpr auto parse(std::format_parse_context& ctx)
+ {
+ return ctx.begin();
+ }
+ auto format(const boost::urls::url& msg, auto& ctx) const
+ {
+ return std::format_to(ctx.out(), "{}", std::string_view(msg.buffer()));
+ }
+};
+
+template <>
+struct std::formatter<boost::core::string_view>
+{
+ constexpr auto parse(std::format_parse_context& ctx)
+ {
+ return ctx.begin();
+ }
+ auto format(const boost::core::string_view& msg, auto& ctx) const
+ {
+ return std::format_to(ctx.out(), "{}", std::string_view(msg));
+ }
+};
+
+template <>
+struct std::formatter<void*>
+{
+ constexpr auto parse(std::format_parse_context& ctx)
+ {
+ return ctx.begin();
+ }
+ auto format(const void*& ptr, auto& ctx) const
+ {
+ return std::format_to(ctx.out(), "{}",
+ std::to_string(std::bit_cast<size_t>(ptr)));
+ }
+};
+
+template <>
+struct std::formatter<nlohmann::json::json_pointer>
+{
+ constexpr auto parse(std::format_parse_context& ctx)
+ {
+ return ctx.begin();
+ }
+ auto format(const nlohmann::json::json_pointer& ptr, auto& ctx) const
+ {
+ return std::format_to(ctx.out(), "{}", ptr.to_string());
+ }
+};
+
+template <>
+struct std::formatter<nlohmann::json>
+{
+ static constexpr auto parse(std::format_parse_context& ctx)
+ {
+ return ctx.begin();
+ }
+ auto format(const nlohmann::json& json, auto& ctx) const
+ {
+ return std::format_to(
+ ctx.out(), "{}",
+ json.dump(-1, ' ', false,
+ nlohmann::json::error_handler_t::replace));
+ }
+};
+// NOLINTEND(readability-convert-member-functions-to-static, cert-dcl58-cpp)
namespace crow
{
@@ -51,103 +154,83 @@ constexpr crow::LogLevel getLogLevelFromName(std::string_view name)
constexpr crow::LogLevel bmcwebCurrentLoggingLevel =
getLogLevelFromName(bmcwebLoggingLevel);
-class Logger
+struct FormatString
{
- private:
- //
- static std::string timestamp()
- {
- std::string date;
- date.resize(32, '\0');
- time_t t = time(nullptr);
-
- tm myTm{};
-
- gmtime_r(&t, &myTm);
-
- size_t sz = strftime(date.data(), date.size(), "%Y-%m-%d %H:%M:%S",
- &myTm);
- date.resize(sz);
- return date;
- }
-
- public:
- Logger([[maybe_unused]] const std::string& prefix,
- [[maybe_unused]] const std::string& filename,
- [[maybe_unused]] const size_t line)
- {
- stringstream << "(" << timestamp() << ") [" << prefix << " "
- << std::filesystem::path(filename).filename() << ":"
- << line << "] ";
- }
- ~Logger()
- {
- stringstream << std::endl;
- std::cerr << stringstream.str();
- }
-
- Logger(const Logger&) = delete;
- Logger(Logger&&) = delete;
- Logger& operator=(const Logger&) = delete;
- Logger& operator=(const Logger&&) = delete;
-
- //
- template <typename T>
- Logger& operator<<([[maybe_unused]] const T& value)
- {
- // Somewhere in the code we're implicitly casting an array to a
- // pointer in logging code. It's non-trivial to find,
- // so disable the check here for now
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
- stringstream << value;
- return *this;
- }
+ std::string_view str;
+ std::source_location loc;
+
+ // NOLINTNEXTLINE(google-explicit-constructor)
+ FormatString(const char* strIn, const std::source_location& locIn =
+ std::source_location::current()) :
+ str(strIn),
+ loc(locIn)
+ {}
+};
- constexpr static LogLevel getCurrentLogLevel()
- {
- return bmcwebCurrentLoggingLevel;
- }
+template <typename T>
+const void* logPtr(T p)
+{
+ static_assert(std::is_pointer<T>::value,
+ "Can't use logPtr without pointer");
+ return std::bit_cast<const void*>(p);
+}
- constexpr static bool isLoggingEnabled()
+template <LogLevel level>
+inline void vlog(const FormatString& format, std::format_args&& args)
+{
+ if constexpr (bmcwebCurrentLoggingLevel > level)
{
- return getCurrentLogLevel() >= crow::LogLevel::Debug;
+ return;
}
-
- constexpr static bool checkLoggingLevel(const LogLevel level)
+ constexpr size_t stringIndex = static_cast<size_t>(level);
+ static_assert(stringIndex < mapLogLevelFromName.size(),
+ "Missing string for level");
+ constexpr std::string_view levelString =
+ mapLogLevelFromName[stringIndex].first;
+ std::string_view filename = format.loc.file_name();
+ if (filename.starts_with("../"))
{
- return isLoggingEnabled() && (getCurrentLogLevel() <= level);
+ filename = filename.substr(3);
}
-
- private:
- //
- std::ostringstream stringstream;
-};
+ std::cout << std::format("[{} {}:{}] ", levelString, filename,
+ format.loc.line());
+ std::cout << std::vformat(format.str, args);
+ std::putc('\n', stdout);
+}
} // namespace crow
-// Disable clang-tidy warnings about unused macros.
-// NOLINTBEGIN(cppcoreguidelines-macro-usage, clang-diagnostic-unused-macros)
-
-// The logging functions currently use macros. Now that we have c++20, ideally
-// they'd use source_location with fixed functions, but for the moment, disable
-// the check.
-#define BMCWEB_LOG_CRITICAL \
- if constexpr (crow::Logger::checkLoggingLevel(crow::LogLevel::Critical)) \
- crow::Logger("CRITICAL", __FILE__, __LINE__)
-
-#define BMCWEB_LOG_ERROR \
- if constexpr (crow::Logger::checkLoggingLevel(crow::LogLevel::Error)) \
- crow::Logger("ERROR", __FILE__, __LINE__)
+template <typename... Args>
+inline void BMCWEB_LOG_CRITICAL(const crow::FormatString& format,
+ Args&&... args)
+{
+ crow::vlog<crow::LogLevel::Critical>(
+ format, std::make_format_args(std::forward<Args>(args)...));
+}
-#define BMCWEB_LOG_WARNING \
- if constexpr (crow::Logger::checkLoggingLevel(crow::LogLevel::Warning)) \
- crow::Logger("WARNING", __FILE__, __LINE__)
+template <typename... Args>
+inline void BMCWEB_LOG_ERROR(const crow::FormatString& format, Args&&... args)
+{
+ crow::vlog<crow::LogLevel::Error>(
+ format, std::make_format_args(std::forward<Args>(args)...));
+}
-#define BMCWEB_LOG_INFO \
- if constexpr (crow::Logger::checkLoggingLevel(crow::LogLevel::Info)) \
- crow::Logger("INFO", __FILE__, __LINE__)
+template <typename... Args>
+inline void BMCWEB_LOG_WARNING(const crow::FormatString& format, Args&&... args)
+{
+ crow::vlog<crow::LogLevel::Warning>(
+ format, std::make_format_args(std::forward<Args>(args)...));
+}
-#define BMCWEB_LOG_DEBUG \
- if constexpr (crow::Logger::checkLoggingLevel(crow::LogLevel::Debug)) \
- crow::Logger("DEBUG", __FILE__, __LINE__)
+template <typename... Args>
+inline void BMCWEB_LOG_INFO(const crow::FormatString& format, Args&&... args)
+{
+ crow::vlog<crow::LogLevel::Info>(
+ format, std::make_format_args(std::forward<Args>(args)...));
+}
-// NOLINTEND(cppcoreguidelines-macro-usage, clang-diagnostic-unused-macros)
+template <typename... Args>
+inline void BMCWEB_LOG_DEBUG(const crow::FormatString& format, Args&&... args)
+{
+ crow::vlog<crow::LogLevel::Debug>(
+ format, std::make_format_args(std::forward<Args>(args)...));
+}