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 { 1662598e31SEd Tanous constexpr auto parse(std::format_parse_context& ctx) 1762598e31SEd Tanous { 1862598e31SEd Tanous return ctx.begin(); 1962598e31SEd Tanous } 2062598e31SEd 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 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 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) 68bd1299b7SAushim Nagarkatti FormatString(const char* stringIn, const std::source_location& locIn = 69bd1299b7SAushim Nagarkatti std::source_location::current()) : 70*7a16ddc8SEd Tanous str(stringIn), loc(locIn) 71bd1299b7SAushim Nagarkatti {} 72bd1299b7SAushim Nagarkatti }; 73662aa6e3SMyung Bae 7462598e31SEd Tanous template <typename T> 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> 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) 1296ea90760SEd 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) 1426ea90760SEd 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) 1556ea90760SEd 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) 1686ea90760SEd 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) 1816ea90760SEd 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> 191bd79bce8SPatrick Williams BMCWEB_LOG_CRITICAL(std::format_string<Args...>, 192bd79bce8SPatrick Williams Args&&...) -> BMCWEB_LOG_CRITICAL<Args...>; 1936ea90760SEd Tanous 1946ea90760SEd Tanous template <typename... Args> 195bd79bce8SPatrick Williams BMCWEB_LOG_ERROR(std::format_string<Args...>, 196bd79bce8SPatrick Williams Args&&...) -> BMCWEB_LOG_ERROR<Args...>; 1976ea90760SEd Tanous 1986ea90760SEd Tanous template <typename... Args> 199bd79bce8SPatrick Williams BMCWEB_LOG_WARNING(std::format_string<Args...>, 200bd79bce8SPatrick Williams Args&&...) -> BMCWEB_LOG_WARNING<Args...>; 2016ea90760SEd Tanous 2026ea90760SEd Tanous template <typename... Args> 203bd79bce8SPatrick Williams BMCWEB_LOG_INFO(std::format_string<Args...>, 204bd79bce8SPatrick Williams Args&&...) -> BMCWEB_LOG_INFO<Args...>; 2056ea90760SEd Tanous 2066ea90760SEd Tanous template <typename... Args> 207bd79bce8SPatrick Williams BMCWEB_LOG_DEBUG(std::format_string<Args...>, 208bd79bce8SPatrick Williams Args&&...) -> BMCWEB_LOG_DEBUG<Args...>; 209