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> 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::core::string_view> 64 { 65 constexpr auto parse(std::format_parse_context& ctx) 66 { 67 return ctx.begin(); 68 } 69 auto format(const boost::core::string_view& msg, auto& ctx) const 70 { 71 return std::format_to(ctx.out(), "{}", std::string_view(msg)); 72 } 73 }; 74 75 template <> 76 struct std::formatter<void*> 77 { 78 constexpr auto parse(std::format_parse_context& ctx) 79 { 80 return ctx.begin(); 81 } 82 auto format(const void*& ptr, auto& ctx) const 83 { 84 return std::format_to(ctx.out(), "{}", 85 std::to_string(std::bit_cast<size_t>(ptr))); 86 } 87 }; 88 89 template <> 90 struct std::formatter<nlohmann::json::json_pointer> 91 { 92 constexpr auto parse(std::format_parse_context& ctx) 93 { 94 return ctx.begin(); 95 } 96 auto format(const nlohmann::json::json_pointer& ptr, auto& ctx) const 97 { 98 return std::format_to(ctx.out(), "{}", ptr.to_string()); 99 } 100 }; 101 102 template <> 103 struct std::formatter<nlohmann::json> 104 { 105 static constexpr auto parse(std::format_parse_context& ctx) 106 { 107 return ctx.begin(); 108 } 109 auto format(const nlohmann::json& json, auto& ctx) const 110 { 111 return std::format_to( 112 ctx.out(), "{}", 113 json.dump(-1, ' ', false, 114 nlohmann::json::error_handler_t::replace)); 115 } 116 }; 117 // NOLINTEND(readability-convert-member-functions-to-static, cert-dcl58-cpp) 118 119 namespace crow 120 { 121 enum class LogLevel 122 { 123 Disabled = 0, 124 Debug, 125 Info, 126 Warning, 127 Error, 128 Critical, 129 }; 130 131 // Mapping of the external loglvl name to internal loglvl 132 constexpr std::array<std::pair<std::string_view, crow::LogLevel>, 7> 133 mapLogLevelFromName{{{"disabled", crow::LogLevel::Disabled}, 134 {"enabled", crow::LogLevel::Debug}, 135 {"debug", crow::LogLevel::Debug}, 136 {"info", crow::LogLevel::Info}, 137 {"warning", crow::LogLevel::Warning}, 138 {"error", crow::LogLevel::Error}, 139 {"critical", crow::LogLevel::Critical}}}; 140 141 constexpr crow::LogLevel getLogLevelFromName(std::string_view name) 142 { 143 const auto* iter = 144 std::find_if(begin(mapLogLevelFromName), end(mapLogLevelFromName), 145 [&name](const auto& v) { return v.first == name; }); 146 if (iter != end(mapLogLevelFromName)) 147 { 148 return iter->second; 149 } 150 return crow::LogLevel::Disabled; 151 } 152 153 // configured bmcweb LogLevel 154 constexpr crow::LogLevel bmcwebCurrentLoggingLevel = 155 getLogLevelFromName(bmcwebLoggingLevel); 156 157 struct FormatString 158 { 159 std::string_view str; 160 std::source_location loc; 161 162 // NOLINTNEXTLINE(google-explicit-constructor) 163 FormatString(const char* strIn, const std::source_location& locIn = 164 std::source_location::current()) : 165 str(strIn), 166 loc(locIn) 167 {} 168 }; 169 170 template <typename T> 171 const void* logPtr(T p) 172 { 173 static_assert(std::is_pointer<T>::value, 174 "Can't use logPtr without pointer"); 175 return std::bit_cast<const void*>(p); 176 } 177 178 template <LogLevel level> 179 inline void vlog(const FormatString& format, std::format_args&& args) 180 { 181 if constexpr (bmcwebCurrentLoggingLevel > level) 182 { 183 return; 184 } 185 constexpr size_t stringIndex = static_cast<size_t>(level); 186 static_assert(stringIndex < mapLogLevelFromName.size(), 187 "Missing string for level"); 188 constexpr std::string_view levelString = 189 mapLogLevelFromName[stringIndex].first; 190 std::string_view filename = format.loc.file_name(); 191 if (filename.starts_with("../")) 192 { 193 filename = filename.substr(3); 194 } 195 std::cout << std::format("[{} {}:{}] ", levelString, filename, 196 format.loc.line()); 197 std::cout << std::vformat(format.str, args); 198 std::putc('\n', stdout); 199 } 200 } // namespace crow 201 202 template <typename... Args> 203 inline void BMCWEB_LOG_CRITICAL(const crow::FormatString& format, 204 Args&&... args) 205 { 206 crow::vlog<crow::LogLevel::Critical>( 207 format, std::make_format_args(std::forward<Args>(args)...)); 208 } 209 210 template <typename... Args> 211 inline void BMCWEB_LOG_ERROR(const crow::FormatString& format, Args&&... args) 212 { 213 crow::vlog<crow::LogLevel::Error>( 214 format, std::make_format_args(std::forward<Args>(args)...)); 215 } 216 217 template <typename... Args> 218 inline void BMCWEB_LOG_WARNING(const crow::FormatString& format, Args&&... args) 219 { 220 crow::vlog<crow::LogLevel::Warning>( 221 format, std::make_format_args(std::forward<Args>(args)...)); 222 } 223 224 template <typename... Args> 225 inline void BMCWEB_LOG_INFO(const crow::FormatString& format, Args&&... args) 226 { 227 crow::vlog<crow::LogLevel::Info>( 228 format, std::make_format_args(std::forward<Args>(args)...)); 229 } 230 231 template <typename... Args> 232 inline void BMCWEB_LOG_DEBUG(const crow::FormatString& format, Args&&... args) 233 { 234 crow::vlog<crow::LogLevel::Debug>( 235 format, std::make_format_args(std::forward<Args>(args)...)); 236 } 237