xref: /openbmc/bmcweb/http/logging.hpp (revision 6ea9076048028a4adfdbdd2606698bffc81203d3)
104e438cbSEd Tanous #pragma once
204e438cbSEd Tanous 
3662aa6e3SMyung Bae #include "bmcweb_config.h"
4662aa6e3SMyung Bae 
562598e31SEd Tanous #include <boost/system/error_code.hpp>
662598e31SEd Tanous #include <boost/url/pct_string_view.hpp>
762598e31SEd Tanous #include <boost/url/string_view.hpp>
862598e31SEd Tanous #include <boost/url/url.hpp>
962598e31SEd Tanous #include <nlohmann/json.hpp>
1062598e31SEd Tanous 
1162598e31SEd Tanous #include <bit>
1262598e31SEd Tanous #include <format>
1304e438cbSEd Tanous #include <iostream>
1462598e31SEd Tanous #include <source_location>
15662aa6e3SMyung Bae #include <string_view>
1662598e31SEd Tanous #include <system_error>
1762598e31SEd Tanous 
1862598e31SEd Tanous // Clang-tidy would rather these be static, but using static causes the template
1962598e31SEd Tanous // specialization to not function.  Ignore the warning.
2062598e31SEd Tanous // NOLINTBEGIN(readability-convert-member-functions-to-static, cert-dcl58-cpp)
2162598e31SEd Tanous template <>
2262598e31SEd Tanous struct std::formatter<boost::system::error_code>
2362598e31SEd Tanous {
2462598e31SEd Tanous     constexpr auto parse(std::format_parse_context& ctx)
2562598e31SEd Tanous     {
2662598e31SEd Tanous         return ctx.begin();
2762598e31SEd Tanous     }
2862598e31SEd Tanous 
2962598e31SEd Tanous     auto format(const boost::system::error_code& ec, auto& ctx) const
3062598e31SEd Tanous     {
3162598e31SEd Tanous         return std::format_to(ctx.out(), "{}", ec.what());
3262598e31SEd Tanous     }
3362598e31SEd Tanous };
3462598e31SEd Tanous 
3562598e31SEd Tanous template <>
3662598e31SEd Tanous struct std::formatter<boost::urls::pct_string_view>
3762598e31SEd Tanous {
3862598e31SEd Tanous     constexpr auto parse(std::format_parse_context& ctx)
3962598e31SEd Tanous     {
4062598e31SEd Tanous         return ctx.begin();
4162598e31SEd Tanous     }
4262598e31SEd Tanous     auto format(const boost::urls::pct_string_view& msg, auto& ctx) const
4362598e31SEd Tanous     {
4462598e31SEd Tanous         return std::format_to(ctx.out(), "{}",
4562598e31SEd Tanous                               std::string_view(msg.data(), msg.size()));
4662598e31SEd Tanous     }
4762598e31SEd Tanous };
4862598e31SEd Tanous 
4962598e31SEd Tanous template <>
50a716aa74SEd Tanous struct std::formatter<boost::urls::url_view>
51a716aa74SEd Tanous {
52a716aa74SEd Tanous     constexpr auto parse(std::format_parse_context& ctx)
53a716aa74SEd Tanous     {
54a716aa74SEd Tanous         return ctx.begin();
55a716aa74SEd Tanous     }
56a716aa74SEd Tanous     auto format(const boost::urls::url& msg, auto& ctx) const
57a716aa74SEd Tanous     {
58a716aa74SEd Tanous         return std::format_to(ctx.out(), "{}", std::string_view(msg.buffer()));
59a716aa74SEd Tanous     }
60a716aa74SEd Tanous };
61a716aa74SEd Tanous 
62a716aa74SEd Tanous template <>
6362598e31SEd Tanous struct std::formatter<boost::urls::url>
6462598e31SEd Tanous {
6562598e31SEd Tanous     constexpr auto parse(std::format_parse_context& ctx)
6662598e31SEd Tanous     {
6762598e31SEd Tanous         return ctx.begin();
6862598e31SEd Tanous     }
6962598e31SEd Tanous     auto format(const boost::urls::url& msg, auto& ctx) const
7062598e31SEd Tanous     {
7162598e31SEd Tanous         return std::format_to(ctx.out(), "{}", std::string_view(msg.buffer()));
7262598e31SEd Tanous     }
7362598e31SEd Tanous };
7462598e31SEd Tanous 
7562598e31SEd Tanous template <>
7662598e31SEd Tanous struct std::formatter<boost::core::string_view>
7762598e31SEd Tanous {
7862598e31SEd Tanous     constexpr auto parse(std::format_parse_context& ctx)
7962598e31SEd Tanous     {
8062598e31SEd Tanous         return ctx.begin();
8162598e31SEd Tanous     }
8262598e31SEd Tanous     auto format(const boost::core::string_view& msg, auto& ctx) const
8362598e31SEd Tanous     {
8462598e31SEd Tanous         return std::format_to(ctx.out(), "{}", std::string_view(msg));
8562598e31SEd Tanous     }
8662598e31SEd Tanous };
8762598e31SEd Tanous 
8862598e31SEd Tanous template <>
8962598e31SEd Tanous struct std::formatter<void*>
9062598e31SEd Tanous {
9162598e31SEd Tanous     constexpr auto parse(std::format_parse_context& ctx)
9262598e31SEd Tanous     {
9362598e31SEd Tanous         return ctx.begin();
9462598e31SEd Tanous     }
9562598e31SEd Tanous     auto format(const void*& ptr, auto& ctx) const
9662598e31SEd Tanous     {
9762598e31SEd Tanous         return std::format_to(ctx.out(), "{}",
9862598e31SEd Tanous                               std::to_string(std::bit_cast<size_t>(ptr)));
9962598e31SEd Tanous     }
10062598e31SEd Tanous };
10162598e31SEd Tanous 
10262598e31SEd Tanous template <>
10362598e31SEd Tanous struct std::formatter<nlohmann::json::json_pointer>
10462598e31SEd Tanous {
10562598e31SEd Tanous     constexpr auto parse(std::format_parse_context& ctx)
10662598e31SEd Tanous     {
10762598e31SEd Tanous         return ctx.begin();
10862598e31SEd Tanous     }
10962598e31SEd Tanous     auto format(const nlohmann::json::json_pointer& ptr, auto& ctx) const
11062598e31SEd Tanous     {
11162598e31SEd Tanous         return std::format_to(ctx.out(), "{}", ptr.to_string());
11262598e31SEd Tanous     }
11362598e31SEd Tanous };
11462598e31SEd Tanous 
11562598e31SEd Tanous template <>
11662598e31SEd Tanous struct std::formatter<nlohmann::json>
11762598e31SEd Tanous {
11862598e31SEd Tanous     static constexpr auto parse(std::format_parse_context& ctx)
11962598e31SEd Tanous     {
12062598e31SEd Tanous         return ctx.begin();
12162598e31SEd Tanous     }
12262598e31SEd Tanous     auto format(const nlohmann::json& json, auto& ctx) const
12362598e31SEd Tanous     {
12462598e31SEd Tanous         return std::format_to(
12562598e31SEd Tanous             ctx.out(), "{}",
12662598e31SEd Tanous             json.dump(-1, ' ', false,
12762598e31SEd Tanous                       nlohmann::json::error_handler_t::replace));
12862598e31SEd Tanous     }
12962598e31SEd Tanous };
13062598e31SEd Tanous // NOLINTEND(readability-convert-member-functions-to-static, cert-dcl58-cpp)
13104e438cbSEd Tanous 
13204e438cbSEd Tanous namespace crow
13304e438cbSEd Tanous {
13404e438cbSEd Tanous enum class LogLevel
13504e438cbSEd Tanous {
136662aa6e3SMyung Bae     Disabled = 0,
13704e438cbSEd Tanous     Critical,
138e7245fe8SEd Tanous     Error,
139e7245fe8SEd Tanous     Warning,
140e7245fe8SEd Tanous     Info,
141e7245fe8SEd Tanous     Debug,
142e7245fe8SEd Tanous     Enabled,
14304e438cbSEd Tanous };
14404e438cbSEd Tanous 
145662aa6e3SMyung Bae // Mapping of the external loglvl name to internal loglvl
146e7245fe8SEd Tanous constexpr std::array<std::string_view, 7> mapLogLevelFromName{
147e7245fe8SEd Tanous     "DISABLED", "CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG", "ENABLED"};
148662aa6e3SMyung Bae 
149662aa6e3SMyung Bae constexpr crow::LogLevel getLogLevelFromName(std::string_view name)
150662aa6e3SMyung Bae {
151e7245fe8SEd Tanous     const auto* iter = std::ranges::find(mapLogLevelFromName, name);
152e7245fe8SEd Tanous     if (iter != mapLogLevelFromName.end())
153662aa6e3SMyung Bae     {
154e7245fe8SEd Tanous         return static_cast<LogLevel>(iter - mapLogLevelFromName.begin());
155662aa6e3SMyung Bae     }
156662aa6e3SMyung Bae     return crow::LogLevel::Disabled;
157662aa6e3SMyung Bae }
158662aa6e3SMyung Bae 
159662aa6e3SMyung Bae // configured bmcweb LogLevel
160662aa6e3SMyung Bae constexpr crow::LogLevel bmcwebCurrentLoggingLevel =
161662aa6e3SMyung Bae     getLogLevelFromName(bmcwebLoggingLevel);
162662aa6e3SMyung Bae 
16362598e31SEd Tanous template <typename T>
16462598e31SEd Tanous const void* logPtr(T p)
16562598e31SEd Tanous {
16662598e31SEd Tanous     static_assert(std::is_pointer<T>::value,
16762598e31SEd Tanous                   "Can't use logPtr without pointer");
16862598e31SEd Tanous     return std::bit_cast<const void*>(p);
16962598e31SEd Tanous }
17062598e31SEd Tanous 
171*6ea90760SEd Tanous template <LogLevel level, typename... Args>
172*6ea90760SEd Tanous inline void vlog(std::format_string<Args...> format, Args... args,
173*6ea90760SEd Tanous                  const std::source_location& loc) noexcept
17462598e31SEd Tanous {
175d518a9beSMyung Bae     if constexpr (bmcwebCurrentLoggingLevel < level)
17662598e31SEd Tanous     {
17762598e31SEd Tanous         return;
17862598e31SEd Tanous     }
17962598e31SEd Tanous     constexpr size_t stringIndex = static_cast<size_t>(level);
18062598e31SEd Tanous     static_assert(stringIndex < mapLogLevelFromName.size(),
18162598e31SEd Tanous                   "Missing string for level");
182e7245fe8SEd Tanous     constexpr std::string_view levelString = mapLogLevelFromName[stringIndex];
183*6ea90760SEd Tanous     std::string_view filename = loc.file_name();
184e7245fe8SEd Tanous     filename = filename.substr(filename.rfind('/') + 1);
185*6ea90760SEd Tanous     std::cout << std::format("[{} {}:{}] ", levelString, filename, loc.line())
186*6ea90760SEd Tanous               << std::format(format, std::forward<Args>(args)...) << '\n'
187dce4d230SEd Tanous               << std::flush;
18862598e31SEd Tanous }
18904e438cbSEd Tanous } // namespace crow
19004e438cbSEd Tanous 
19162598e31SEd Tanous template <typename... Args>
192*6ea90760SEd Tanous struct BMCWEB_LOG_CRITICAL
19362598e31SEd Tanous {
194*6ea90760SEd Tanous     // NOLINTNEXTLINE(google-explicit-constructor)
195*6ea90760SEd Tanous     BMCWEB_LOG_CRITICAL(std::format_string<Args...> format, Args&&... args,
196*6ea90760SEd Tanous                         const std::source_location& loc =
197*6ea90760SEd Tanous                             std::source_location::current()) noexcept
198*6ea90760SEd Tanous     {
199*6ea90760SEd Tanous         crow::vlog<crow::LogLevel::Critical, Args...>(format, args..., loc);
20062598e31SEd Tanous     }
201*6ea90760SEd Tanous };
202eb8a3998SPatrick Williams 
20362598e31SEd Tanous template <typename... Args>
204*6ea90760SEd Tanous struct BMCWEB_LOG_ERROR
20562598e31SEd Tanous {
206*6ea90760SEd Tanous     // NOLINTNEXTLINE(google-explicit-constructor)
207*6ea90760SEd Tanous     BMCWEB_LOG_ERROR(std::format_string<Args...> format, Args&&... args,
208*6ea90760SEd Tanous                      const std::source_location& loc =
209*6ea90760SEd Tanous                          std::source_location::current()) noexcept
210*6ea90760SEd Tanous     {
211*6ea90760SEd Tanous         crow::vlog<crow::LogLevel::Error, Args...>(format, args..., loc);
21262598e31SEd Tanous     }
213*6ea90760SEd Tanous };
214600d2394SEd Tanous 
21562598e31SEd Tanous template <typename... Args>
216*6ea90760SEd Tanous struct BMCWEB_LOG_WARNING
21762598e31SEd Tanous {
218*6ea90760SEd Tanous     // NOLINTNEXTLINE(google-explicit-constructor)
219*6ea90760SEd Tanous     BMCWEB_LOG_WARNING(std::format_string<Args...> format, Args&&... args,
220*6ea90760SEd Tanous                        const std::source_location& loc =
221*6ea90760SEd Tanous                            std::source_location::current()) noexcept
222*6ea90760SEd Tanous     {
223*6ea90760SEd Tanous         crow::vlog<crow::LogLevel::Warning, Args...>(format, args..., loc);
22462598e31SEd Tanous     }
225*6ea90760SEd Tanous };
226600d2394SEd Tanous 
22762598e31SEd Tanous template <typename... Args>
228*6ea90760SEd Tanous struct BMCWEB_LOG_INFO
22962598e31SEd Tanous {
230*6ea90760SEd Tanous     // NOLINTNEXTLINE(google-explicit-constructor)
231*6ea90760SEd Tanous     BMCWEB_LOG_INFO(std::format_string<Args...> format, Args&&... args,
232*6ea90760SEd Tanous                     const std::source_location& loc =
233*6ea90760SEd Tanous                         std::source_location::current()) noexcept
234*6ea90760SEd Tanous     {
235*6ea90760SEd Tanous         crow::vlog<crow::LogLevel::Info, Args...>(format, args..., loc);
23662598e31SEd Tanous     }
237*6ea90760SEd Tanous };
238600d2394SEd Tanous 
23962598e31SEd Tanous template <typename... Args>
240*6ea90760SEd Tanous struct BMCWEB_LOG_DEBUG
24162598e31SEd Tanous {
242*6ea90760SEd Tanous     // NOLINTNEXTLINE(google-explicit-constructor)
243*6ea90760SEd Tanous     BMCWEB_LOG_DEBUG(std::format_string<Args...> format, Args&&... args,
244*6ea90760SEd Tanous                      const std::source_location& loc =
245*6ea90760SEd Tanous                          std::source_location::current()) noexcept
246*6ea90760SEd Tanous     {
247*6ea90760SEd Tanous         crow::vlog<crow::LogLevel::Debug, Args...>(format, args..., loc);
24862598e31SEd Tanous     }
249*6ea90760SEd Tanous };
250*6ea90760SEd Tanous 
251*6ea90760SEd Tanous template <typename... Args>
252*6ea90760SEd Tanous BMCWEB_LOG_CRITICAL(std::format_string<Args...>, Args&&...)
253*6ea90760SEd Tanous     -> BMCWEB_LOG_CRITICAL<Args...>;
254*6ea90760SEd Tanous 
255*6ea90760SEd Tanous template <typename... Args>
256*6ea90760SEd Tanous BMCWEB_LOG_ERROR(std::format_string<Args...>, Args&&...)
257*6ea90760SEd Tanous     -> BMCWEB_LOG_ERROR<Args...>;
258*6ea90760SEd Tanous 
259*6ea90760SEd Tanous template <typename... Args>
260*6ea90760SEd Tanous BMCWEB_LOG_WARNING(std::format_string<Args...>, Args&&...)
261*6ea90760SEd Tanous     -> BMCWEB_LOG_WARNING<Args...>;
262*6ea90760SEd Tanous 
263*6ea90760SEd Tanous template <typename... Args>
264*6ea90760SEd Tanous BMCWEB_LOG_INFO(std::format_string<Args...>, Args&&...)
265*6ea90760SEd Tanous     -> BMCWEB_LOG_INFO<Args...>;
266*6ea90760SEd Tanous 
267*6ea90760SEd Tanous template <typename... Args>
268*6ea90760SEd Tanous BMCWEB_LOG_DEBUG(std::format_string<Args...>, Args&&...)
269*6ea90760SEd Tanous     -> BMCWEB_LOG_DEBUG<Args...>;
270