| 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. |
| 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) |
| 3 | |
| 4 | #pragma once |
| 5 | |
| 6 | #include <spdlog/details/null_mutex.h> |
| 7 | #include <spdlog/tweakme.h> |
| 8 | |
| 9 | #include <atomic> |
| 10 | #include <chrono> |
| 11 | #include <cstdio> |
| 12 | #include <exception> |
| 13 | #include <functional> |
| 14 | #include <initializer_list> |
| 15 | #include <memory> |
| 16 | #include <string> |
| 17 | #include <type_traits> |
| 18 | |
| 19 | #ifdef SPDLOG_USE_STD_FORMAT |
| 20 | #include <version> |
| 21 | #if __cpp_lib_format >= 202207L |
| 22 | #include <format> |
| 23 | #else |
| 24 | #include <string_view> |
| 25 | #endif |
| 26 | #endif |
| 27 | |
| 28 | #ifdef SPDLOG_COMPILED_LIB |
| 29 | #undef SPDLOG_HEADER_ONLY |
| 30 | #if defined(SPDLOG_SHARED_LIB) |
| 31 | #if defined(_WIN32) |
| 32 | #ifdef spdlog_EXPORTS |
| 33 | #define SPDLOG_API __declspec(dllexport) |
| 34 | #else // !spdlog_EXPORTS |
| 35 | #define SPDLOG_API __declspec(dllimport) |
| 36 | #endif |
| 37 | #else // !defined(_WIN32) |
| 38 | #define SPDLOG_API __attribute__((visibility("default"))) |
| 39 | #endif |
| 40 | #else // !defined(SPDLOG_SHARED_LIB) |
| 41 | #define SPDLOG_API |
| 42 | #endif |
| 43 | #define SPDLOG_INLINE |
| 44 | #else // !defined(SPDLOG_COMPILED_LIB) |
| 45 | #define SPDLOG_API |
| 46 | #define SPDLOG_HEADER_ONLY |
| 47 | #define SPDLOG_INLINE inline |
| 48 | #endif // #ifdef SPDLOG_COMPILED_LIB |
| 49 | |
| 50 | #include <spdlog/fmt/fmt.h> |
| 51 | |
| 52 | #if !defined(SPDLOG_USE_STD_FORMAT) && \ |
| 53 | FMT_VERSION >= 80000 // backward compatibility with fmt versions older than 8 |
| 54 | #define SPDLOG_FMT_RUNTIME(format_string) fmt::runtime(format_string) |
| 55 | #define SPDLOG_FMT_STRING(format_string) FMT_STRING(format_string) |
| 56 | #if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) |
| 57 | #include <spdlog/fmt/xchar.h> |
| 58 | #endif |
| 59 | #else |
| 60 | #define SPDLOG_FMT_RUNTIME(format_string) format_string |
| 61 | #define SPDLOG_FMT_STRING(format_string) format_string |
| 62 | #endif |
| 63 | |
| 64 | // visual studio up to 2013 does not support noexcept nor constexpr |
| 65 | #if defined(_MSC_VER) && (_MSC_VER < 1900) |
| 66 | #define SPDLOG_NOEXCEPT _NOEXCEPT |
| 67 | #define SPDLOG_CONSTEXPR |
| 68 | #else |
| 69 | #define SPDLOG_NOEXCEPT noexcept |
| 70 | #define SPDLOG_CONSTEXPR constexpr |
| 71 | #endif |
| 72 | |
| 73 | // If building with std::format, can just use constexpr, otherwise if building with fmt |
| 74 | // SPDLOG_CONSTEXPR_FUNC needs to be set the same as FMT_CONSTEXPR to avoid situations where |
| 75 | // a constexpr function in spdlog could end up calling a non-constexpr function in fmt |
| 76 | // depending on the compiler |
| 77 | // If fmt determines it can't use constexpr, we should inline the function instead |
| 78 | #ifdef SPDLOG_USE_STD_FORMAT |
| 79 | #define SPDLOG_CONSTEXPR_FUNC constexpr |
| 80 | #else // Being built with fmt |
| 81 | #if FMT_USE_CONSTEXPR |
| 82 | #define SPDLOG_CONSTEXPR_FUNC FMT_CONSTEXPR |
| 83 | #else |
| 84 | #define SPDLOG_CONSTEXPR_FUNC inline |
| 85 | #endif |
| 86 | #endif |
| 87 | |
| 88 | #if defined(__GNUC__) || defined(__clang__) |
| 89 | #define SPDLOG_DEPRECATED __attribute__((deprecated)) |
| 90 | #elif defined(_MSC_VER) |
| 91 | #define SPDLOG_DEPRECATED __declspec(deprecated) |
| 92 | #else |
| 93 | #define SPDLOG_DEPRECATED |
| 94 | #endif |
| 95 | |
| 96 | // disable thread local on msvc 2013 |
| 97 | #ifndef SPDLOG_NO_TLS |
| 98 | #if (defined(_MSC_VER) && (_MSC_VER < 1900)) || defined(__cplusplus_winrt) |
| 99 | #define SPDLOG_NO_TLS 1 |
| 100 | #endif |
| 101 | #endif |
| 102 | |
| 103 | #ifndef SPDLOG_FUNCTION |
| 104 | #define SPDLOG_FUNCTION static_cast<const char *>(__FUNCTION__) |
| 105 | #endif |
| 106 | |
| 107 | #ifdef SPDLOG_NO_EXCEPTIONS |
| 108 | #define SPDLOG_TRY |
| 109 | #define SPDLOG_THROW(ex) \ |
| 110 | do { \ |
| 111 | printf("spdlog fatal error: %s\n", ex.what()); \ |
| 112 | std::abort(); \ |
| 113 | } while (0) |
| 114 | #define SPDLOG_CATCH_STD |
| 115 | #else |
| 116 | #define SPDLOG_TRY try |
| 117 | #define SPDLOG_THROW(ex) throw(ex) |
| 118 | #define SPDLOG_CATCH_STD \ |
| 119 | catch (const std::exception &) { \ |
| 120 | } |
| 121 | #endif |
| 122 | |
| 123 | namespace spdlog { |
| 124 | |
| 125 | class formatter; |
| 126 | |
| 127 | namespace sinks { |
| 128 | class sink; |
| 129 | } |
| 130 | |
| 131 | #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) |
| 132 | using filename_t = std::wstring; |
| 133 | // allow macro expansion to occur in SPDLOG_FILENAME_T |
| 134 | #define SPDLOG_FILENAME_T_INNER(s) L##s |
| 135 | #define SPDLOG_FILENAME_T(s) SPDLOG_FILENAME_T_INNER(s) |
| 136 | #else |
| 137 | using filename_t = std::string; |
| 138 | #define SPDLOG_FILENAME_T(s) s |
| 139 | #endif |
| 140 | |
| 141 | using log_clock = std::chrono::system_clock; |
| 142 | using sink_ptr = std::shared_ptr<sinks::sink>; |
| 143 | using sinks_init_list = std::initializer_list<sink_ptr>; |
| 144 | using err_handler = std::function<void(const std::string &err_msg)>; |
| 145 | #ifdef SPDLOG_USE_STD_FORMAT |
| 146 | namespace fmt_lib = std; |
| 147 | |
| 148 | using string_view_t = std::string_view; |
| 149 | using memory_buf_t = std::string; |
| 150 | |
| 151 | template <typename... Args> |
| 152 | #if __cpp_lib_format >= 202207L |
| 153 | using format_string_t = std::format_string<Args...>; |
| 154 | #else |
| 155 | using format_string_t = std::string_view; |
| 156 | #endif |
| 157 | |
| 158 | template <class T, class Char = char> |
| 159 | struct is_convertible_to_basic_format_string |
| 160 | : std::integral_constant<bool, std::is_convertible<T, std::basic_string_view<Char>>::value> {}; |
| 161 | |
| 162 | #if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) |
| 163 | using wstring_view_t = std::wstring_view; |
| 164 | using wmemory_buf_t = std::wstring; |
| 165 | |
| 166 | template <typename... Args> |
| 167 | #if __cpp_lib_format >= 202207L |
| 168 | using wformat_string_t = std::wformat_string<Args...>; |
| 169 | #else |
| 170 | using wformat_string_t = std::wstring_view; |
| 171 | #endif |
| 172 | #endif |
| 173 | #define SPDLOG_BUF_TO_STRING(x) x |
| 174 | #else // use fmt lib instead of std::format |
| 175 | namespace fmt_lib = fmt; |
| 176 | |
| 177 | using string_view_t = fmt::basic_string_view<char>; |
| 178 | using memory_buf_t = fmt::basic_memory_buffer<char, 250>; |
| 179 | |
| 180 | template <typename... Args> |
| 181 | using format_string_t = fmt::format_string<Args...>; |
| 182 | |
| 183 | template <class T> |
| 184 | using remove_cvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type; |
| 185 | |
| 186 | template <typename Char> |
| 187 | #if FMT_VERSION >= 90101 |
| 188 | using fmt_runtime_string = fmt::runtime_format_string<Char>; |
| 189 | #else |
| 190 | using fmt_runtime_string = fmt::basic_runtime<Char>; |
| 191 | #endif |
| 192 | |
| 193 | // clang doesn't like SFINAE disabled constructor in std::is_convertible<> so have to repeat the |
| 194 | // condition from basic_format_string here, in addition, fmt::basic_runtime<Char> is only |
| 195 | // convertible to basic_format_string<Char> but not basic_string_view<Char> |
| 196 | template <class T, class Char = char> |
| 197 | struct is_convertible_to_basic_format_string |
| 198 | : std::integral_constant<bool, |
| 199 | std::is_convertible<T, fmt::basic_string_view<Char>>::value || |
| 200 | std::is_same<remove_cvref_t<T>, fmt_runtime_string<Char>>::value> { |
| 201 | }; |
| 202 | |
| 203 | #if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) |
| 204 | using wstring_view_t = fmt::basic_string_view<wchar_t>; |
| 205 | using wmemory_buf_t = fmt::basic_memory_buffer<wchar_t, 250>; |
| 206 | |
| 207 | template <typename... Args> |
| 208 | using wformat_string_t = fmt::wformat_string<Args...>; |
| 209 | #endif |
| 210 | #define SPDLOG_BUF_TO_STRING(x) fmt::to_string(x) |
| 211 | #endif |
| 212 | |
| 213 | #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT |
| 214 | #ifndef _WIN32 |
| 215 | #error SPDLOG_WCHAR_TO_UTF8_SUPPORT only supported on windows |
| 216 | #endif // _WIN32 |
| 217 | #endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT |
| 218 | |
| 219 | template <class T> |
| 220 | struct is_convertible_to_any_format_string |
| 221 | : std::integral_constant<bool, |
| 222 | is_convertible_to_basic_format_string<T, char>::value || |
| 223 | is_convertible_to_basic_format_string<T, wchar_t>::value> {}; |
| 224 | |
| 225 | #if defined(SPDLOG_NO_ATOMIC_LEVELS) |
| 226 | using level_t = details::null_atomic_int; |
| 227 | #else |
| 228 | using level_t = std::atomic<int>; |
| 229 | #endif |
| 230 | |
| 231 | #define SPDLOG_LEVEL_TRACE 0 |
| 232 | #define SPDLOG_LEVEL_DEBUG 1 |
| 233 | #define SPDLOG_LEVEL_INFO 2 |
| 234 | #define SPDLOG_LEVEL_WARN 3 |
| 235 | #define SPDLOG_LEVEL_ERROR 4 |
| 236 | #define SPDLOG_LEVEL_CRITICAL 5 |
| 237 | #define SPDLOG_LEVEL_OFF 6 |
| 238 | |
| 239 | #if !defined(SPDLOG_ACTIVE_LEVEL) |
| 240 | #define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_INFO |
| 241 | #endif |
| 242 | |
| 243 | // Log level enum |
| 244 | namespace level { |
| 245 | enum level_enum : int { |
| 246 | trace = SPDLOG_LEVEL_TRACE, |
| 247 | debug = SPDLOG_LEVEL_DEBUG, |
| 248 | info = SPDLOG_LEVEL_INFO, |
| 249 | warn = SPDLOG_LEVEL_WARN, |
| 250 | err = SPDLOG_LEVEL_ERROR, |
| 251 | critical = SPDLOG_LEVEL_CRITICAL, |
| 252 | off = SPDLOG_LEVEL_OFF, |
| 253 | n_levels |
| 254 | }; |
| 255 | |
| 256 | #define SPDLOG_LEVEL_NAME_TRACE spdlog::string_view_t("trace", 5) |
| 257 | #define SPDLOG_LEVEL_NAME_DEBUG spdlog::string_view_t("debug", 5) |
| 258 | #define SPDLOG_LEVEL_NAME_INFO spdlog::string_view_t("info", 4) |
| 259 | #define SPDLOG_LEVEL_NAME_WARNING spdlog::string_view_t("warning", 7) |
| 260 | #define SPDLOG_LEVEL_NAME_ERROR spdlog::string_view_t("error", 5) |
| 261 | #define SPDLOG_LEVEL_NAME_CRITICAL spdlog::string_view_t("critical", 8) |
| 262 | #define SPDLOG_LEVEL_NAME_OFF spdlog::string_view_t("off", 3) |
| 263 | |
| 264 | #if !defined(SPDLOG_LEVEL_NAMES) |
| 265 | #define SPDLOG_LEVEL_NAMES \ |
| 266 | { \ |
| 267 | SPDLOG_LEVEL_NAME_TRACE, SPDLOG_LEVEL_NAME_DEBUG, SPDLOG_LEVEL_NAME_INFO, \ |
| 268 | SPDLOG_LEVEL_NAME_WARNING, SPDLOG_LEVEL_NAME_ERROR, SPDLOG_LEVEL_NAME_CRITICAL, \ |
| 269 | SPDLOG_LEVEL_NAME_OFF \ |
| 270 | } |
| 271 | #endif |
| 272 | |
| 273 | #if !defined(SPDLOG_SHORT_LEVEL_NAMES) |
| 274 | |
| 275 | #define SPDLOG_SHORT_LEVEL_NAMES \ |
| 276 | { "T", "D", "I", "W", "E", "C", "O" } |
| 277 | #endif |
| 278 | |
| 279 | SPDLOG_API const string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT; |
| 280 | SPDLOG_API const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT; |
| 281 | SPDLOG_API spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT; |
| 282 | |
| 283 | } // namespace level |
| 284 | |
| 285 | // |
| 286 | // Color mode used by sinks with color support. |
| 287 | // |
| 288 | enum class color_mode { always, automatic, never }; |
| 289 | |
| 290 | // |
| 291 | // Pattern time - specific time getting to use for pattern_formatter. |
| 292 | // local time by default |
| 293 | // |
| 294 | enum class pattern_time_type { |
| 295 | local, // log localtime |
| 296 | utc // log utc |
| 297 | }; |
| 298 | |
| 299 | // |
| 300 | // Log exception |
| 301 | // |
| 302 | class SPDLOG_API spdlog_ex : public std::exception { |
| 303 | public: |
| 304 | explicit spdlog_ex(std::string msg); |
| 305 | spdlog_ex(const std::string &msg, int last_errno); |
| 306 | const char *what() const SPDLOG_NOEXCEPT override; |
| 307 | |
| 308 | private: |
| 309 | std::string msg_; |
| 310 | }; |
| 311 | |
| 312 | [[noreturn]] SPDLOG_API void throw_spdlog_ex(const std::string &msg, int last_errno); |
| 313 | [[noreturn]] SPDLOG_API void throw_spdlog_ex(std::string msg); |
| 314 | |
| 315 | struct source_loc { |
| 316 | SPDLOG_CONSTEXPR source_loc() = default; |
| 317 | SPDLOG_CONSTEXPR source_loc(const char *filename_in, int line_in, const char *funcname_in) |
| 318 | : filename{filename_in}, |
| 319 | line{line_in}, |
| 320 | funcname{funcname_in} {} |
| 321 | |
| 322 | SPDLOG_CONSTEXPR bool empty() const SPDLOG_NOEXCEPT { return line <= 0; } |
| 323 | const char *filename{nullptr}; |
| 324 | int line{0}; |
| 325 | const char *funcname{nullptr}; |
| 326 | }; |
| 327 | |
| 328 | struct file_event_handlers { |
| 329 | file_event_handlers() |
| 330 | : before_open(nullptr), |
| 331 | after_open(nullptr), |
| 332 | before_close(nullptr), |
| 333 | after_close(nullptr) {} |
| 334 | |
| 335 | std::function<void(const filename_t &filename)> before_open; |
| 336 | std::function<void(const filename_t &filename, std::FILE *file_stream)> after_open; |
| 337 | std::function<void(const filename_t &filename, std::FILE *file_stream)> before_close; |
| 338 | std::function<void(const filename_t &filename)> after_close; |
| 339 | }; |
| 340 | |
| 341 | namespace details { |
| 342 | |
| 343 | // to_string_view |
| 344 | |
| 345 | SPDLOG_CONSTEXPR_FUNC spdlog::string_view_t to_string_view(const memory_buf_t &buf) |
| 346 | SPDLOG_NOEXCEPT { |
| 347 | return spdlog::string_view_t{buf.data(), buf.size()}; |
| 348 | } |
| 349 | |
| 350 | SPDLOG_CONSTEXPR_FUNC spdlog::string_view_t to_string_view(spdlog::string_view_t str) |
| 351 | SPDLOG_NOEXCEPT { |
| 352 | return str; |
| 353 | } |
| 354 | |
| 355 | #if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) |
| 356 | SPDLOG_CONSTEXPR_FUNC spdlog::wstring_view_t to_string_view(const wmemory_buf_t &buf) |
| 357 | SPDLOG_NOEXCEPT { |
| 358 | return spdlog::wstring_view_t{buf.data(), buf.size()}; |
| 359 | } |
| 360 | |
| 361 | SPDLOG_CONSTEXPR_FUNC spdlog::wstring_view_t to_string_view(spdlog::wstring_view_t str) |
| 362 | SPDLOG_NOEXCEPT { |
| 363 | return str; |
| 364 | } |
| 365 | #endif |
| 366 | |
| 367 | #if defined(SPDLOG_USE_STD_FORMAT) && __cpp_lib_format >= 202207L |
| 368 | template <typename T, typename... Args> |
| 369 | SPDLOG_CONSTEXPR_FUNC std::basic_string_view<T> to_string_view( |
| 370 | std::basic_format_string<T, Args...> fmt) SPDLOG_NOEXCEPT { |
| 371 | return fmt.get(); |
| 372 | } |
| 373 | #endif |
| 374 | |
| 375 | // make_unique support for pre c++14 |
| 376 | #if __cplusplus >= 201402L // C++14 and beyond |
| 377 | using std::enable_if_t; |
| 378 | using std::make_unique; |
| 379 | #else |
| 380 | template <bool B, class T = void> |
| 381 | using enable_if_t = typename std::enable_if<B, T>::type; |
| 382 | |
| 383 | template <typename T, typename... Args> |
| 384 | std::unique_ptr<T> make_unique(Args &&...args) { |
| 385 | static_assert(!std::is_array<T>::value, "arrays not supported" ); |
| 386 | return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); |
| 387 | } |
| 388 | #endif |
| 389 | |
| 390 | // to avoid useless casts (see https://github.com/nlohmann/json/issues/2893#issuecomment-889152324) |
| 391 | template <typename T, typename U, enable_if_t<!std::is_same<T, U>::value, int> = 0> |
| 392 | constexpr T conditional_static_cast(U value) { |
| 393 | return static_cast<T>(value); |
| 394 | } |
| 395 | |
| 396 | template <typename T, typename U, enable_if_t<std::is_same<T, U>::value, int> = 0> |
| 397 | constexpr T conditional_static_cast(U value) { |
| 398 | return value; |
| 399 | } |
| 400 | |
| 401 | } // namespace details |
| 402 | } // namespace spdlog |
| 403 | |
| 404 | #ifdef SPDLOG_HEADER_ONLY |
| 405 | #include "common-inl.h" |
| 406 | #endif |
| 407 | |