#pragma once #include "bmcweb_config.h" #include #include #include #include #include #include #include #include #include #include namespace crow { enum class LogLevel { Disabled = 0, Debug, Info, Warning, Error, Critical, }; // Mapping of the external loglvl name to internal loglvl constexpr std::array, 7> mapLogLevelFromName{{{"disabled", crow::LogLevel::Disabled}, {"enabled", crow::LogLevel::Debug}, {"debug", crow::LogLevel::Debug}, {"info", crow::LogLevel::Info}, {"warning", crow::LogLevel::Warning}, {"error", crow::LogLevel::Error}, {"critical", crow::LogLevel::Critical}}}; constexpr crow::LogLevel getLogLevelFromName(std::string_view name) { const auto* iter = std::find_if(begin(mapLogLevelFromName), end(mapLogLevelFromName), [&name](const auto& v) { return v.first == name; }); if (iter != end(mapLogLevelFromName)) { return iter->second; } return crow::LogLevel::Disabled; } // configured bmcweb LogLevel constexpr crow::LogLevel bmcwebCurrentLoggingLevel = getLogLevelFromName(bmcwebLoggingLevel); class Logger { 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 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; } constexpr static LogLevel getCurrentLogLevel() { return bmcwebCurrentLoggingLevel; } constexpr static bool isLoggingEnabled() { return getCurrentLogLevel() >= crow::LogLevel::Debug; } constexpr static bool checkLoggingLevel(const LogLevel level) { return isLoggingEnabled() && (getCurrentLogLevel() <= level); } private: // std::ostringstream stringstream; }; } // 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__) #define BMCWEB_LOG_WARNING \ if constexpr (crow::Logger::checkLoggingLevel(crow::LogLevel::Warning)) \ crow::Logger("WARNING", __FILE__, __LINE__) #define BMCWEB_LOG_INFO \ if constexpr (crow::Logger::checkLoggingLevel(crow::LogLevel::Info)) \ crow::Logger("INFO", __FILE__, __LINE__) #define BMCWEB_LOG_DEBUG \ if constexpr (crow::Logger::checkLoggingLevel(crow::LogLevel::Debug)) \ crow::Logger("DEBUG", __FILE__, __LINE__) // NOLINTEND(cppcoreguidelines-macro-usage, clang-diagnostic-unused-macros)