104e438cbSEd Tanous #pragma once 204e438cbSEd Tanous 304e438cbSEd Tanous #include <cstdio> 404e438cbSEd Tanous #include <cstdlib> 504e438cbSEd Tanous #include <ctime> 604e438cbSEd Tanous #include <filesystem> 704e438cbSEd Tanous #include <iostream> 804e438cbSEd Tanous #include <sstream> 904e438cbSEd Tanous #include <string> 1004e438cbSEd Tanous 1104e438cbSEd Tanous namespace crow 1204e438cbSEd Tanous { 1304e438cbSEd Tanous enum class LogLevel 1404e438cbSEd Tanous { 1504e438cbSEd Tanous Debug = 0, 1604e438cbSEd Tanous Info, 1704e438cbSEd Tanous Warning, 1804e438cbSEd Tanous Error, 1904e438cbSEd Tanous Critical, 2004e438cbSEd Tanous }; 2104e438cbSEd Tanous 2204e438cbSEd Tanous class Logger 2304e438cbSEd Tanous { 2404e438cbSEd Tanous private: 2504e438cbSEd Tanous // 2604e438cbSEd Tanous static std::string timestamp() 2704e438cbSEd Tanous { 2804e438cbSEd Tanous std::string date; 2904e438cbSEd Tanous date.resize(32, '\0'); 3004e438cbSEd Tanous time_t t = time(nullptr); 3104e438cbSEd Tanous 3204e438cbSEd Tanous tm myTm{}; 3304e438cbSEd Tanous 3404e438cbSEd Tanous gmtime_r(&t, &myTm); 3504e438cbSEd Tanous 3604e438cbSEd Tanous size_t sz = 3704e438cbSEd Tanous strftime(date.data(), date.size(), "%Y-%m-%d %H:%M:%S", &myTm); 3804e438cbSEd Tanous date.resize(sz); 3904e438cbSEd Tanous return date; 4004e438cbSEd Tanous } 4104e438cbSEd Tanous 4204e438cbSEd Tanous public: 4304e438cbSEd Tanous Logger([[maybe_unused]] const std::string& prefix, 4404e438cbSEd Tanous [[maybe_unused]] const std::string& filename, 4504e438cbSEd Tanous [[maybe_unused]] const size_t line, LogLevel levelIn) : 4604e438cbSEd Tanous level(levelIn) 4704e438cbSEd Tanous { 4804e438cbSEd Tanous #ifdef BMCWEB_ENABLE_LOGGING 4904e438cbSEd Tanous stringstream << "(" << timestamp() << ") [" << prefix << " " 5004e438cbSEd Tanous << std::filesystem::path(filename).filename() << ":" 5104e438cbSEd Tanous << line << "] "; 5204e438cbSEd Tanous #endif 5304e438cbSEd Tanous } 5404e438cbSEd Tanous ~Logger() 5504e438cbSEd Tanous { 5604e438cbSEd Tanous if (level >= getCurrentLogLevel()) 5704e438cbSEd Tanous { 5804e438cbSEd Tanous #ifdef BMCWEB_ENABLE_LOGGING 5904e438cbSEd Tanous stringstream << std::endl; 6004e438cbSEd Tanous std::cerr << stringstream.str(); 6104e438cbSEd Tanous #endif 6204e438cbSEd Tanous } 6304e438cbSEd Tanous } 6404e438cbSEd Tanous 65ecd6a3a2SEd Tanous Logger(const Logger&) = delete; 66ecd6a3a2SEd Tanous Logger(Logger&&) = delete; 67ecd6a3a2SEd Tanous Logger& operator=(const Logger&) = delete; 68ecd6a3a2SEd Tanous Logger& operator=(const Logger&&) = delete; 69ecd6a3a2SEd Tanous 7004e438cbSEd Tanous // 7104e438cbSEd Tanous template <typename T> 7204e438cbSEd Tanous Logger& operator<<([[maybe_unused]] T const& value) 7304e438cbSEd Tanous { 7404e438cbSEd Tanous if (level >= getCurrentLogLevel()) 7504e438cbSEd Tanous { 7604e438cbSEd Tanous #ifdef BMCWEB_ENABLE_LOGGING 7704e438cbSEd Tanous stringstream << value; 7804e438cbSEd Tanous #endif 7904e438cbSEd Tanous } 8004e438cbSEd Tanous return *this; 8104e438cbSEd Tanous } 8204e438cbSEd Tanous 8304e438cbSEd Tanous // 8404e438cbSEd Tanous static void setLogLevel(LogLevel level) 8504e438cbSEd Tanous { 8604e438cbSEd Tanous getLogLevelRef() = level; 8704e438cbSEd Tanous } 8804e438cbSEd Tanous 8904e438cbSEd Tanous static LogLevel getCurrentLogLevel() 9004e438cbSEd Tanous { 9104e438cbSEd Tanous return getLogLevelRef(); 9204e438cbSEd Tanous } 9304e438cbSEd Tanous 9404e438cbSEd Tanous private: 9504e438cbSEd Tanous // 9604e438cbSEd Tanous static LogLevel& getLogLevelRef() 9704e438cbSEd Tanous { 9804e438cbSEd Tanous static auto currentLevel = static_cast<LogLevel>(1); 9904e438cbSEd Tanous return currentLevel; 10004e438cbSEd Tanous } 10104e438cbSEd Tanous 10204e438cbSEd Tanous // 10304e438cbSEd Tanous std::ostringstream stringstream; 10404e438cbSEd Tanous LogLevel level; 10504e438cbSEd Tanous }; 10604e438cbSEd Tanous } // namespace crow 10704e438cbSEd Tanous 108*600d2394SEd Tanous // The logging functions currently use macros. Now that we have c++20, ideally 109*600d2394SEd Tanous // they'd use source_location with fixed functions, but for the moment, disable 110*600d2394SEd Tanous // the check. 111*600d2394SEd Tanous 112*600d2394SEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 11304e438cbSEd Tanous #define BMCWEB_LOG_CRITICAL \ 11404e438cbSEd Tanous if (crow::Logger::getCurrentLogLevel() <= crow::LogLevel::Critical) \ 11504e438cbSEd Tanous crow::Logger("CRITICAL", __FILE__, __LINE__, crow::LogLevel::Critical) 116*600d2394SEd Tanous 117*600d2394SEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 11804e438cbSEd Tanous #define BMCWEB_LOG_ERROR \ 11904e438cbSEd Tanous if (crow::Logger::getCurrentLogLevel() <= crow::LogLevel::Error) \ 12004e438cbSEd Tanous crow::Logger("ERROR", __FILE__, __LINE__, crow::LogLevel::Error) 121*600d2394SEd Tanous 122*600d2394SEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 12304e438cbSEd Tanous #define BMCWEB_LOG_WARNING \ 12404e438cbSEd Tanous if (crow::Logger::getCurrentLogLevel() <= crow::LogLevel::Warning) \ 12504e438cbSEd Tanous crow::Logger("WARNING", __FILE__, __LINE__, crow::LogLevel::Warning) 126*600d2394SEd Tanous 127*600d2394SEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 12804e438cbSEd Tanous #define BMCWEB_LOG_INFO \ 12904e438cbSEd Tanous if (crow::Logger::getCurrentLogLevel() <= crow::LogLevel::Info) \ 13004e438cbSEd Tanous crow::Logger("INFO", __FILE__, __LINE__, crow::LogLevel::Info) 131*600d2394SEd Tanous 132*600d2394SEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 13304e438cbSEd Tanous #define BMCWEB_LOG_DEBUG \ 13404e438cbSEd Tanous if (crow::Logger::getCurrentLogLevel() <= crow::LogLevel::Debug) \ 13504e438cbSEd Tanous crow::Logger("DEBUG", __FILE__, __LINE__, crow::LogLevel::Debug) 136