104e438cbSEd Tanous #pragma once
204e438cbSEd Tanous
3662aa6e3SMyung Bae #include "bmcweb_config.h"
4662aa6e3SMyung Bae
562598e31SEd Tanous #include <bit>
662598e31SEd Tanous #include <format>
704e438cbSEd Tanous #include <iostream>
862598e31SEd Tanous #include <source_location>
9662aa6e3SMyung Bae #include <string_view>
1062598e31SEd Tanous #include <system_error>
1162598e31SEd Tanous
1262598e31SEd Tanous // NOLINTBEGIN(readability-convert-member-functions-to-static, cert-dcl58-cpp)
1362598e31SEd Tanous template <>
1462598e31SEd Tanous struct std::formatter<void*>
1562598e31SEd Tanous {
parsestd::formatter1662598e31SEd Tanous constexpr auto parse(std::format_parse_context& ctx)
1762598e31SEd Tanous {
1862598e31SEd Tanous return ctx.begin();
1962598e31SEd Tanous }
formatstd::formatter2062598e31SEd Tanous auto format(const void*& ptr, auto& ctx) const
2162598e31SEd Tanous {
2262598e31SEd Tanous return std::format_to(ctx.out(), "{}",
2362598e31SEd Tanous std::to_string(std::bit_cast<size_t>(ptr)));
2462598e31SEd Tanous }
2562598e31SEd Tanous };
2662598e31SEd Tanous // NOLINTEND(readability-convert-member-functions-to-static, cert-dcl58-cpp)
2704e438cbSEd Tanous
2804e438cbSEd Tanous namespace crow
2904e438cbSEd Tanous {
3004e438cbSEd Tanous enum class LogLevel
3104e438cbSEd Tanous {
32662aa6e3SMyung Bae Disabled = 0,
3304e438cbSEd Tanous Critical,
34e7245fe8SEd Tanous Error,
35e7245fe8SEd Tanous Warning,
36e7245fe8SEd Tanous Info,
37e7245fe8SEd Tanous Debug,
38e7245fe8SEd Tanous Enabled,
3904e438cbSEd Tanous };
4004e438cbSEd Tanous
41662aa6e3SMyung Bae // Mapping of the external loglvl name to internal loglvl
42e7245fe8SEd Tanous constexpr std::array<std::string_view, 7> mapLogLevelFromName{
43e7245fe8SEd Tanous "DISABLED", "CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG", "ENABLED"};
44662aa6e3SMyung Bae
getLogLevelFromName(std::string_view name)45662aa6e3SMyung Bae constexpr crow::LogLevel getLogLevelFromName(std::string_view name)
46662aa6e3SMyung Bae {
47e7245fe8SEd Tanous const auto* iter = std::ranges::find(mapLogLevelFromName, name);
48e7245fe8SEd Tanous if (iter != mapLogLevelFromName.end())
49662aa6e3SMyung Bae {
50e7245fe8SEd Tanous return static_cast<LogLevel>(iter - mapLogLevelFromName.begin());
51662aa6e3SMyung Bae }
52662aa6e3SMyung Bae return crow::LogLevel::Disabled;
53662aa6e3SMyung Bae }
54662aa6e3SMyung Bae
55662aa6e3SMyung Bae // configured bmcweb LogLevel
getBmcwebCurrentLoggingLevel()56bd1299b7SAushim Nagarkatti inline crow::LogLevel& getBmcwebCurrentLoggingLevel()
57bd1299b7SAushim Nagarkatti {
58bd1299b7SAushim Nagarkatti static crow::LogLevel level = getLogLevelFromName(BMCWEB_LOGGING_LEVEL);
59bd1299b7SAushim Nagarkatti return level;
60bd1299b7SAushim Nagarkatti }
61bd1299b7SAushim Nagarkatti
62bd1299b7SAushim Nagarkatti struct FormatString
63bd1299b7SAushim Nagarkatti {
64bd1299b7SAushim Nagarkatti std::string_view str;
65bd1299b7SAushim Nagarkatti std::source_location loc;
66bd1299b7SAushim Nagarkatti
67bd1299b7SAushim Nagarkatti // NOLINTNEXTLINE(google-explicit-constructor)
FormatStringcrow::FormatString68bd1299b7SAushim Nagarkatti FormatString(const char* stringIn, const std::source_location& locIn =
69bd1299b7SAushim Nagarkatti std::source_location::current()) :
707a16ddc8SEd Tanous str(stringIn), loc(locIn)
71bd1299b7SAushim Nagarkatti {}
72bd1299b7SAushim Nagarkatti };
73662aa6e3SMyung Bae
7462598e31SEd Tanous template <typename T>
logPtr(T p)7562598e31SEd Tanous const void* logPtr(T p)
7662598e31SEd Tanous {
7762598e31SEd Tanous static_assert(std::is_pointer<T>::value,
7862598e31SEd Tanous "Can't use logPtr without pointer");
7962598e31SEd Tanous return std::bit_cast<const void*>(p);
8062598e31SEd Tanous }
8162598e31SEd Tanous
826ea90760SEd Tanous template <LogLevel level, typename... Args>
vlog(std::format_string<Args...> && format,Args &&...args,const std::source_location & loc)8317c47245SEd Tanous inline void vlog(std::format_string<Args...>&& format, Args&&... args,
846ea90760SEd Tanous const std::source_location& loc) noexcept
8562598e31SEd Tanous {
86bd1299b7SAushim Nagarkatti if (getBmcwebCurrentLoggingLevel() < level)
8762598e31SEd Tanous {
8862598e31SEd Tanous return;
8962598e31SEd Tanous }
9062598e31SEd Tanous constexpr size_t stringIndex = static_cast<size_t>(level);
9162598e31SEd Tanous static_assert(stringIndex < mapLogLevelFromName.size(),
9262598e31SEd Tanous "Missing string for level");
93e7245fe8SEd Tanous constexpr std::string_view levelString = mapLogLevelFromName[stringIndex];
946ea90760SEd Tanous std::string_view filename = loc.file_name();
95ea5e2242SEd Tanous filename = filename.substr(filename.rfind('/'));
96ea5e2242SEd Tanous if (!filename.empty())
97ea5e2242SEd Tanous {
98ea5e2242SEd Tanous filename.remove_prefix(1);
99ea5e2242SEd Tanous }
10017c47245SEd Tanous std::string logLocation;
10117c47245SEd Tanous try
10217c47245SEd Tanous {
10317c47245SEd Tanous // TODO, multiple static analysis tools flag that this could potentially
10417c47245SEd Tanous // throw Based on the documentation, it shouldn't throw, so long as none
10517c47245SEd Tanous // of the formatters throw, so unclear at this point why this try/catch
10617c47245SEd Tanous // is required, but add it to silence the static analysis tools.
107bd79bce8SPatrick Williams logLocation =
108bd79bce8SPatrick Williams std::format("[{} {}:{}] ", levelString, filename, loc.line());
109bd79bce8SPatrick Williams logLocation +=
110bd79bce8SPatrick Williams std::format(std::move(format), std::forward<Args>(args)...);
11117c47245SEd Tanous }
11217c47245SEd Tanous catch (const std::format_error& /*error*/)
11317c47245SEd Tanous {
11417c47245SEd Tanous logLocation += "Failed to format";
11517c47245SEd Tanous // Nothing more we can do here if logging is broken.
11617c47245SEd Tanous }
11717c47245SEd Tanous logLocation += '\n';
11817c47245SEd Tanous // Intentionally ignore error return.
11917c47245SEd Tanous fwrite(logLocation.data(), sizeof(std::string::value_type),
12017c47245SEd Tanous logLocation.size(), stdout);
12117c47245SEd Tanous fflush(stdout);
12262598e31SEd Tanous }
12304e438cbSEd Tanous } // namespace crow
12404e438cbSEd Tanous
12562598e31SEd Tanous template <typename... Args>
1266ea90760SEd Tanous struct BMCWEB_LOG_CRITICAL
12762598e31SEd Tanous {
1286ea90760SEd Tanous // NOLINTNEXTLINE(google-explicit-constructor)
BMCWEB_LOG_CRITICALBMCWEB_LOG_CRITICAL1296ea90760SEd Tanous BMCWEB_LOG_CRITICAL(std::format_string<Args...> format, Args&&... args,
1306ea90760SEd Tanous const std::source_location& loc =
1316ea90760SEd Tanous std::source_location::current()) noexcept
1326ea90760SEd Tanous {
13317c47245SEd Tanous crow::vlog<crow::LogLevel::Critical, Args...>(
13417c47245SEd Tanous std::move(format), std::forward<Args>(args)..., loc);
13562598e31SEd Tanous }
1366ea90760SEd Tanous };
137eb8a3998SPatrick Williams
13862598e31SEd Tanous template <typename... Args>
1396ea90760SEd Tanous struct BMCWEB_LOG_ERROR
14062598e31SEd Tanous {
1416ea90760SEd Tanous // NOLINTNEXTLINE(google-explicit-constructor)
BMCWEB_LOG_ERRORBMCWEB_LOG_ERROR1426ea90760SEd Tanous BMCWEB_LOG_ERROR(std::format_string<Args...> format, Args&&... args,
1436ea90760SEd Tanous const std::source_location& loc =
1446ea90760SEd Tanous std::source_location::current()) noexcept
1456ea90760SEd Tanous {
14617c47245SEd Tanous crow::vlog<crow::LogLevel::Error, Args...>(
14717c47245SEd Tanous std::move(format), std::forward<Args>(args)..., loc);
14862598e31SEd Tanous }
1496ea90760SEd Tanous };
150600d2394SEd Tanous
15162598e31SEd Tanous template <typename... Args>
1526ea90760SEd Tanous struct BMCWEB_LOG_WARNING
15362598e31SEd Tanous {
1546ea90760SEd Tanous // NOLINTNEXTLINE(google-explicit-constructor)
BMCWEB_LOG_WARNINGBMCWEB_LOG_WARNING1556ea90760SEd Tanous BMCWEB_LOG_WARNING(std::format_string<Args...> format, Args&&... args,
1566ea90760SEd Tanous const std::source_location& loc =
1576ea90760SEd Tanous std::source_location::current()) noexcept
1586ea90760SEd Tanous {
15917c47245SEd Tanous crow::vlog<crow::LogLevel::Warning, Args...>(
16017c47245SEd Tanous std::move(format), std::forward<Args>(args)..., loc);
16162598e31SEd Tanous }
1626ea90760SEd Tanous };
163600d2394SEd Tanous
16462598e31SEd Tanous template <typename... Args>
1656ea90760SEd Tanous struct BMCWEB_LOG_INFO
16662598e31SEd Tanous {
1676ea90760SEd Tanous // NOLINTNEXTLINE(google-explicit-constructor)
BMCWEB_LOG_INFOBMCWEB_LOG_INFO1686ea90760SEd Tanous BMCWEB_LOG_INFO(std::format_string<Args...> format, Args&&... args,
1696ea90760SEd Tanous const std::source_location& loc =
1706ea90760SEd Tanous std::source_location::current()) noexcept
1716ea90760SEd Tanous {
17217c47245SEd Tanous crow::vlog<crow::LogLevel::Info, Args...>(
17317c47245SEd Tanous std::move(format), std::forward<Args>(args)..., loc);
17462598e31SEd Tanous }
1756ea90760SEd Tanous };
176600d2394SEd Tanous
17762598e31SEd Tanous template <typename... Args>
1786ea90760SEd Tanous struct BMCWEB_LOG_DEBUG
17962598e31SEd Tanous {
1806ea90760SEd Tanous // NOLINTNEXTLINE(google-explicit-constructor)
BMCWEB_LOG_DEBUGBMCWEB_LOG_DEBUG1816ea90760SEd Tanous BMCWEB_LOG_DEBUG(std::format_string<Args...> format, Args&&... args,
1826ea90760SEd Tanous const std::source_location& loc =
1836ea90760SEd Tanous std::source_location::current()) noexcept
1846ea90760SEd Tanous {
18517c47245SEd Tanous crow::vlog<crow::LogLevel::Debug, Args...>(
18617c47245SEd Tanous std::move(format), std::forward<Args>(args)..., loc);
18762598e31SEd Tanous }
1886ea90760SEd Tanous };
1896ea90760SEd Tanous
1906ea90760SEd Tanous template <typename... Args>
191*0f441f09SEd Tanous BMCWEB_LOG_CRITICAL(std::format_string<Args...>, Args&&...)
192*0f441f09SEd Tanous -> BMCWEB_LOG_CRITICAL<Args...>;
1936ea90760SEd Tanous
1946ea90760SEd Tanous template <typename... Args>
195*0f441f09SEd Tanous BMCWEB_LOG_ERROR(std::format_string<Args...>, Args&&...)
196*0f441f09SEd Tanous -> BMCWEB_LOG_ERROR<Args...>;
1976ea90760SEd Tanous
1986ea90760SEd Tanous template <typename... Args>
199*0f441f09SEd Tanous BMCWEB_LOG_WARNING(std::format_string<Args...>, Args&&...)
200*0f441f09SEd Tanous -> BMCWEB_LOG_WARNING<Args...>;
2016ea90760SEd Tanous
2026ea90760SEd Tanous template <typename... Args>
203*0f441f09SEd Tanous BMCWEB_LOG_INFO(std::format_string<Args...>, Args&&...)
204*0f441f09SEd Tanous -> BMCWEB_LOG_INFO<Args...>;
2056ea90760SEd Tanous
2066ea90760SEd Tanous template <typename... Args>
207*0f441f09SEd Tanous BMCWEB_LOG_DEBUG(std::format_string<Args...>, Args&&...)
208*0f441f09SEd Tanous -> BMCWEB_LOG_DEBUG<Args...>;
209