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 <> 5062598e31SEd Tanous struct std::formatter<boost::urls::url> 5162598e31SEd Tanous { 5262598e31SEd Tanous constexpr auto parse(std::format_parse_context& ctx) 5362598e31SEd Tanous { 5462598e31SEd Tanous return ctx.begin(); 5562598e31SEd Tanous } 5662598e31SEd Tanous auto format(const boost::urls::url& msg, auto& ctx) const 5762598e31SEd Tanous { 5862598e31SEd Tanous return std::format_to(ctx.out(), "{}", std::string_view(msg.buffer())); 5962598e31SEd Tanous } 6062598e31SEd Tanous }; 6162598e31SEd Tanous 6262598e31SEd Tanous template <> 6362598e31SEd Tanous struct std::formatter<boost::core::string_view> 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::core::string_view& msg, auto& ctx) const 7062598e31SEd Tanous { 7162598e31SEd Tanous return std::format_to(ctx.out(), "{}", std::string_view(msg)); 7262598e31SEd Tanous } 7362598e31SEd Tanous }; 7462598e31SEd Tanous 7562598e31SEd Tanous template <> 7662598e31SEd Tanous struct std::formatter<void*> 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 void*& ptr, auto& ctx) const 8362598e31SEd Tanous { 8462598e31SEd Tanous return std::format_to(ctx.out(), "{}", 8562598e31SEd Tanous std::to_string(std::bit_cast<size_t>(ptr))); 8662598e31SEd Tanous } 8762598e31SEd Tanous }; 8862598e31SEd Tanous 8962598e31SEd Tanous template <> 9062598e31SEd Tanous struct std::formatter<nlohmann::json::json_pointer> 9162598e31SEd Tanous { 9262598e31SEd Tanous constexpr auto parse(std::format_parse_context& ctx) 9362598e31SEd Tanous { 9462598e31SEd Tanous return ctx.begin(); 9562598e31SEd Tanous } 9662598e31SEd Tanous auto format(const nlohmann::json::json_pointer& ptr, auto& ctx) const 9762598e31SEd Tanous { 9862598e31SEd Tanous return std::format_to(ctx.out(), "{}", ptr.to_string()); 9962598e31SEd Tanous } 10062598e31SEd Tanous }; 10162598e31SEd Tanous 10262598e31SEd Tanous template <> 10362598e31SEd Tanous struct std::formatter<nlohmann::json> 10462598e31SEd Tanous { 10562598e31SEd Tanous static 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, auto& ctx) const 11062598e31SEd Tanous { 11162598e31SEd Tanous return std::format_to( 11262598e31SEd Tanous ctx.out(), "{}", 11362598e31SEd Tanous json.dump(-1, ' ', false, 11462598e31SEd Tanous nlohmann::json::error_handler_t::replace)); 11562598e31SEd Tanous } 11662598e31SEd Tanous }; 11762598e31SEd Tanous // NOLINTEND(readability-convert-member-functions-to-static, cert-dcl58-cpp) 11804e438cbSEd Tanous 11904e438cbSEd Tanous namespace crow 12004e438cbSEd Tanous { 12104e438cbSEd Tanous enum class LogLevel 12204e438cbSEd Tanous { 123662aa6e3SMyung Bae Disabled = 0, 12404e438cbSEd Tanous Critical, 125*e7245fe8SEd Tanous Error, 126*e7245fe8SEd Tanous Warning, 127*e7245fe8SEd Tanous Info, 128*e7245fe8SEd Tanous Debug, 129*e7245fe8SEd Tanous Enabled, 13004e438cbSEd Tanous }; 13104e438cbSEd Tanous 132662aa6e3SMyung Bae // Mapping of the external loglvl name to internal loglvl 133*e7245fe8SEd Tanous constexpr std::array<std::string_view, 7> mapLogLevelFromName{ 134*e7245fe8SEd Tanous "DISABLED", "CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG", "ENABLED"}; 135662aa6e3SMyung Bae 136662aa6e3SMyung Bae constexpr crow::LogLevel getLogLevelFromName(std::string_view name) 137662aa6e3SMyung Bae { 138*e7245fe8SEd Tanous const auto* iter = std::ranges::find(mapLogLevelFromName, name); 139*e7245fe8SEd Tanous if (iter != mapLogLevelFromName.end()) 140662aa6e3SMyung Bae { 141*e7245fe8SEd Tanous return static_cast<LogLevel>(iter - mapLogLevelFromName.begin()); 142662aa6e3SMyung Bae } 143662aa6e3SMyung Bae return crow::LogLevel::Disabled; 144662aa6e3SMyung Bae } 145662aa6e3SMyung Bae 146662aa6e3SMyung Bae // configured bmcweb LogLevel 147662aa6e3SMyung Bae constexpr crow::LogLevel bmcwebCurrentLoggingLevel = 148662aa6e3SMyung Bae getLogLevelFromName(bmcwebLoggingLevel); 149662aa6e3SMyung Bae 15062598e31SEd Tanous struct FormatString 15104e438cbSEd Tanous { 15262598e31SEd Tanous std::string_view str; 15362598e31SEd Tanous std::source_location loc; 15404e438cbSEd Tanous 15562598e31SEd Tanous // NOLINTNEXTLINE(google-explicit-constructor) 15662598e31SEd Tanous FormatString(const char* strIn, const std::source_location& locIn = 15762598e31SEd Tanous std::source_location::current()) : 15862598e31SEd Tanous str(strIn), 15962598e31SEd Tanous loc(locIn) 16062598e31SEd Tanous {} 16104e438cbSEd Tanous }; 16262598e31SEd Tanous 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 17162598e31SEd Tanous template <LogLevel level> 17262598e31SEd Tanous inline void vlog(const FormatString& format, std::format_args&& args) 17362598e31SEd Tanous { 174*e7245fe8SEd Tanous if constexpr (bmcwebCurrentLoggingLevel <= level) 17562598e31SEd Tanous { 17662598e31SEd Tanous return; 17762598e31SEd Tanous } 17862598e31SEd Tanous constexpr size_t stringIndex = static_cast<size_t>(level); 17962598e31SEd Tanous static_assert(stringIndex < mapLogLevelFromName.size(), 18062598e31SEd Tanous "Missing string for level"); 181*e7245fe8SEd Tanous constexpr std::string_view levelString = mapLogLevelFromName[stringIndex]; 18262598e31SEd Tanous std::string_view filename = format.loc.file_name(); 183*e7245fe8SEd Tanous filename = filename.substr(filename.rfind('/') + 1); 18462598e31SEd Tanous std::cout << std::format("[{} {}:{}] ", levelString, filename, 185*e7245fe8SEd Tanous format.loc.line()) 186*e7245fe8SEd Tanous << std::vformat(format.str, args) << '\n'; 18762598e31SEd Tanous } 18804e438cbSEd Tanous } // namespace crow 18904e438cbSEd Tanous 19062598e31SEd Tanous template <typename... Args> 19162598e31SEd Tanous inline void BMCWEB_LOG_CRITICAL(const crow::FormatString& format, 19262598e31SEd Tanous Args&&... args) 19362598e31SEd Tanous { 19462598e31SEd Tanous crow::vlog<crow::LogLevel::Critical>( 19562598e31SEd Tanous format, std::make_format_args(std::forward<Args>(args)...)); 19662598e31SEd Tanous } 197eb8a3998SPatrick Williams 19862598e31SEd Tanous template <typename... Args> 19962598e31SEd Tanous inline void BMCWEB_LOG_ERROR(const crow::FormatString& format, Args&&... args) 20062598e31SEd Tanous { 20162598e31SEd Tanous crow::vlog<crow::LogLevel::Error>( 20262598e31SEd Tanous format, std::make_format_args(std::forward<Args>(args)...)); 20362598e31SEd Tanous } 204600d2394SEd Tanous 20562598e31SEd Tanous template <typename... Args> 20662598e31SEd Tanous inline void BMCWEB_LOG_WARNING(const crow::FormatString& format, Args&&... args) 20762598e31SEd Tanous { 20862598e31SEd Tanous crow::vlog<crow::LogLevel::Warning>( 20962598e31SEd Tanous format, std::make_format_args(std::forward<Args>(args)...)); 21062598e31SEd Tanous } 211600d2394SEd Tanous 21262598e31SEd Tanous template <typename... Args> 21362598e31SEd Tanous inline void BMCWEB_LOG_INFO(const crow::FormatString& format, Args&&... args) 21462598e31SEd Tanous { 21562598e31SEd Tanous crow::vlog<crow::LogLevel::Info>( 21662598e31SEd Tanous format, std::make_format_args(std::forward<Args>(args)...)); 21762598e31SEd Tanous } 218600d2394SEd Tanous 21962598e31SEd Tanous template <typename... Args> 22062598e31SEd Tanous inline void BMCWEB_LOG_DEBUG(const crow::FormatString& format, Args&&... args) 22162598e31SEd Tanous { 22262598e31SEd Tanous crow::vlog<crow::LogLevel::Debug>( 22362598e31SEd Tanous format, std::make_format_args(std::forward<Args>(args)...)); 22462598e31SEd Tanous } 225