xref: /openbmc/bmcweb/http/logging.hpp (revision 600d2394cfd3a3a09b126f0570cc66561fd02d31)
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