xref: /openbmc/bmcweb/http/logging.hpp (revision f263e09c)
1 #pragma once
2 
3 #include "bmcweb_config.h"
4 
5 #include <algorithm>
6 #include <array>
7 #include <cstdio>
8 #include <cstdlib>
9 #include <ctime>
10 #include <filesystem>
11 #include <iostream>
12 #include <sstream>
13 #include <string>
14 #include <string_view>
15 
16 namespace crow
17 {
18 enum class LogLevel
19 {
20     Disabled = 0,
21     Debug,
22     Info,
23     Warning,
24     Error,
25     Critical,
26 };
27 
28 // Mapping of the external loglvl name to internal loglvl
29 constexpr std::array<std::pair<std::string_view, crow::LogLevel>, 7>
30     mapLogLevelFromName{{{"disabled", crow::LogLevel::Disabled},
31                          {"enabled", crow::LogLevel::Debug},
32                          {"debug", crow::LogLevel::Debug},
33                          {"info", crow::LogLevel::Info},
34                          {"warning", crow::LogLevel::Warning},
35                          {"error", crow::LogLevel::Error},
36                          {"critical", crow::LogLevel::Critical}}};
37 
38 constexpr crow::LogLevel getLogLevelFromName(std::string_view name)
39 {
40     const auto* iter =
41         std::find_if(begin(mapLogLevelFromName), end(mapLogLevelFromName),
42                      [&name](const auto& v) { return v.first == name; });
43     if (iter != end(mapLogLevelFromName))
44     {
45         return iter->second;
46     }
47     return crow::LogLevel::Disabled;
48 }
49 
50 // configured bmcweb LogLevel
51 constexpr crow::LogLevel bmcwebCurrentLoggingLevel =
52     getLogLevelFromName(bmcwebLoggingLevel);
53 
54 class Logger
55 {
56   private:
57     //
58     static std::string timestamp()
59     {
60         std::string date;
61         date.resize(32, '\0');
62         time_t t = time(nullptr);
63 
64         tm myTm{};
65 
66         gmtime_r(&t, &myTm);
67 
68         size_t sz = strftime(date.data(), date.size(), "%Y-%m-%d %H:%M:%S",
69                              &myTm);
70         date.resize(sz);
71         return date;
72     }
73 
74   public:
75     Logger([[maybe_unused]] const std::string& prefix,
76            [[maybe_unused]] const std::string& filename,
77            [[maybe_unused]] const size_t line)
78     {
79         stringstream << "(" << timestamp() << ") [" << prefix << " "
80                      << std::filesystem::path(filename).filename() << ":"
81                      << line << "] ";
82     }
83     ~Logger()
84     {
85         stringstream << std::endl;
86         std::cerr << stringstream.str();
87     }
88 
89     Logger(const Logger&) = delete;
90     Logger(Logger&&) = delete;
91     Logger& operator=(const Logger&) = delete;
92     Logger& operator=(const Logger&&) = delete;
93 
94     //
95     template <typename T>
96     Logger& operator<<([[maybe_unused]] const T& value)
97     {
98         // Somewhere in the code we're implicitly casting an array to a
99         // pointer in logging code. It's non-trivial to find,
100         // so disable the check here for now
101         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
102         stringstream << value;
103         return *this;
104     }
105 
106     constexpr static LogLevel getCurrentLogLevel()
107     {
108         return bmcwebCurrentLoggingLevel;
109     }
110 
111     constexpr static bool isLoggingEnabled()
112     {
113         return getCurrentLogLevel() >= crow::LogLevel::Debug;
114     }
115 
116     constexpr static bool checkLoggingLevel(const LogLevel level)
117     {
118         return isLoggingEnabled() && (getCurrentLogLevel() <= level);
119     }
120 
121   private:
122     //
123     std::ostringstream stringstream;
124 };
125 } // namespace crow
126 
127 // Disable clang-tidy warnings about unused macros.
128 // NOLINTBEGIN(cppcoreguidelines-macro-usage, clang-diagnostic-unused-macros)
129 
130 // The logging functions currently use macros.  Now that we have c++20, ideally
131 // they'd use source_location with fixed functions, but for the moment, disable
132 // the check.
133 #define BMCWEB_LOG_CRITICAL                                                    \
134     if constexpr (crow::Logger::checkLoggingLevel(crow::LogLevel::Critical))   \
135     crow::Logger("CRITICAL", __FILE__, __LINE__)
136 
137 #define BMCWEB_LOG_ERROR                                                       \
138     if constexpr (crow::Logger::checkLoggingLevel(crow::LogLevel::Error))      \
139     crow::Logger("ERROR", __FILE__, __LINE__)
140 
141 #define BMCWEB_LOG_WARNING                                                     \
142     if constexpr (crow::Logger::checkLoggingLevel(crow::LogLevel::Warning))    \
143     crow::Logger("WARNING", __FILE__, __LINE__)
144 
145 #define BMCWEB_LOG_INFO                                                        \
146     if constexpr (crow::Logger::checkLoggingLevel(crow::LogLevel::Info))       \
147     crow::Logger("INFO", __FILE__, __LINE__)
148 
149 #define BMCWEB_LOG_DEBUG                                                       \
150     if constexpr (crow::Logger::checkLoggingLevel(crow::LogLevel::Debug))      \
151     crow::Logger("DEBUG", __FILE__, __LINE__)
152 
153 // NOLINTEND(cppcoreguidelines-macro-usage, clang-diagnostic-unused-macros)
154