xref: /openbmc/bmcweb/http/logging.hpp (revision d9e89dfd)
1 #pragma once
2 
3 #include "bmcweb_config.h"
4 
5 #include <boost/system/error_code.hpp>
6 #include <boost/url/pct_string_view.hpp>
7 #include <boost/url/string_view.hpp>
8 #include <boost/url/url.hpp>
9 #include <nlohmann/json.hpp>
10 
11 #include <bit>
12 #include <format>
13 #include <iostream>
14 #include <source_location>
15 #include <string_view>
16 #include <system_error>
17 
18 // Clang-tidy would rather these be static, but using static causes the template
19 // specialization to not function.  Ignore the warning.
20 // NOLINTBEGIN(readability-convert-member-functions-to-static, cert-dcl58-cpp)
21 template <>
22 struct std::formatter<boost::system::error_code>
23 {
24     constexpr auto parse(std::format_parse_context& ctx)
25     {
26         return ctx.begin();
27     }
28 
29     auto format(const boost::system::error_code& ec, auto& ctx) const
30     {
31         return std::format_to(ctx.out(), "{}", ec.what());
32     }
33 };
34 
35 template <>
36 struct std::formatter<boost::urls::pct_string_view>
37 {
38     constexpr auto parse(std::format_parse_context& ctx)
39     {
40         return ctx.begin();
41     }
42     auto format(const boost::urls::pct_string_view& msg, auto& ctx) const
43     {
44         return std::format_to(ctx.out(), "{}",
45                               std::string_view(msg.data(), msg.size()));
46     }
47 };
48 
49 template <>
50 struct std::formatter<boost::urls::url_view>
51 {
52     constexpr auto parse(std::format_parse_context& ctx)
53     {
54         return ctx.begin();
55     }
56     auto format(const boost::urls::url& msg, auto& ctx) const
57     {
58         return std::format_to(ctx.out(), "{}", std::string_view(msg.buffer()));
59     }
60 };
61 
62 template <>
63 struct std::formatter<boost::urls::url>
64 {
65     constexpr auto parse(std::format_parse_context& ctx)
66     {
67         return ctx.begin();
68     }
69     auto format(const boost::urls::url& msg, auto& ctx) const
70     {
71         return std::format_to(ctx.out(), "{}", std::string_view(msg.buffer()));
72     }
73 };
74 
75 template <>
76 struct std::formatter<boost::core::string_view>
77 {
78     constexpr auto parse(std::format_parse_context& ctx)
79     {
80         return ctx.begin();
81     }
82     auto format(const boost::core::string_view& msg, auto& ctx) const
83     {
84         return std::format_to(ctx.out(), "{}", std::string_view(msg));
85     }
86 };
87 
88 template <>
89 struct std::formatter<void*>
90 {
91     constexpr auto parse(std::format_parse_context& ctx)
92     {
93         return ctx.begin();
94     }
95     auto format(const void*& ptr, auto& ctx) const
96     {
97         return std::format_to(ctx.out(), "{}",
98                               std::to_string(std::bit_cast<size_t>(ptr)));
99     }
100 };
101 
102 template <>
103 struct std::formatter<nlohmann::json::json_pointer>
104 {
105     constexpr auto parse(std::format_parse_context& ctx)
106     {
107         return ctx.begin();
108     }
109     auto format(const nlohmann::json::json_pointer& ptr, auto& ctx) const
110     {
111         return std::format_to(ctx.out(), "{}", ptr.to_string());
112     }
113 };
114 
115 template <>
116 struct std::formatter<nlohmann::json>
117 {
118     static constexpr auto parse(std::format_parse_context& ctx)
119     {
120         return ctx.begin();
121     }
122     auto format(const nlohmann::json& json, auto& ctx) const
123     {
124         return std::format_to(
125             ctx.out(), "{}",
126             json.dump(-1, ' ', false,
127                       nlohmann::json::error_handler_t::replace));
128     }
129 };
130 // NOLINTEND(readability-convert-member-functions-to-static, cert-dcl58-cpp)
131 
132 namespace crow
133 {
134 enum class LogLevel
135 {
136     Disabled = 0,
137     Critical,
138     Error,
139     Warning,
140     Info,
141     Debug,
142     Enabled,
143 };
144 
145 // Mapping of the external loglvl name to internal loglvl
146 constexpr std::array<std::string_view, 7> mapLogLevelFromName{
147     "DISABLED", "CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG", "ENABLED"};
148 
149 constexpr crow::LogLevel getLogLevelFromName(std::string_view name)
150 {
151     const auto* iter = std::ranges::find(mapLogLevelFromName, name);
152     if (iter != mapLogLevelFromName.end())
153     {
154         return static_cast<LogLevel>(iter - mapLogLevelFromName.begin());
155     }
156     return crow::LogLevel::Disabled;
157 }
158 
159 // configured bmcweb LogLevel
160 constexpr crow::LogLevel bmcwebCurrentLoggingLevel =
161     getLogLevelFromName(bmcwebLoggingLevel);
162 
163 template <typename T>
164 const void* logPtr(T p)
165 {
166     static_assert(std::is_pointer<T>::value,
167                   "Can't use logPtr without pointer");
168     return std::bit_cast<const void*>(p);
169 }
170 
171 template <LogLevel level, typename... Args>
172 inline void vlog(std::format_string<Args...> format, Args... args,
173                  const std::source_location& loc) noexcept
174 {
175     if constexpr (bmcwebCurrentLoggingLevel < level)
176     {
177         return;
178     }
179     constexpr size_t stringIndex = static_cast<size_t>(level);
180     static_assert(stringIndex < mapLogLevelFromName.size(),
181                   "Missing string for level");
182     constexpr std::string_view levelString = mapLogLevelFromName[stringIndex];
183     std::string_view filename = loc.file_name();
184     filename = filename.substr(filename.rfind('/') + 1);
185     std::cout << std::format("[{} {}:{}] ", levelString, filename, loc.line())
186               << std::format(format, std::forward<Args>(args)...) << '\n'
187               << std::flush;
188 }
189 } // namespace crow
190 
191 template <typename... Args>
192 struct BMCWEB_LOG_CRITICAL
193 {
194     // NOLINTNEXTLINE(google-explicit-constructor)
195     BMCWEB_LOG_CRITICAL(std::format_string<Args...> format, Args&&... args,
196                         const std::source_location& loc =
197                             std::source_location::current()) noexcept
198     {
199         crow::vlog<crow::LogLevel::Critical, Args...>(format, args..., loc);
200     }
201 };
202 
203 template <typename... Args>
204 struct BMCWEB_LOG_ERROR
205 {
206     // NOLINTNEXTLINE(google-explicit-constructor)
207     BMCWEB_LOG_ERROR(std::format_string<Args...> format, Args&&... args,
208                      const std::source_location& loc =
209                          std::source_location::current()) noexcept
210     {
211         crow::vlog<crow::LogLevel::Error, Args...>(format, args..., loc);
212     }
213 };
214 
215 template <typename... Args>
216 struct BMCWEB_LOG_WARNING
217 {
218     // NOLINTNEXTLINE(google-explicit-constructor)
219     BMCWEB_LOG_WARNING(std::format_string<Args...> format, Args&&... args,
220                        const std::source_location& loc =
221                            std::source_location::current()) noexcept
222     {
223         crow::vlog<crow::LogLevel::Warning, Args...>(format, args..., loc);
224     }
225 };
226 
227 template <typename... Args>
228 struct BMCWEB_LOG_INFO
229 {
230     // NOLINTNEXTLINE(google-explicit-constructor)
231     BMCWEB_LOG_INFO(std::format_string<Args...> format, Args&&... args,
232                     const std::source_location& loc =
233                         std::source_location::current()) noexcept
234     {
235         crow::vlog<crow::LogLevel::Info, Args...>(format, args..., loc);
236     }
237 };
238 
239 template <typename... Args>
240 struct BMCWEB_LOG_DEBUG
241 {
242     // NOLINTNEXTLINE(google-explicit-constructor)
243     BMCWEB_LOG_DEBUG(std::format_string<Args...> format, Args&&... args,
244                      const std::source_location& loc =
245                          std::source_location::current()) noexcept
246     {
247         crow::vlog<crow::LogLevel::Debug, Args...>(format, args..., loc);
248     }
249 };
250 
251 template <typename... Args>
252 BMCWEB_LOG_CRITICAL(std::format_string<Args...>, Args&&...)
253     -> BMCWEB_LOG_CRITICAL<Args...>;
254 
255 template <typename... Args>
256 BMCWEB_LOG_ERROR(std::format_string<Args...>, Args&&...)
257     -> BMCWEB_LOG_ERROR<Args...>;
258 
259 template <typename... Args>
260 BMCWEB_LOG_WARNING(std::format_string<Args...>, Args&&...)
261     -> BMCWEB_LOG_WARNING<Args...>;
262 
263 template <typename... Args>
264 BMCWEB_LOG_INFO(std::format_string<Args...>, Args&&...)
265     -> BMCWEB_LOG_INFO<Args...>;
266 
267 template <typename... Args>
268 BMCWEB_LOG_DEBUG(std::format_string<Args...>, Args&&...)
269     -> BMCWEB_LOG_DEBUG<Args...>;
270