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