104e438cbSEd Tanous #pragma once 204e438cbSEd Tanous 3*662aa6e3SMyung Bae #include "bmcweb_config.h" 4*662aa6e3SMyung Bae 5*662aa6e3SMyung Bae #include <algorithm> 6*662aa6e3SMyung Bae #include <array> 704e438cbSEd Tanous #include <cstdio> 804e438cbSEd Tanous #include <cstdlib> 904e438cbSEd Tanous #include <ctime> 1004e438cbSEd Tanous #include <filesystem> 1104e438cbSEd Tanous #include <iostream> 1204e438cbSEd Tanous #include <sstream> 1304e438cbSEd Tanous #include <string> 14*662aa6e3SMyung Bae #include <string_view> 1504e438cbSEd Tanous 1604e438cbSEd Tanous namespace crow 1704e438cbSEd Tanous { 1804e438cbSEd Tanous enum class LogLevel 1904e438cbSEd Tanous { 20*662aa6e3SMyung Bae Disabled = 0, 21*662aa6e3SMyung Bae Debug, 2204e438cbSEd Tanous Info, 2304e438cbSEd Tanous Warning, 2404e438cbSEd Tanous Error, 2504e438cbSEd Tanous Critical, 2604e438cbSEd Tanous }; 2704e438cbSEd Tanous 28*662aa6e3SMyung Bae // Mapping of the external loglvl name to internal loglvl 29*662aa6e3SMyung Bae constexpr std::array<std::pair<std::string_view, crow::LogLevel>, 7> 30*662aa6e3SMyung Bae mapLogLevelFromName{{{"disabled", crow::LogLevel::Disabled}, 31*662aa6e3SMyung Bae {"enabled", crow::LogLevel::Debug}, 32*662aa6e3SMyung Bae {"debug", crow::LogLevel::Debug}, 33*662aa6e3SMyung Bae {"info", crow::LogLevel::Info}, 34*662aa6e3SMyung Bae {"warning", crow::LogLevel::Warning}, 35*662aa6e3SMyung Bae {"error", crow::LogLevel::Error}, 36*662aa6e3SMyung Bae {"critical", crow::LogLevel::Critical}}}; 37*662aa6e3SMyung Bae 38*662aa6e3SMyung Bae constexpr crow::LogLevel getLogLevelFromName(std::string_view name) 39*662aa6e3SMyung Bae { 40*662aa6e3SMyung Bae const auto* iter = 41*662aa6e3SMyung Bae std::find_if(begin(mapLogLevelFromName), end(mapLogLevelFromName), 42*662aa6e3SMyung Bae [&name](const auto& v) { return v.first == name; }); 43*662aa6e3SMyung Bae if (iter != end(mapLogLevelFromName)) 44*662aa6e3SMyung Bae { 45*662aa6e3SMyung Bae return iter->second; 46*662aa6e3SMyung Bae } 47*662aa6e3SMyung Bae return crow::LogLevel::Disabled; 48*662aa6e3SMyung Bae } 49*662aa6e3SMyung Bae 50*662aa6e3SMyung Bae // configured bmcweb LogLevel 51*662aa6e3SMyung Bae constexpr crow::LogLevel bmcwebCurrentLoggingLevel = 52*662aa6e3SMyung Bae getLogLevelFromName(bmcwebLoggingLevel); 53*662aa6e3SMyung Bae 5404e438cbSEd Tanous class Logger 5504e438cbSEd Tanous { 5604e438cbSEd Tanous private: 5704e438cbSEd Tanous // 5804e438cbSEd Tanous static std::string timestamp() 5904e438cbSEd Tanous { 6004e438cbSEd Tanous std::string date; 6104e438cbSEd Tanous date.resize(32, '\0'); 6204e438cbSEd Tanous time_t t = time(nullptr); 6304e438cbSEd Tanous 6404e438cbSEd Tanous tm myTm{}; 6504e438cbSEd Tanous 6604e438cbSEd Tanous gmtime_r(&t, &myTm); 6704e438cbSEd Tanous 6804e438cbSEd Tanous size_t sz = 6904e438cbSEd Tanous strftime(date.data(), date.size(), "%Y-%m-%d %H:%M:%S", &myTm); 7004e438cbSEd Tanous date.resize(sz); 7104e438cbSEd Tanous return date; 7204e438cbSEd Tanous } 7304e438cbSEd Tanous 7404e438cbSEd Tanous public: 7504e438cbSEd Tanous Logger([[maybe_unused]] const std::string& prefix, 7604e438cbSEd Tanous [[maybe_unused]] const std::string& filename, 77*662aa6e3SMyung Bae [[maybe_unused]] const size_t line) 7804e438cbSEd Tanous { 7904e438cbSEd Tanous stringstream << "(" << timestamp() << ") [" << prefix << " " 8004e438cbSEd Tanous << std::filesystem::path(filename).filename() << ":" 8104e438cbSEd Tanous << line << "] "; 8204e438cbSEd Tanous } 8304e438cbSEd Tanous ~Logger() 8404e438cbSEd Tanous { 8504e438cbSEd Tanous stringstream << std::endl; 8604e438cbSEd Tanous std::cerr << stringstream.str(); 8704e438cbSEd Tanous } 8804e438cbSEd Tanous 89ecd6a3a2SEd Tanous Logger(const Logger&) = delete; 90ecd6a3a2SEd Tanous Logger(Logger&&) = delete; 91ecd6a3a2SEd Tanous Logger& operator=(const Logger&) = delete; 92ecd6a3a2SEd Tanous Logger& operator=(const Logger&&) = delete; 93ecd6a3a2SEd Tanous 9404e438cbSEd Tanous // 9504e438cbSEd Tanous template <typename T> 9604e438cbSEd Tanous Logger& operator<<([[maybe_unused]] T const& value) 9704e438cbSEd Tanous { 989b6ffca5SEd Tanous // Somewhere in the code we're implicitly casting an array to a 99*662aa6e3SMyung Bae // pointer in logging code. It's non-trivial to find, 100*662aa6e3SMyung Bae // so disable the check here for now 1019b6ffca5SEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) 10204e438cbSEd Tanous stringstream << value; 10304e438cbSEd Tanous return *this; 10404e438cbSEd Tanous } 10504e438cbSEd Tanous 106*662aa6e3SMyung Bae constexpr static LogLevel getCurrentLogLevel() 10704e438cbSEd Tanous { 108*662aa6e3SMyung Bae return bmcwebCurrentLoggingLevel; 10904e438cbSEd Tanous } 11004e438cbSEd Tanous 111*662aa6e3SMyung Bae constexpr static bool isLoggingEnabled() 11204e438cbSEd Tanous { 113*662aa6e3SMyung Bae return getCurrentLogLevel() >= crow::LogLevel::Debug; 114*662aa6e3SMyung Bae } 115*662aa6e3SMyung Bae 116*662aa6e3SMyung Bae constexpr static bool checkLoggingLevel(const LogLevel level) 117*662aa6e3SMyung Bae { 118*662aa6e3SMyung Bae return isLoggingEnabled() && (getCurrentLogLevel() <= level); 11904e438cbSEd Tanous } 12004e438cbSEd Tanous 12104e438cbSEd Tanous private: 12204e438cbSEd Tanous // 12304e438cbSEd Tanous std::ostringstream stringstream; 12404e438cbSEd Tanous }; 12504e438cbSEd Tanous } // namespace crow 12604e438cbSEd Tanous 127600d2394SEd Tanous // The logging functions currently use macros. Now that we have c++20, ideally 128600d2394SEd Tanous // they'd use source_location with fixed functions, but for the moment, disable 129600d2394SEd Tanous // the check. 130600d2394SEd Tanous 131600d2394SEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 13204e438cbSEd Tanous #define BMCWEB_LOG_CRITICAL \ 133*662aa6e3SMyung Bae if constexpr (crow::Logger::checkLoggingLevel(crow::LogLevel::Critical)) \ 134*662aa6e3SMyung Bae crow::Logger("CRITICAL", __FILE__, __LINE__) 135600d2394SEd Tanous 136600d2394SEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 13704e438cbSEd Tanous #define BMCWEB_LOG_ERROR \ 138*662aa6e3SMyung Bae if constexpr (crow::Logger::checkLoggingLevel(crow::LogLevel::Error)) \ 139*662aa6e3SMyung Bae crow::Logger("ERROR", __FILE__, __LINE__) 140600d2394SEd Tanous 141600d2394SEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 14204e438cbSEd Tanous #define BMCWEB_LOG_WARNING \ 143*662aa6e3SMyung Bae if constexpr (crow::Logger::checkLoggingLevel(crow::LogLevel::Warning)) \ 144*662aa6e3SMyung Bae crow::Logger("WARNING", __FILE__, __LINE__) 145600d2394SEd Tanous 146600d2394SEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 14704e438cbSEd Tanous #define BMCWEB_LOG_INFO \ 148*662aa6e3SMyung Bae if constexpr (crow::Logger::checkLoggingLevel(crow::LogLevel::Info)) \ 149*662aa6e3SMyung Bae crow::Logger("INFO", __FILE__, __LINE__) 150600d2394SEd Tanous 151600d2394SEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 15204e438cbSEd Tanous #define BMCWEB_LOG_DEBUG \ 153*662aa6e3SMyung Bae if constexpr (crow::Logger::checkLoggingLevel(crow::LogLevel::Debug)) \ 154*662aa6e3SMyung Bae crow::Logger("DEBUG", __FILE__, __LINE__) 155