logger.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  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, details::to_string_view(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, details::to_string_view(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(args...));
  311. #else
  312. fmt::vformat_to(fmt::appender(buf), fmt, fmt::make_format_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. fmt_lib::vformat_to(std::back_inserter(wbuf), fmt, fmt_lib::make_format_args<fmt_lib::wformat_context>(args...));
  334. memory_buf_t buf;
  335. details::os::wstr_to_utf8buf(wstring_view_t(wbuf.data(), wbuf.size()), buf);
  336. details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()));
  337. log_it_(log_msg, log_enabled, traceback_enabled);
  338. }
  339. SPDLOG_LOGGER_CATCH(loc)
  340. }
  341. #endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT
  342. // log the given message (if the given log level is high enough),
  343. // and save backtrace (if backtrace is enabled).
  344. void log_it_(const details::log_msg &log_msg, bool log_enabled, bool traceback_enabled);
  345. virtual void sink_it_(const details::log_msg &msg);
  346. virtual void flush_();
  347. void dump_backtrace_();
  348. bool should_flush_(const details::log_msg &msg);
  349. // handle errors during logging.
  350. // default handler prints the error to stderr at max rate of 1 message/sec.
  351. void err_handler_(const std::string &msg);
  352. };
  353. void swap(logger &a, logger &b);
  354. } // namespace spdlog
  355. #ifdef SPDLOG_HEADER_ONLY
  356. # include "logger-inl.h"
  357. #endif