diff options
author | Charless Milette <charles.milette@gmail.com> | 2021-11-13 19:29:05 +0300 |
---|---|---|
committer | Charless Milette <charles.milette@gmail.com> | 2021-11-13 19:29:05 +0300 |
commit | 44a4517e2b1189bde950b86cbf6c2c5943a5a55a (patch) | |
tree | 04cadb34e8aaa2fc84db53cd2d2e118e4350863e /include/spdlog | |
parent | ff9313e6ddccb85dae33df024a5378d5e8377b9b (diff) |
Support C++20 std::format as an alternative to fmtlib
Diffstat (limited to 'include/spdlog')
-rw-r--r-- | include/spdlog/common-inl.h | 4 | ||||
-rw-r--r-- | include/spdlog/common.h | 48 | ||||
-rw-r--r-- | include/spdlog/details/fmt_helper.h | 54 | ||||
-rw-r--r-- | include/spdlog/details/os-inl.h | 16 | ||||
-rw-r--r-- | include/spdlog/details/tcp_client-windows.h | 4 | ||||
-rw-r--r-- | include/spdlog/details/tcp_client.h | 3 | ||||
-rw-r--r-- | include/spdlog/details/udp_client-windows.h | 4 | ||||
-rw-r--r-- | include/spdlog/fmt/bin_to_hex.h | 12 | ||||
-rw-r--r-- | include/spdlog/fmt/chrono.h | 16 | ||||
-rw-r--r-- | include/spdlog/fmt/compile.h | 18 | ||||
-rw-r--r-- | include/spdlog/fmt/fmt.h | 4 | ||||
-rw-r--r-- | include/spdlog/fmt/ostr.h | 16 | ||||
-rw-r--r-- | include/spdlog/fmt/xchar.h | 18 | ||||
-rw-r--r-- | include/spdlog/logger.h | 97 | ||||
-rw-r--r-- | include/spdlog/sinks/daily_file_sink.h | 8 | ||||
-rw-r--r-- | include/spdlog/sinks/hourly_file_sink.h | 2 | ||||
-rw-r--r-- | include/spdlog/sinks/msvc_sink.h | 4 | ||||
-rw-r--r-- | include/spdlog/sinks/ringbuffer_sink.h | 4 | ||||
-rw-r--r-- | include/spdlog/sinks/rotating_file_sink-inl.h | 2 | ||||
-rw-r--r-- | include/spdlog/sinks/win_eventlog_sink.h | 33 | ||||
-rw-r--r-- | include/spdlog/spdlog.h | 32 | ||||
-rw-r--r-- | include/spdlog/tweakme.h | 7 |
22 files changed, 290 insertions, 116 deletions
diff --git a/include/spdlog/common-inl.h b/include/spdlog/common-inl.h index 97cbbddc..9fd2bcb5 100644 --- a/include/spdlog/common-inl.h +++ b/include/spdlog/common-inl.h @@ -55,9 +55,13 @@ SPDLOG_INLINE spdlog_ex::spdlog_ex(std::string msg) SPDLOG_INLINE spdlog_ex::spdlog_ex(const std::string &msg, int last_errno) { +#ifdef SPDLOG_USE_STD_FORMAT + msg_ = std::system_error(std::error_code(last_errno, std::generic_category()), msg).what(); +#else memory_buf_t outbuf; fmt::format_system_error(outbuf, last_errno, msg.c_str()); msg_ = fmt::to_string(outbuf); +#endif } SPDLOG_INLINE const char *spdlog_ex::what() const SPDLOG_NOEXCEPT diff --git a/include/spdlog/common.h b/include/spdlog/common.h index ddaa34ce..fb45d2a2 100644 --- a/include/spdlog/common.h +++ b/include/spdlog/common.h @@ -16,6 +16,10 @@ #include <functional> #include <cstdio> +#ifdef SPDLOG_USE_STD_FORMAT +#include <string_view> +#endif + #ifdef SPDLOG_COMPILED_LIB # undef SPDLOG_HEADER_ONLY # if defined(_WIN32) && defined(SPDLOG_SHARED_LIB) @@ -36,14 +40,15 @@ #include <spdlog/fmt/fmt.h> -// backward compatibility with fmt versions older than 8 -#if FMT_VERSION >= 80000 -# define SPDLOG_FMT_RUNTIME(format_string) fmt::runtime(format_string) -# if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) -# include <spdlog/fmt/xchar.h> +#ifndef SPDLOG_USE_STD_FORMAT +# if FMT_VERSION >= 80000 // backward compatibility with fmt versions older than 8 +# define SPDLOG_FMT_RUNTIME(format_string) fmt::runtime(format_string) +# if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) +# include <spdlog/fmt/xchar.h> +# endif +# else +# define SPDLOG_FMT_RUNTIME(format_string) format_string # endif -#else -# define SPDLOG_FMT_RUNTIME(format_string) format_string #endif // visual studio upto 2013 does not support noexcept nor constexpr @@ -112,11 +117,39 @@ using log_clock = std::chrono::system_clock; using sink_ptr = std::shared_ptr<sinks::sink>; using sinks_init_list = std::initializer_list<sink_ptr>; using err_handler = std::function<void(const std::string &err_msg)>; +#ifdef SPDLOG_USE_STD_FORMAT +namespace fmt_lib = std; + +using string_view_t = std::string_view; +using wstring_view_t = std::wstring_view; +using memory_buf_t = std::string; +using wmemory_buf_t = std::wstring; + +template<typename... Args> +using format_string_t = std::string_view; + +template<typename... Args> +using wformat_string_t = std::wstring_view; + +template<class T, class Char = char> +struct is_convertible_to_basic_format_string + : std::integral_constant<bool, + std::is_convertible<T, std::basic_string_view<Char>>::value> +{}; +#else +namespace fmt_lib = fmt; + using string_view_t = fmt::basic_string_view<char>; using wstring_view_t = fmt::basic_string_view<wchar_t>; using memory_buf_t = fmt::basic_memory_buffer<char, 250>; using wmemory_buf_t = fmt::basic_memory_buffer<wchar_t, 250>; +template<typename... Args> +using format_string_t = fmt::format_string<Args...>; + +template<typename... Args> +using wformat_string_t = fmt::wformat_string<Args...>; + template<class T> using remove_cvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type; @@ -127,6 +160,7 @@ struct is_convertible_to_basic_format_string : std::integral_constant<bool, std::is_convertible<T, fmt::basic_string_view<Char>>::value || std::is_same<remove_cvref_t<T>, fmt::basic_runtime<Char>>::value> {}; +#endif #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT # ifndef _WIN32 diff --git a/include/spdlog/details/fmt_helper.h b/include/spdlog/details/fmt_helper.h index 01b2aa4d..31ed64fd 100644 --- a/include/spdlog/details/fmt_helper.h +++ b/include/spdlog/details/fmt_helper.h @@ -8,6 +8,11 @@ #include <spdlog/fmt/fmt.h> #include <spdlog/common.h> +#ifdef SPDLOG_USE_STD_FORMAT +#include <charconv> +#include <limits> +#endif + // Some fmt helpers to efficiently format and pad ints and strings namespace spdlog { namespace details { @@ -24,17 +29,63 @@ inline void append_string_view(spdlog::string_view_t view, memory_buf_t &dest) dest.append(buf_ptr, buf_ptr + view.size()); } +#ifdef SPDLOG_USE_STD_FORMAT +template<typename T> +inline void append_int(T n, memory_buf_t &dest) +{ + // Buffer should be large enough to hold all digits (digits10 + 1) and a sign + SPDLOG_CONSTEXPR auto BUF_SIZE = std::numeric_limits<T>::digits10 + 2; + char buf[BUF_SIZE]; + + auto [ptr, ec] = std::to_chars(buf, buf + BUF_SIZE, n, 10); + if (ec == std::errc()) + { + dest.append(buf, ptr); + } + else + { + throw_spdlog_ex("Failed to format int", static_cast<int>(ec)); + } +} +#else template<typename T> inline void append_int(T n, memory_buf_t &dest) { fmt::format_int i(n); dest.append(i.data(), i.data() + i.size()); } +#endif + +template<typename T> +SPDLOG_CONSTEXPR unsigned int count_digits_fallback(T n) +{ + // taken from fmt. + unsigned int count = 1; + for (;;) + { + // Integer division is slow so do it for a group of four digits instead + // of for every digit. The idea comes from the talk by Alexandrescu + // "Three Optimization Tips for C++". See speed-test for a comparison. + if (n < 10) + return count; + if (n < 100) + return count + 1; + if (n < 1000) + return count + 2; + if (n < 10000) + return count + 3; + n /= 10000u; + count += 4; + } +} template<typename T> inline unsigned int count_digits(T n) { using count_type = typename std::conditional<(sizeof(T) > sizeof(uint32_t)), uint64_t, uint32_t>::type; +#ifdef SPDLOG_USE_STD_FORMAT + return count_digits_fallback(static_cast<count_type>(n)); +#else return static_cast<unsigned int>(fmt:: // fmt 7.0.0 renamed the internal namespace to detail. // See: https://github.com/fmtlib/fmt/issues/1538 @@ -44,6 +95,7 @@ inline unsigned int count_digits(T n) detail #endif ::count_digits(static_cast<count_type>(n))); +#endif } inline void pad2(int n, memory_buf_t &dest) @@ -55,7 +107,7 @@ inline void pad2(int n, memory_buf_t &dest) } else // unlikely, but just in case, let fmt deal with it { - fmt::format_to(std::back_inserter(dest), SPDLOG_FMT_RUNTIME("{:02}"), n); + fmt_lib::format_to(std::back_inserter(dest), "{:02}", n); } } diff --git a/include/spdlog/details/os-inl.h b/include/spdlog/details/os-inl.h index 4602782c..9b2ef0d8 100644 --- a/include/spdlog/details/os-inl.h +++ b/include/spdlog/details/os-inl.h @@ -381,7 +381,11 @@ SPDLOG_INLINE std::string filename_to_str(const filename_t &filename) { memory_buf_t buf; wstr_to_utf8buf(filename, buf); +#ifdef SPDLOG_USE_STD_FORMAT + return buf; +#else return fmt::to_string(buf); +#endif } #else SPDLOG_INLINE std::string filename_to_str(const filename_t &filename) @@ -458,8 +462,12 @@ SPDLOG_INLINE void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target) return; } +#ifdef SPDLOG_USE_STD_FORMAT + int result_size = 0; +#else int result_size = static_cast<int>(target.capacity()); if ((wstr_size + 1) * 2 > result_size) +#endif { result_size = ::WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr_size, NULL, 0, NULL, NULL); } @@ -476,7 +484,7 @@ SPDLOG_INLINE void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target) } } - throw_spdlog_ex(fmt::format("WideCharToMultiByte failed. Last error: {}", ::GetLastError())); + throw_spdlog_ex(fmt_lib::format("WideCharToMultiByte failed. Last error: {}", ::GetLastError())); } SPDLOG_INLINE void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target) @@ -493,8 +501,12 @@ SPDLOG_INLINE void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target) return; } +#ifdef SPDLOG_USE_STD_FORMAT + int result_size = 0; +#else int result_size = static_cast<int>(target.capacity()); if (str_size + 1 > result_size) +#endif { result_size = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.data(), str_size, NULL, 0); } @@ -511,7 +523,7 @@ SPDLOG_INLINE void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target) } } - throw_spdlog_ex(fmt::format("MultiByteToWideChar failed. Last error: {}", ::GetLastError())); + throw_spdlog_ex(fmt_lib::format("MultiByteToWideChar failed. Last error: {}", ::GetLastError())); } #endif // (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32) diff --git a/include/spdlog/details/tcp_client-windows.h b/include/spdlog/details/tcp_client-windows.h index 45b69630..b331a500 100644 --- a/include/spdlog/details/tcp_client-windows.h +++ b/include/spdlog/details/tcp_client-windows.h @@ -38,10 +38,10 @@ class tcp_client static void throw_winsock_error_(const std::string &msg, int last_error) { char buf[512]; - ::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, last_error, + ::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, last_error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, (sizeof(buf) / sizeof(char)), NULL); - throw_spdlog_ex(fmt::format("tcp_sink - {}: {}", msg, buf)); + throw_spdlog_ex(fmt_lib::format("tcp_sink - {}: {}", msg, buf)); } public: diff --git a/include/spdlog/details/tcp_client.h b/include/spdlog/details/tcp_client.h index 706d7599..0daff0eb 100644 --- a/include/spdlog/details/tcp_client.h +++ b/include/spdlog/details/tcp_client.h @@ -67,8 +67,7 @@ public: auto rv = ::getaddrinfo(host.c_str(), port_str.c_str(), &hints, &addrinfo_result); if (rv != 0) { - auto msg = fmt::format("::getaddrinfo failed: {}", gai_strerror(rv)); - throw_spdlog_ex(msg); + throw_spdlog_ex(fmt_lib::format("::getaddrinfo failed: {}", gai_strerror(rv))); } // Try each address until we successfully connect(2). diff --git a/include/spdlog/details/udp_client-windows.h b/include/spdlog/details/udp_client-windows.h index 5cc3dd88..372efa6d 100644 --- a/include/spdlog/details/udp_client-windows.h +++ b/include/spdlog/details/udp_client-windows.h @@ -40,10 +40,10 @@ class udp_client static void throw_winsock_error_(const std::string &msg, int last_error) { char buf[512]; - ::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, last_error, + ::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, last_error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, (sizeof(buf) / sizeof(char)), NULL); - throw_spdlog_ex(fmt::format("udp_sink - {}: {}", msg, buf)); + throw_spdlog_ex(fmt_lib::format("udp_sink - {}: {}", msg, buf)); } void cleanup_() diff --git a/include/spdlog/fmt/bin_to_hex.h b/include/spdlog/fmt/bin_to_hex.h index 0b6c3e96..62807d63 100644 --- a/include/spdlog/fmt/bin_to_hex.h +++ b/include/spdlog/fmt/bin_to_hex.h @@ -74,12 +74,8 @@ inline details::dump_info<It> to_hex(const It range_begin, const It range_end, s return details::dump_info<It>(range_begin, range_end, size_per_line); } -} // namespace spdlog - -namespace fmt { - template<typename T> -struct formatter<spdlog::details::dump_info<T>> +struct fmt_lib::formatter<spdlog::details::dump_info<T>, char> { const char delimiter = ' '; bool put_newlines = true; @@ -90,7 +86,7 @@ struct formatter<spdlog::details::dump_info<T>> // parse the format string flags template<typename ParseContext> - FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) + SPDLOG_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { auto it = ctx.begin(); while (it != ctx.end() && *it != '}') @@ -210,8 +206,8 @@ struct formatter<spdlog::details::dump_info<T>> if (put_positions) { - fmt::format_to(inserter, "{:04X}: ", pos); + fmt_lib::format_to(inserter, "{:04X}: ", pos); } } }; -} // namespace fmt +} // namespace spdlog diff --git a/include/spdlog/fmt/chrono.h b/include/spdlog/fmt/chrono.h index a0544bca..83fad2ff 100644 --- a/include/spdlog/fmt/chrono.h +++ b/include/spdlog/fmt/chrono.h @@ -8,13 +8,15 @@ // include bundled or external copy of fmtlib's chrono support // -#if !defined(SPDLOG_FMT_EXTERNAL) -# ifdef SPDLOG_HEADER_ONLY -# ifndef FMT_HEADER_ONLY -# define FMT_HEADER_ONLY +#if !defined(SPDLOG_USE_STD_FORMAT) +# if !defined(SPDLOG_FMT_EXTERNAL) +# ifdef SPDLOG_HEADER_ONLY +# ifndef FMT_HEADER_ONLY +# define FMT_HEADER_ONLY +# endif # endif +# include <spdlog/fmt/bundled/chrono.h> +# else +# include <fmt/chrono.h> # endif -# include <spdlog/fmt/bundled/chrono.h> -#else -# include <fmt/chrono.h> #endif diff --git a/include/spdlog/fmt/compile.h b/include/spdlog/fmt/compile.h index 6f345935..906e9f57 100644 --- a/include/spdlog/fmt/compile.h +++ b/include/spdlog/fmt/compile.h @@ -5,16 +5,18 @@ #pragma once // -// include bundled or external copy of fmtlib's ostream support +// include bundled or external copy of fmtlib's compile-time support // -#if !defined(SPDLOG_FMT_EXTERNAL) -# ifdef SPDLOG_HEADER_ONLY -# ifndef FMT_HEADER_ONLY -# define FMT_HEADER_ONLY +#if !defined(SPDLOG_USE_STD_FORMAT) +# if !defined(SPDLOG_FMT_EXTERNAL) +# ifdef SPDLOG_HEADER_ONLY +# ifndef FMT_HEADER_ONLY +# define FMT_HEADER_ONLY +# endif # endif +# include <spdlog/fmt/bundled/compile.h> +# else +# include <fmt/compile.h> # endif -# include <spdlog/fmt/bundled/compile.h> -#else -# include <fmt/compile.h> #endif diff --git a/include/spdlog/fmt/fmt.h b/include/spdlog/fmt/fmt.h index 7aaeed81..fa4a2a84 100644 --- a/include/spdlog/fmt/fmt.h +++ b/include/spdlog/fmt/fmt.h @@ -10,7 +10,9 @@ // By default spdlog include its own copy. // -#if !defined(SPDLOG_FMT_EXTERNAL) +#if defined(SPDLOG_USE_STD_FORMAT) // SPDLOG_USE_STD_FORMAT is defined - use std::format +# include <format> +#elif !defined(SPDLOG_FMT_EXTERNAL) # if !defined(SPDLOG_COMPILED_LIB) && !defined(FMT_HEADER_ONLY) # define FMT_HEADER_ONLY # endif diff --git a/include/spdlog/fmt/ostr.h b/include/spdlog/fmt/ostr.h index 9d8efe38..75880341 100644 --- a/include/spdlog/fmt/ostr.h +++ b/include/spdlog/fmt/ostr.h @@ -8,13 +8,15 @@ // include bundled or external copy of fmtlib's ostream support // -#if !defined(SPDLOG_FMT_EXTERNAL) -# ifdef SPDLOG_HEADER_ONLY -# ifndef FMT_HEADER_ONLY -# define FMT_HEADER_ONLY +#if !defined(SPDLOG_USE_STD_FORMAT) +# if !defined(SPDLOG_FMT_EXTERNAL) +# ifdef SPDLOG_HEADER_ONLY +# ifndef FMT_HEADER_ONLY +# define FMT_HEADER_ONLY +# endif # endif +# include <spdlog/fmt/bundled/ostream.h> +# else +# include <fmt/ostream.h> # endif -# include <spdlog/fmt/bundled/ostream.h> -#else -# include <fmt/ostream.h> #endif diff --git a/include/spdlog/fmt/xchar.h b/include/spdlog/fmt/xchar.h index 616d8f5b..9a766e5a 100644 --- a/include/spdlog/fmt/xchar.h +++ b/include/spdlog/fmt/xchar.h @@ -5,16 +5,18 @@ #pragma once // -// include bundled or external copy of fmtlib's ostream support +// include bundled or external copy of fmtlib's xchar support // -#if !defined(SPDLOG_FMT_EXTERNAL) -# ifdef SPDLOG_HEADER_ONLY -# ifndef FMT_HEADER_ONLY -# define FMT_HEADER_ONLY +#if !defined(SPDLOG_USE_STD_FORMAT) +# if !defined(SPDLOG_FMT_EXTERNAL) +# ifdef SPDLOG_HEADER_ONLY +# ifndef FMT_HEADER_ONLY +# define FMT_HEADER_ONLY +# endif # endif +# include <spdlog/fmt/bundled/xchar.h> +# else +# include <fmt/xchar.h> # endif -# include <spdlog/fmt/bundled/xchar.h> -#else -# include <fmt/xchar.h> #endif diff --git a/include/spdlog/logger.h b/include/spdlog/logger.h index eea0afc2..9adfec97 100644 --- a/include/spdlog/logger.h +++ b/include/spdlog/logger.h @@ -33,7 +33,7 @@ { \ if(location.filename) \ { \ - err_handler_(fmt::format("{} [{}({})]", ex.what(), location.filename, location.line)); \ + err_handler_(fmt_lib::format("{} [{}({})]", ex.what(), location.filename, location.line)); \ } \ else \ { \ @@ -85,13 +85,13 @@ public: void swap(spdlog::logger &other) SPDLOG_NOEXCEPT; template<typename... Args> - void log(source_loc loc, level::level_enum lvl, fmt::format_string<Args...> fmt, Args &&...args) + void log(source_loc loc, level::level_enum lvl, format_string_t<Args...> fmt, Args &&...args) { log_(loc, lvl, fmt, std::forward<Args>(args)...); } template<typename... Args> - void log(level::level_enum lvl, fmt::format_string<Args...> fmt, Args &&...args) + void log(level::level_enum lvl, format_string_t<Args...> fmt, Args &&...args) { log(source_loc{}, lvl, fmt, std::forward<Args>(args)...); } @@ -102,14 +102,7 @@ public: log(source_loc{}, lvl, msg); } - // T can be statically converted to string_view - template<class T, typename std::enable_if<std::is_convertible<const T &, spdlog::string_view_t>::value, int>::type = 0> - void log(source_loc loc, level::level_enum lvl, const T &msg) - { - log(loc, lvl, string_view_t{msg}); - } - - // T cannot be statically converted to format string (including string_view) + // T cannot be statically converted to format string (including string_view/wstring_view) template<class T, typename std::enable_if<!is_convertible_to_any_format_string<const T &>::value, int>::type = 0> void log(source_loc loc, level::level_enum lvl, const T &msg) { @@ -148,86 +141,121 @@ public: } template<typename... Args> - void trace(fmt::format_string<Args...> fmt, Args &&...args) + void trace(format_string_t<Args...> fmt, Args &&...args) { log(level::trace, fmt, std::forward<Args>(args)...); } template<typename... Args> - void debug(fmt::format_string<Args...> fmt, Args &&...args) + void debug(format_string_t<Args...> fmt, Args &&...args) { log(level::debug, fmt, std::forward<Args>(args)...); } template<typename... Args> - void info(fmt::format_string<Args...> fmt, Args &&...args) + void info(format_string_t<Args...> fmt, Args &&...args) { log(level::info, fmt, std::forward<Args>(args)...); } template<typename... Args> - void warn(fmt::format_string<Args...> fmt, Args &&...args) + void warn(format_string_t<Args...> fmt, Args &&...args) { log(level::warn, fmt, std::forward<Args>(args)...); } template<typename... Args> - void error(fmt::format_string<Args...> fmt, Args &&...args) + void error(format_string_t<Args...> fmt, Args &&...args) { log(level::err, fmt, std::forward<Args>(args)...); } template<typename... Args> - void critical(fmt::format_string<Args...> fmt, Args &&...args) + void critical(format_string_t<Args...> fmt, Args &&...args) { log(level::critical, fmt, std::forward<Args>(args)...); } #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT template<typename... Args> - void log(level::level_enum lvl, fmt::wformat_string<Args...> fmt, Args &&...args) + void log(source_loc loc, level::level_enum lvl, wformat_string_t<Args...> fmt, Args &&...args) { - log(source_loc{}, lvl, fmt, std::forward<Args>(args)...); + log_(loc, lvl, fmt, std::forward<Args>(args)...); } template<typename... Args> - void log(source_loc loc, level::level_enum lvl, fmt::wformat_string<Args...> fmt, Args &&...args) + void log(level::level_enum lvl, wformat_string_t<Args...> fmt, Args &&...args) { - log_(loc, lvl, fmt, std::forward<Args>(args)...); + log(source_loc{}, lvl, fmt, std::forward<Args>(args)...); + } + + void log(log_clock::time_point log_time, source_loc loc, level::level_enum lvl, wstring_view_t msg) + { + bool log_enabled = should_log(lvl); + bool traceback_enabled = tracer_.enabled(); + if (!log_enabled && !traceback_enabled) + { + return; + } + + memory_buf_t buf; + details::os::wstr_to_utf8buf(wstring_view_t(msg.data(), msg.size()), buf); + details::log_msg log_msg(log_time, loc, name_, lvl, string_view_t(buf.data(), buf.size())); + log_it_(log_msg, log_enabled, traceback_enabled); + } + + void log(source_loc loc, level::level_enum lvl, wstring_view_t msg) + { + bool log_enabled = should_log(lvl); + bool traceback_enabled = tracer_.enabled(); + if (!log_enabled && !traceback_enabled) + { + return; + } + + memory_buf_t buf; + details::os::wstr_to_utf8buf(wstring_view_t(msg.data(), msg.size()), buf); + details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size())); + log_it_(log_msg, log_enabled, traceback_enabled); + } + + void log(level::level_enum lvl, wstring_view_t msg) + { + log(source_loc{}, lvl, msg); } template<typename... Args> - void trace(fmt::wformat_string<Args...> fmt, Args &&...args) + void trace(wformat_string_t<Args...> fmt, Args &&...args) { log(level::trace, fmt, std::forward<Args>(args)...); } template<typename... Args> - void debug(fmt::wformat_string<Args...> fmt, Args &&...args) + void debug(wformat_string_t<Args...> fmt, Args &&...args) { log(level::debug, fmt, std::forward<Args>(args)...); } template<typename... Args> - void info(fmt::wformat_string<Args...> fmt, Args &&...args) + void info(wformat_string_t<Args...> fmt, Args &&...args) { log(level::info, fmt, std::forward<Args>(args)...); } template<typename... Args> - void warn(fmt::wformat_string<Args...> fmt, Args &&...args) + void warn(wformat_string_t<Args...> fmt, Args &&...args) { log(level::warn, fmt, std::forward<Args>(args)...); } template<typename... Args> - void error(fmt::wformat_string<Args...> fmt, Args &&...args) + void error(wformat_string_t<Args...> fmt, Args &&...args) { log(level::err, fmt, std::forward<Args>(args)...); } template<typename... Args> - void critical(fmt::wformat_string<Args...> fmt, Args &&...args) + void critical(wformat_string_t<Args...> fmt, Args &&...args) { log(level::critical, fmt, std::forward<Args>(args)...); } @@ -335,8 +363,12 @@ protected: } SPDLOG_TRY { +#ifdef SPDLOG_USE_STD_FORMAT + memory_buf_t buf = std::vformat(fmt, std::make_format_args(std::forward<Args...>(args)...)); +#else memory_buf_t buf; - fmt::detail::vformat_to(buf, fmt, fmt::make_format_args(args...)); + fmt::detail::vformat_to(buf, fmt, fmt::make_format_args(std::forward<Args...>(args)...)); +#endif details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size())); log_it_(log_msg, log_enabled, traceback_enabled); } @@ -356,8 +388,13 @@ protected: SPDLOG_TRY { // format to wmemory_buffer and convert to utf8 - fmt::wmemory_buffer wbuf; - fmt::detail::vformat_to(wbuf, fmt, fmt::make_format_args<fmt::wformat_context>(args...)); + ; +#ifdef SPDLOG_USE_STD_FORMAT + wmemory_buf_t wbuf = std::vformat(fmt, std::make_wformat_args(std::forward<Args...>(args)...)); +#else + wmemory_buf_t wbuf; + fmt::detail::vformat_to(wbuf, fmt, fmt::make_format_args<fmt::wformat_context>(std::forward<Args...>(args)...)); +#endif memory_buf_t buf; details::os::wstr_to_utf8buf(wstring_view_t(wbuf.data(), wbuf.size()), buf); details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size())); diff --git a/include/spdlog/sinks/daily_file_sink.h b/include/spdlog/sinks/daily_file_sink.h index fc552398..cf83800a 100644 --- a/include/spdlog/sinks/daily_file_sink.h +++ b/include/spdlog/sinks/daily_file_sink.h @@ -32,7 +32,7 @@ struct daily_filename_calculator { filename_t basename, ext; std::tie(basename, ext) = details::file_helper::split_by_extension(filename); - return fmt::format( + return fmt_lib::format( SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}{}"), basename, now_tm.tm_year + 1900, now_tm.tm_mon + 1, now_tm.tm_mday, ext); } }; @@ -49,8 +49,10 @@ struct daily_filename_format_calculator static filename_t calc_filename(const filename_t &filename, const tm &now_tm) { // generate fmt datetime format string, e.g. {:%Y-%m-%d}. - filename_t fmt_filename = fmt::format(SPDLOG_FILENAME_T("{{:{}}}"), filename); -#if defined(_MSC_VER) && defined(SPDLOG_WCHAR_FILENAMES) // for some reason msvc doesnt allow fmt::runtime(..) with wchar here + filename_t fmt_filename = fmt_lib::format(SPDLOG_FILENAME_T("{{:{}}}"), filename); +#if defined(SPDLOG_USE_STD_FORMAT) + return std::vformat(fmt_filename, std::make_format_args(now_tm)); +#elif defined(_MSC_VER) && defined(SPDLOG_WCHAR_FILENAMES) // for some reason msvc doesnt allow fmt::runtime(..) with wchar here return fmt::format(fmt_filename, now_tm); #else return fmt::format(SPDLOG_FMT_RUNTIME(fmt_filename), now_tm); diff --git a/include/spdlog/sinks/hourly_file_sink.h b/include/spdlog/sinks/hourly_file_sink.h index 653faceb..71b5a1b4 100644 --- a/include/spdlog/sinks/hourly_file_sink.h +++ b/include/spdlog/sinks/hourly_file_sink.h @@ -31,7 +31,7 @@ struct hourly_filename_calculator { filename_t basename, ext; std::tie(basename, ext) = details::file_helper::split_by_extension(filename); - return fmt::format(SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}_{:02d}{}"), basename, now_tm.tm_year + 1900, now_tm.tm_mon + 1, + return fmt_lib::format(SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}_{:02d}{}"), basename, now_tm.tm_year + 1900, now_tm.tm_mon + 1, now_tm.tm_mday, now_tm.tm_hour, ext); } }; diff --git a/include/spdlog/sinks/msvc_sink.h b/include/spdlog/sinks/msvc_sink.h index 2ac4a965..76ec40a0 100644 --- a/include/spdlog/sinks/msvc_sink.h +++ b/include/spdlog/sinks/msvc_sink.h @@ -30,7 +30,11 @@ protected: { memory_buf_t formatted; base_sink<Mutex>::formatter_->format(msg, formatted); +#ifdef SPDLOG_USE_STD_FORMAT + OutputDebugStringA(formatted.c_str()); +#else OutputDebugStringA(fmt::to_string(formatted).c_str()); +#endif } void flush_() override {} diff --git a/include/spdlog/sinks/ringbuffer_sink.h b/include/spdlog/sinks/ringbuffer_sink.h index 1ee3f691..5836d98b 100644 --- a/include/spdlog/sinks/ringbuffer_sink.h +++ b/include/spdlog/sinks/ringbuffer_sink.h @@ -50,7 +50,11 @@ public: { memory_buf_t formatted; base_sink<Mutex>::formatter_->format(q_.at(i), formatted); +#ifdef SPDLOG_USE_STD_FORMAT + ret.push_back(std::move(formatted)); +#else ret.push_back(fmt::to_string(formatted)); +#endif } return ret; } diff --git a/include/spdlog/sinks/rotating_file_sink-inl.h b/include/spdlog/sinks/rotating_file_sink-inl.h index 2e3087af..87e80593 100644 --- a/include/spdlog/sinks/rotating_file_sink-inl.h +++ b/include/spdlog/sinks/rotating_file_sink-inl.h @@ -51,7 +51,7 @@ SPDLOG_INLINE filename_t rotating_file_sink<Mutex>::calc_filename(const filename filename_t basename, ext; std::tie(basename, ext) = details::file_helper::split_by_extension(filename); - return fmt::format(SPDLOG_FILENAME_T("{}.{}{}"), basename, index, ext); + return fmt_lib::format(SPDLOG_FILENAME_T("{}.{}{}"), basename, index, ext); } template<typename Mutex> diff --git a/include/spdlog/sinks/win_eventlog_sink.h b/include/spdlog/sinks/win_eventlog_sink.h index 5e70599a..202c79f8 100644 --- a/include/spdlog/sinks/win_eventlog_sink.h +++ b/include/spdlog/sinks/win_eventlog_sink.h @@ -47,6 +47,24 @@ namespace win_eventlog { namespace internal { +struct local_alloc_t +{ + HLOCAL hlocal_; + + SPDLOG_CONSTEXPR local_alloc_t() SPDLOG_NOEXCEPT : hlocal_(nullptr) {} + + local_alloc_t(local_alloc_t const&) = delete; + local_alloc_t& operator=(local_alloc_t const&) = delete; + + ~local_alloc_t() SPDLOG_NOEXCEPT + { + if (hlocal_) + { + LocalFree(hlocal_); + } + } +}; + /** Windows error */ struct win32_error : public spdlog_ex { @@ -55,22 +73,17 @@ struct win32_error : public spdlog_ex { std::string system_message; - LPSTR format_message_result{}; + local_alloc_t format_message_result{}; auto format_message_succeeded = ::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, - error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&format_message_result, 0, nullptr); - - if (format_message_succeeded && format_message_result) - { - system_message = fmt::format(" ({})", format_message_result); - } + error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&format_message_result.hlocal_, 0, nullptr); - if (format_message_result) + if (format_message_succeeded && format_message_result.hlocal_) { - LocalFree((HLOCAL)format_message_result); + system_message = fmt_lib::format(" ({})", (LPSTR)format_message_result.hlocal_); } - return fmt::format("{}: {}{}", user_message, error_code, system_message); + return fmt_lib::format("{}: {}{}", user_message, error_code, system_message); } explicit win32_error(std::string const &func_name, DWORD error = GetLastError()) diff --git a/include/spdlog/spdlog.h b/include/spdlog/spdlog.h index 812896da..327a0ebe 100644 --- a/include/spdlog/spdlog.h +++ b/include/spdlog/spdlog.h @@ -128,49 +128,49 @@ SPDLOG_API spdlog::logger *default_logger_raw(); SPDLOG_API void set_default_logger(std::shared_ptr<spdlog::logger> default_logger); template<typename... Args> -inline void log(source_loc source, level::level_enum lvl, fmt::format_string<Args...> fmt, Args &&...args) +inline void log(source_loc source, level::level_enum lvl, format_string_t<Args...> fmt, Args &&...args) { default_logger_raw()->log(source, lvl, fmt, std::forward<Args>(args)...); } template<typename... Args> -inline void log(level::level_enum lvl, fmt::format_string<Args...> fmt, Args &&...args) +inline void log(level::level_enum lvl, format_string_t<Args...> fmt, Args &&...args) { default_logger_raw()->log(source_loc{}, lvl, fmt, std::forward<Args>(args)...); } template<typename... Args> -inline void trace(fmt::format_string<Args...> fmt, Args &&...args) +inline void trace(format_string_t<Args...> fmt, Args &&...args) { default_logger_raw()->trace(fmt, std::forward<Args>(args)...); } template<typename... Args> -inline void debug(fmt::format_string<Args...> fmt, Args &&...args) +inline void debug(format_string_t<Args...> fmt, Args &&...args) { default_logger_raw()->debug(fmt, std::forward<Args>(args)...); } template<typename... Args> -inline void info(fmt::format_string<Args...> fmt, Args &&...args) +inline void info(format_string_t<Args...> fmt, Args &&...args) { default_logger_raw()->info(fmt, std::forward<Args>(args)...); } template<typename... Args> -inline void warn(fmt::format_string<Args...> fmt, Args &&...args) +inline void warn(format_string_t<Args...> fmt, Args &&...args) { default_logger_raw()->warn(fmt, std::forward<Args>(args)...); } template<typename... Args> -inline void error(fmt::format_string<Args...> fmt, Args &&...args) +inline void error(format_string_t<Args...> fmt, Args &&...args) { default_logger_raw()->error(fmt, std::forward<Args>(args)...); } template<typename... Args> -inline void critical(fmt::format_string<Args...> fmt, Args &&...args) +inline void critical(format_string_t<Args...> fmt, Args &&...args) { default_logger_raw()->critical(fmt, std::forward<Args>(args)...); } @@ -189,49 +189,49 @@ inline void log(level::level_enum lvl, const T &msg) #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT template<typename... Args> -inline void log(source_loc source, level::level_enum lvl, fmt::wformat_string<Args...> fmt, Args &&...args) +inline void log(source_loc source, level::level_enum lvl, wformat_string_t<Args...> fmt, Args &&...args) { default_logger_raw()->log(source, lvl, fmt, std::forward<Args>(args)...); } template<typename... Args> -inline void log(level::level_enum lvl, fmt::wformat_string<Args...> fmt, Args &&...args) +inline void log(level::level_enum lvl, wformat_string_t<Args...> fmt, Args &&...args) { default_logger_raw()->log(source_loc{}, lvl, fmt, std::forward<Args>(args)...); } template<typename... Args> -inline void trace(fmt::wformat_string<Args...> fmt, Args &&...args) +inline void trace(wformat_string_t<Args...> fmt, Args &&...args) { default_logger_raw()->trace(fmt, std::forward<Args>(args)...); } template<typename... Args> -inline void debug(fmt::wformat_string<Args...> fmt, Args &&...args) +inline void debug(wformat_string_t<Args...> fmt, Args &&...args) { default_logger_raw()->debug(fmt, std::forward<Args>(args)...); } template<typename... Args> -inline void info(fmt::wformat_string<Args...> fmt, Args &&...args) +inline void info(wformat_string_t<Args...> fmt, Args &&...args) { default_logger_raw()->info(fmt, std::forward<Args>(args)...); } template<typename... Args> -inline void warn(fmt::wformat_string<Args...> fmt, Args &&...args) +inline void warn(wformat_string_t<Args...> fmt, Args &&...args) { default_logger_raw()->warn(fmt, std::forward<Args>(args)...); } template<typename... Args> -inline void error(fmt::wformat_string<Args...> fmt, Args &&...args) +inline void error(wformat_string_t<Args...> fmt, Args &&...args) { default_logger_raw()->error(fmt, std::forward<Args>(args)...); } template<typename... Args> -inline void critical(fmt::wformat_string<Args...> fmt, Args &&...args) +inline void critical(wformat_string_t<Args...> fmt, Args &&...args) { default_logger_raw()->critical(fmt, std::forward<Args>(args)...); } diff --git a/include/spdlog/tweakme.h b/include/spdlog/tweakme.h index 24361f30..08f0f4e5 100644 --- a/include/spdlog/tweakme.h +++ b/include/spdlog/tweakme.h @@ -75,6 +75,13 @@ /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// +// Uncomment to use C++20 std::format instead of fmt. This removes compile +// time checking of format strings, but doesn't depend on the fmt library. +// +// #define SPDLOG_USE_STD_FORMAT +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// // Uncomment to enable wchar_t support (convert to utf8) // // #define SPDLOG_WCHAR_TO_UTF8_SUPPORT |