xref: /openbmc/bmcweb/http/logging.hpp (revision bd79bce8c3f1deb1fb2773868b9ece25233cf27b)
1 #pragma once
2 
3 #include "bmcweb_config.h"
4 
5 #include <bit>
6 #include <format>
7 #include <iostream>
8 #include <source_location>
9 #include <string_view>
10 #include <system_error>
11 
12 // NOLINTBEGIN(readability-convert-member-functions-to-static, cert-dcl58-cpp)
13 template <>
14 struct std::formatter<void*>
15 {
16     constexpr auto parse(std::format_parse_context& ctx)
17     {
18         return ctx.begin();
19     }
20     auto format(const void*& ptr, auto& ctx) const
21     {
22         return std::format_to(ctx.out(), "{}",
23                               std::to_string(std::bit_cast<size_t>(ptr)));
24     }
25 };
26 // NOLINTEND(readability-convert-member-functions-to-static, cert-dcl58-cpp)
27 
28 namespace crow
29 {
30 enum class LogLevel
31 {
32     Disabled = 0,
33     Critical,
34     Error,
35     Warning,
36     Info,
37     Debug,
38     Enabled,
39 };
40 
41 // Mapping of the external loglvl name to internal loglvl
42 constexpr std::array<std::string_view, 7> mapLogLevelFromName{
43     "DISABLED", "CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG", "ENABLED"};
44 
45 constexpr crow::LogLevel getLogLevelFromName(std::string_view name)
46 {
47     const auto* iter = std::ranges::find(mapLogLevelFromName, name);
48     if (iter != mapLogLevelFromName.end())
49     {
50         return static_cast<LogLevel>(iter - mapLogLevelFromName.begin());
51     }
52     return crow::LogLevel::Disabled;
53 }
54 
55 // configured bmcweb LogLevel
56 constexpr crow::LogLevel bmcwebCurrentLoggingLevel =
57     getLogLevelFromName(BMCWEB_LOGGING_LEVEL);
58 
59 template <typename T>
60 const void* logPtr(T p)
61 {
62     static_assert(std::is_pointer<T>::value,
63                   "Can't use logPtr without pointer");
64     return std::bit_cast<const void*>(p);
65 }
66 
67 template <LogLevel level, typename... Args>
68 inline void vlog(std::format_string<Args...>&& format, Args&&... args,
69                  const std::source_location& loc) noexcept
70 {
71     if constexpr (bmcwebCurrentLoggingLevel < level)
72     {
73         return;
74     }
75     constexpr size_t stringIndex = static_cast<size_t>(level);
76     static_assert(stringIndex < mapLogLevelFromName.size(),
77                   "Missing string for level");
78     constexpr std::string_view levelString = mapLogLevelFromName[stringIndex];
79     std::string_view filename = loc.file_name();
80     filename = filename.substr(filename.rfind('/'));
81     if (!filename.empty())
82     {
83         filename.remove_prefix(1);
84     }
85     std::string logLocation;
86     try
87     {
88         // TODO, multiple static analysis tools flag that this could potentially
89         // throw Based on the documentation, it shouldn't throw, so long as none
90         // of the formatters throw, so unclear at this point why this try/catch
91         // is required, but add it to silence the static analysis tools.
92         logLocation =
93             std::format("[{} {}:{}] ", levelString, filename, loc.line());
94         logLocation +=
95             std::format(std::move(format), std::forward<Args>(args)...);
96     }
97     catch (const std::format_error& /*error*/)
98     {
99         logLocation += "Failed to format";
100         // Nothing more we can do here if logging is broken.
101     }
102     logLocation += '\n';
103     // Intentionally ignore error return.
104     fwrite(logLocation.data(), sizeof(std::string::value_type),
105            logLocation.size(), stdout);
106     fflush(stdout);
107 }
108 } // namespace crow
109 
110 template <typename... Args>
111 struct BMCWEB_LOG_CRITICAL
112 {
113     // NOLINTNEXTLINE(google-explicit-constructor)
114     BMCWEB_LOG_CRITICAL(std::format_string<Args...> format, Args&&... args,
115                         const std::source_location& loc =
116                             std::source_location::current()) noexcept
117     {
118         crow::vlog<crow::LogLevel::Critical, Args...>(
119             std::move(format), std::forward<Args>(args)..., loc);
120     }
121 };
122 
123 template <typename... Args>
124 struct BMCWEB_LOG_ERROR
125 {
126     // NOLINTNEXTLINE(google-explicit-constructor)
127     BMCWEB_LOG_ERROR(std::format_string<Args...> format, Args&&... args,
128                      const std::source_location& loc =
129                          std::source_location::current()) noexcept
130     {
131         crow::vlog<crow::LogLevel::Error, Args...>(
132             std::move(format), std::forward<Args>(args)..., loc);
133     }
134 };
135 
136 template <typename... Args>
137 struct BMCWEB_LOG_WARNING
138 {
139     // NOLINTNEXTLINE(google-explicit-constructor)
140     BMCWEB_LOG_WARNING(std::format_string<Args...> format, Args&&... args,
141                        const std::source_location& loc =
142                            std::source_location::current()) noexcept
143     {
144         crow::vlog<crow::LogLevel::Warning, Args...>(
145             std::move(format), std::forward<Args>(args)..., loc);
146     }
147 };
148 
149 template <typename... Args>
150 struct BMCWEB_LOG_INFO
151 {
152     // NOLINTNEXTLINE(google-explicit-constructor)
153     BMCWEB_LOG_INFO(std::format_string<Args...> format, Args&&... args,
154                     const std::source_location& loc =
155                         std::source_location::current()) noexcept
156     {
157         crow::vlog<crow::LogLevel::Info, Args...>(
158             std::move(format), std::forward<Args>(args)..., loc);
159     }
160 };
161 
162 template <typename... Args>
163 struct BMCWEB_LOG_DEBUG
164 {
165     // NOLINTNEXTLINE(google-explicit-constructor)
166     BMCWEB_LOG_DEBUG(std::format_string<Args...> format, Args&&... args,
167                      const std::source_location& loc =
168                          std::source_location::current()) noexcept
169     {
170         crow::vlog<crow::LogLevel::Debug, Args...>(
171             std::move(format), std::forward<Args>(args)..., loc);
172     }
173 };
174 
175 template <typename... Args>
176 BMCWEB_LOG_CRITICAL(std::format_string<Args...>,
177                     Args&&...) -> BMCWEB_LOG_CRITICAL<Args...>;
178 
179 template <typename... Args>
180 BMCWEB_LOG_ERROR(std::format_string<Args...>,
181                  Args&&...) -> BMCWEB_LOG_ERROR<Args...>;
182 
183 template <typename... Args>
184 BMCWEB_LOG_WARNING(std::format_string<Args...>,
185                    Args&&...) -> BMCWEB_LOG_WARNING<Args...>;
186 
187 template <typename... Args>
188 BMCWEB_LOG_INFO(std::format_string<Args...>,
189                 Args&&...) -> BMCWEB_LOG_INFO<Args...>;
190 
191 template <typename... Args>
192 BMCWEB_LOG_DEBUG(std::format_string<Args...>,
193                  Args&&...) -> BMCWEB_LOG_DEBUG<Args...>;
194