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