You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

453 lines
15 KiB

5 months ago
  1. // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
  2. // Distributed under the MIT License (http://opensource.org/licenses/MIT)
  3. #pragma once
  4. // Thread safe logger (except for set_error_handler())
  5. // Has name, log level, vector of std::shared sink pointers and formatter
  6. // Upon each log write the logger:
  7. // 1. Checks if its log level is enough to log the message and if yes:
  8. // 2. Call the underlying sinks to do the job.
  9. // 3. Each sink use its own private copy of a formatter to format the message
  10. // and send to its destination.
  11. //
  12. // The use of private formatter per sink provides the opportunity to cache some
  13. // formatted data, and support for different format per sink.
  14. #include <spdlog/common.h>
  15. #include <spdlog/details/log_msg.h>
  16. #include <spdlog/details/backtracer.h>
  17. #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
  18. # ifndef _WIN32
  19. # error SPDLOG_WCHAR_TO_UTF8_SUPPORT only supported on windows
  20. # endif
  21. # include <spdlog/details/os.h>
  22. #endif
  23. #include <vector>
  24. #ifndef SPDLOG_NO_EXCEPTIONS
  25. # define SPDLOG_LOGGER_CATCH(location) \
  26. catch (const std::exception &ex) \
  27. { \
  28. if (location.filename) \
  29. { \
  30. err_handler_(fmt_lib::format(SPDLOG_FMT_STRING("{} [{}({})]"), ex.what(), location.filename, location.line)); \
  31. } \
  32. else \
  33. { \
  34. err_handler_(ex.what()); \
  35. } \
  36. } \
  37. catch (...) \
  38. { \
  39. err_handler_("Rethrowing unknown exception in logger"); \
  40. throw; \
  41. }
  42. #else
  43. # define SPDLOG_LOGGER_CATCH(location)
  44. #endif
  45. namespace spdlog {
  46. class SPDLOG_API logger
  47. {
  48. public:
  49. // Empty logger
  50. explicit logger(std::string name)
  51. : name_(std::move(name))
  52. , sinks_()
  53. {}
  54. // Logger with range on sinks
  55. template<typename It>
  56. logger(std::string name, It begin, It end)
  57. : name_(std::move(name))
  58. , sinks_(begin, end)
  59. {}
  60. // Logger with single sink
  61. logger(std::string name, sink_ptr single_sink)
  62. : logger(std::move(name), {std::move(single_sink)})
  63. {}
  64. // Logger with sinks init list
  65. logger(std::string name, sinks_init_list sinks)
  66. : logger(std::move(name), sinks.begin(), sinks.end())
  67. {}
  68. virtual ~logger() = default;
  69. logger(const logger &other);
  70. logger(logger &&other) SPDLOG_NOEXCEPT;
  71. logger &operator=(logger other) SPDLOG_NOEXCEPT;
  72. void swap(spdlog::logger &other) SPDLOG_NOEXCEPT;
  73. template<typename... Args>
  74. void log(source_loc loc, level::level_enum lvl, format_string_t<Args...> fmt, Args &&... args)
  75. {
  76. log_(loc, lvl, fmt, std::forward<Args>(args)...);
  77. }
  78. template<typename... Args>
  79. void log(level::level_enum lvl, format_string_t<Args...> fmt, Args &&... args)
  80. {
  81. log(source_loc{}, lvl, fmt, std::forward<Args>(args)...);
  82. }
  83. template<typename T>
  84. void log(level::level_enum lvl, const T &msg)
  85. {
  86. log(source_loc{}, lvl, msg);
  87. }
  88. // T cannot be statically converted to format string (including string_view/wstring_view)
  89. template<class T, typename std::enable_if<!is_convertible_to_any_format_string<const T &>::value, int>::type = 0>
  90. void log(source_loc loc, level::level_enum lvl, const T &msg)
  91. {
  92. log(loc, lvl, "{}", msg);
  93. }
  94. void log(log_clock::time_point log_time, source_loc loc, level::level_enum lvl, string_view_t msg)
  95. {
  96. bool log_enabled = should_log(lvl);
  97. bool traceback_enabled = tracer_.enabled();
  98. if (!log_enabled && !traceback_enabled)
  99. {
  100. return;
  101. }
  102. details::log_msg log_msg(log_time, loc, name_, lvl, msg);
  103. log_it_(log_msg, log_enabled, traceback_enabled);
  104. }
  105. void log(source_loc loc, level::level_enum lvl, string_view_t msg)
  106. {
  107. bool log_enabled = should_log(lvl);
  108. bool traceback_enabled = tracer_.enabled();
  109. if (!log_enabled && !traceback_enabled)
  110. {
  111. return;
  112. }
  113. details::log_msg log_msg(loc, name_, lvl, msg);
  114. log_it_(log_msg, log_enabled, traceback_enabled);
  115. }
  116. void log(level::level_enum lvl, string_view_t msg)
  117. {
  118. log(source_loc{}, lvl, msg);
  119. }
  120. template<typename... Args>
  121. void trace(format_string_t<Args...> fmt, Args &&... args)
  122. {
  123. log(level::trace, fmt, std::forward<Args>(args)...);
  124. }
  125. template<typename... Args>
  126. void debug(format_string_t<Args...> fmt, Args &&... args)
  127. {
  128. log(level::debug, fmt, std::forward<Args>(args)...);
  129. }
  130. template<typename... Args>
  131. void info(format_string_t<Args...> fmt, Args &&... args)
  132. {
  133. log(level::info, fmt, std::forward<Args>(args)...);
  134. }
  135. template<typename... Args>
  136. void warn(format_string_t<Args...> fmt, Args &&... args)
  137. {
  138. log(level::warn, fmt, std::forward<Args>(args)...);
  139. }
  140. template<typename... Args>
  141. void error(format_string_t<Args...> fmt, Args &&... args)
  142. {
  143. log(level::err, fmt, std::forward<Args>(args)...);
  144. }
  145. template<typename... Args>
  146. void critical(format_string_t<Args...> fmt, Args &&... args)
  147. {
  148. log(level::critical, fmt, std::forward<Args>(args)...);
  149. }
  150. #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
  151. template<typename... Args>
  152. void log(source_loc loc, level::level_enum lvl, wformat_string_t<Args...> fmt, Args &&... args)
  153. {
  154. log_(loc, lvl, fmt, std::forward<Args>(args)...);
  155. }
  156. template<typename... Args>
  157. void log(level::level_enum lvl, wformat_string_t<Args...> fmt, Args &&... args)
  158. {
  159. log(source_loc{}, lvl, fmt, std::forward<Args>(args)...);
  160. }
  161. void log(log_clock::time_point log_time, source_loc loc, level::level_enum lvl, wstring_view_t msg)
  162. {
  163. bool log_enabled = should_log(lvl);
  164. bool traceback_enabled = tracer_.enabled();
  165. if (!log_enabled && !traceback_enabled)
  166. {
  167. return;
  168. }
  169. memory_buf_t buf;
  170. details::os::wstr_to_utf8buf(wstring_view_t(msg.data(), msg.size()), buf);
  171. details::log_msg log_msg(log_time, loc, name_, lvl, string_view_t(buf.data(), buf.size()));
  172. log_it_(log_msg, log_enabled, traceback_enabled);
  173. }
  174. void log(source_loc loc, level::level_enum lvl, wstring_view_t msg)
  175. {
  176. bool log_enabled = should_log(lvl);
  177. bool traceback_enabled = tracer_.enabled();
  178. if (!log_enabled && !traceback_enabled)
  179. {
  180. return;
  181. }
  182. memory_buf_t buf;
  183. details::os::wstr_to_utf8buf(wstring_view_t(msg.data(), msg.size()), buf);
  184. details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()));
  185. log_it_(log_msg, log_enabled, traceback_enabled);
  186. }
  187. void log(level::level_enum lvl, wstring_view_t msg)
  188. {
  189. log(source_loc{}, lvl, msg);
  190. }
  191. template<typename... Args>
  192. void trace(wformat_string_t<Args...> fmt, Args &&... args)
  193. {
  194. log(level::trace, fmt, std::forward<Args>(args)...);
  195. }
  196. template<typename... Args>
  197. void debug(wformat_string_t<Args...> fmt, Args &&... args)
  198. {
  199. log(level::debug, fmt, std::forward<Args>(args)...);
  200. }
  201. template<typename... Args>
  202. void info(wformat_string_t<Args...> fmt, Args &&... args)
  203. {
  204. log(level::info, fmt, std::forward<Args>(args)...);
  205. }
  206. template<typename... Args>
  207. void warn(wformat_string_t<Args...> fmt, Args &&... args)
  208. {
  209. log(level::warn, fmt, std::forward<Args>(args)...);
  210. }
  211. template<typename... Args>
  212. void error(wformat_string_t<Args...> fmt, Args &&... args)
  213. {
  214. log(level::err, fmt, std::forward<Args>(args)...);
  215. }
  216. template<typename... Args>
  217. void critical(wformat_string_t<Args...> fmt, Args &&... args)
  218. {
  219. log(level::critical, fmt, std::forward<Args>(args)...);
  220. }
  221. #endif
  222. template<typename T>
  223. void trace(const T &msg)
  224. {
  225. log(level::trace, msg);
  226. }
  227. template<typename T>
  228. void debug(const T &msg)
  229. {
  230. log(level::debug, msg);
  231. }
  232. template<typename T>
  233. void info(const T &msg)
  234. {
  235. log(level::info, msg);
  236. }
  237. template<typename T>
  238. void warn(const T &msg)
  239. {
  240. log(level::warn, msg);
  241. }
  242. template<typename T>
  243. void error(const T &msg)
  244. {
  245. log(level::err, msg);
  246. }
  247. template<typename T>
  248. void critical(const T &msg)
  249. {
  250. log(level::critical, msg);
  251. }
  252. // return true logging is enabled for the given level.
  253. bool should_log(level::level_enum msg_level) const
  254. {
  255. return msg_level >= level_.load(std::memory_order_relaxed);
  256. }
  257. // return true if backtrace logging is enabled.
  258. bool should_backtrace() const
  259. {
  260. return tracer_.enabled();
  261. }
  262. void set_level(level::level_enum log_level);
  263. level::level_enum level() const;
  264. const std::string &name() const;
  265. // set formatting for the sinks in this logger.
  266. // each sink will get a separate instance of the formatter object.
  267. void set_formatter(std::unique_ptr<formatter> f);
  268. // set formatting for the sinks in this logger.
  269. // equivalent to
  270. // set_formatter(make_unique<pattern_formatter>(pattern, time_type))
  271. // Note: each sink will get a new instance of a formatter object, replacing the old one.
  272. void set_pattern(std::string pattern, pattern_time_type time_type = pattern_time_type::local);
  273. // backtrace support.
  274. // efficiently store all debug/trace messages in a circular buffer until needed for debugging.
  275. void enable_backtrace(size_t n_messages);
  276. void disable_backtrace();
  277. void dump_backtrace();
  278. // flush functions
  279. void flush();
  280. void flush_on(level::level_enum log_level);
  281. level::level_enum flush_level() const;
  282. // sinks
  283. const std::vector<sink_ptr> &sinks() const;
  284. std::vector<sink_ptr> &sinks();
  285. // error handler
  286. void set_error_handler(err_handler);
  287. // create new logger with same sinks and configuration.
  288. virtual std::shared_ptr<logger> clone(std::string logger_name);
  289. protected:
  290. std::string name_;
  291. std::vector<sink_ptr> sinks_;
  292. spdlog::level_t level_{level::info};
  293. spdlog::level_t flush_level_{level::off};
  294. err_handler custom_err_handler_{nullptr};
  295. details::backtracer tracer_;
  296. // common implementation for after templated public api has been resolved
  297. template<typename... Args>
  298. void log_(source_loc loc, level::level_enum lvl, string_view_t fmt, Args &&... args)
  299. {
  300. bool log_enabled = should_log(lvl);
  301. bool traceback_enabled = tracer_.enabled();
  302. if (!log_enabled && !traceback_enabled)
  303. {
  304. return;
  305. }
  306. SPDLOG_TRY
  307. {
  308. memory_buf_t buf;
  309. #ifdef SPDLOG_USE_STD_FORMAT
  310. fmt_lib::vformat_to(std::back_inserter(buf), fmt, fmt_lib::make_format_args(std::forward<Args>(args)...));
  311. #else
  312. fmt::vformat_to(fmt::appender(buf), fmt, fmt::make_format_args(std::forward<Args>(args)...));
  313. #endif
  314. details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()));
  315. log_it_(log_msg, log_enabled, traceback_enabled);
  316. }
  317. SPDLOG_LOGGER_CATCH(loc)
  318. }
  319. #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
  320. template<typename... Args>
  321. void log_(source_loc loc, level::level_enum lvl, wstring_view_t fmt, Args &&... args)
  322. {
  323. bool log_enabled = should_log(lvl);
  324. bool traceback_enabled = tracer_.enabled();
  325. if (!log_enabled && !traceback_enabled)
  326. {
  327. return;
  328. }
  329. SPDLOG_TRY
  330. {
  331. // format to wmemory_buffer and convert to utf8
  332. wmemory_buf_t wbuf;
  333. # ifdef SPDLOG_USE_STD_FORMAT
  334. fmt_lib::vformat_to(
  335. std::back_inserter(wbuf), fmt, fmt_lib::make_format_args<fmt_lib::wformat_context>(std::forward<Args>(args)...));
  336. # else
  337. fmt::vformat_to(std::back_inserter(wbuf), fmt, fmt::make_format_args<fmt::wformat_context>(std::forward<Args>(args)...));
  338. # endif
  339. memory_buf_t buf;
  340. details::os::wstr_to_utf8buf(wstring_view_t(wbuf.data(), wbuf.size()), buf);
  341. details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()));
  342. log_it_(log_msg, log_enabled, traceback_enabled);
  343. }
  344. SPDLOG_LOGGER_CATCH(loc)
  345. }
  346. // T can be statically converted to wstring_view, and no formatting needed.
  347. template<class T, typename std::enable_if<std::is_convertible<const T &, spdlog::wstring_view_t>::value, int>::type = 0>
  348. void log_(source_loc loc, level::level_enum lvl, const T &msg)
  349. {
  350. bool log_enabled = should_log(lvl);
  351. bool traceback_enabled = tracer_.enabled();
  352. if (!log_enabled && !traceback_enabled)
  353. {
  354. return;
  355. }
  356. SPDLOG_TRY
  357. {
  358. memory_buf_t buf;
  359. details::os::wstr_to_utf8buf(msg, buf);
  360. details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()));
  361. log_it_(log_msg, log_enabled, traceback_enabled);
  362. }
  363. SPDLOG_LOGGER_CATCH(loc)
  364. }
  365. #endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT
  366. // log the given message (if the given log level is high enough),
  367. // and save backtrace (if backtrace is enabled).
  368. void log_it_(const details::log_msg &log_msg, bool log_enabled, bool traceback_enabled);
  369. virtual void sink_it_(const details::log_msg &msg);
  370. virtual void flush_();
  371. void dump_backtrace_();
  372. bool should_flush_(const details::log_msg &msg);
  373. // handle errors during logging.
  374. // default handler prints the error to stderr at max rate of 1 message/sec.
  375. void err_handler_(const std::string &msg);
  376. };
  377. void swap(logger &a, logger &b);
  378. } // namespace spdlog
  379. #ifdef SPDLOG_HEADER_ONLY
  380. # include "logger-inl.h"
  381. #endif