xref: /openbmc/bmcweb/http/logging.hpp (revision 9b6ffca5c1cafcc5406cf835390153a370dec4f6)
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
77*9b6ffca5SEd Tanous             // Somewhere in the code we're implicitly casting an array to a
78*9b6ffca5SEd Tanous             // pointer in logging code.  It's non-trivial to find, so disable
79*9b6ffca5SEd Tanous             // the check here for now
80*9b6ffca5SEd Tanous             // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
8104e438cbSEd Tanous             stringstream << value;
8204e438cbSEd Tanous #endif
8304e438cbSEd Tanous         }
8404e438cbSEd Tanous         return *this;
8504e438cbSEd Tanous     }
8604e438cbSEd Tanous 
8704e438cbSEd Tanous     //
8804e438cbSEd Tanous     static void setLogLevel(LogLevel level)
8904e438cbSEd Tanous     {
9004e438cbSEd Tanous         getLogLevelRef() = level;
9104e438cbSEd Tanous     }
9204e438cbSEd Tanous 
9304e438cbSEd Tanous     static LogLevel getCurrentLogLevel()
9404e438cbSEd Tanous     {
9504e438cbSEd Tanous         return getLogLevelRef();
9604e438cbSEd Tanous     }
9704e438cbSEd Tanous 
9804e438cbSEd Tanous   private:
9904e438cbSEd Tanous     //
10004e438cbSEd Tanous     static LogLevel& getLogLevelRef()
10104e438cbSEd Tanous     {
10204e438cbSEd Tanous         static auto currentLevel = static_cast<LogLevel>(1);
10304e438cbSEd Tanous         return currentLevel;
10404e438cbSEd Tanous     }
10504e438cbSEd Tanous 
10604e438cbSEd Tanous     //
10704e438cbSEd Tanous     std::ostringstream stringstream;
10804e438cbSEd Tanous     LogLevel level;
10904e438cbSEd Tanous };
11004e438cbSEd Tanous } // namespace crow
11104e438cbSEd Tanous 
112600d2394SEd Tanous // The logging functions currently use macros.  Now that we have c++20, ideally
113600d2394SEd Tanous // they'd use source_location with fixed functions, but for the moment, disable
114600d2394SEd Tanous // the check.
115600d2394SEd Tanous 
116600d2394SEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
11704e438cbSEd Tanous #define BMCWEB_LOG_CRITICAL                                                    \
11804e438cbSEd Tanous     if (crow::Logger::getCurrentLogLevel() <= crow::LogLevel::Critical)        \
11904e438cbSEd Tanous     crow::Logger("CRITICAL", __FILE__, __LINE__, crow::LogLevel::Critical)
120600d2394SEd Tanous 
121600d2394SEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
12204e438cbSEd Tanous #define BMCWEB_LOG_ERROR                                                       \
12304e438cbSEd Tanous     if (crow::Logger::getCurrentLogLevel() <= crow::LogLevel::Error)           \
12404e438cbSEd Tanous     crow::Logger("ERROR", __FILE__, __LINE__, crow::LogLevel::Error)
125600d2394SEd Tanous 
126600d2394SEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
12704e438cbSEd Tanous #define BMCWEB_LOG_WARNING                                                     \
12804e438cbSEd Tanous     if (crow::Logger::getCurrentLogLevel() <= crow::LogLevel::Warning)         \
12904e438cbSEd Tanous     crow::Logger("WARNING", __FILE__, __LINE__, crow::LogLevel::Warning)
130600d2394SEd Tanous 
131600d2394SEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
13204e438cbSEd Tanous #define BMCWEB_LOG_INFO                                                        \
13304e438cbSEd Tanous     if (crow::Logger::getCurrentLogLevel() <= crow::LogLevel::Info)            \
13404e438cbSEd Tanous     crow::Logger("INFO", __FILE__, __LINE__, crow::LogLevel::Info)
135600d2394SEd Tanous 
136600d2394SEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
13704e438cbSEd Tanous #define BMCWEB_LOG_DEBUG                                                       \
13804e438cbSEd Tanous     if (crow::Logger::getCurrentLogLevel() <= crow::LogLevel::Debug)           \
13904e438cbSEd Tanous     crow::Logger("DEBUG", __FILE__, __LINE__, crow::LogLevel::Debug)
140