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