logger.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  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/backtracer.h>
  16. #include <spdlog/details/log_msg.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. if (location.filename) { \
  28. err_handler_(fmt_lib::format(SPDLOG_FMT_STRING("{} [{}({})]"), ex.what(), \
  29. location.filename, location.line)); \
  30. } else { \
  31. err_handler_(ex.what()); \
  32. } \
  33. } \
  34. catch (...) { \
  35. err_handler_("Rethrowing unknown exception in logger"); \
  36. throw; \
  37. }
  38. #else
  39. #define SPDLOG_LOGGER_CATCH(location)
  40. #endif
  41. namespace spdlog {
  42. class SPDLOG_API logger {
  43. public:
  44. // Empty logger
  45. explicit logger(std::string name)
  46. : name_(std::move(name)),
  47. sinks_() {}
  48. // Logger with range on sinks
  49. template <typename It>
  50. logger(std::string name, It begin, It end)
  51. : name_(std::move(name)),
  52. sinks_(begin, end) {}
  53. // Logger with single sink
  54. logger(std::string name, sink_ptr single_sink)
  55. : logger(std::move(name), {std::move(single_sink)}) {}
  56. // Logger with sinks init list
  57. logger(std::string name, sinks_init_list sinks)
  58. : logger(std::move(name), sinks.begin(), sinks.end()) {}
  59. virtual ~logger() = default;
  60. logger(const logger &other);
  61. logger(logger &&other) SPDLOG_NOEXCEPT;
  62. logger &operator=(logger other) SPDLOG_NOEXCEPT;
  63. void swap(spdlog::logger &other) SPDLOG_NOEXCEPT;
  64. template <typename... Args>
  65. void log(source_loc loc, level::level_enum lvl, format_string_t<Args...> fmt, Args &&...args) {
  66. log_(loc, lvl, details::to_string_view(fmt), std::forward<Args>(args)...);
  67. }
  68. template <typename... Args>
  69. void log(level::level_enum lvl, format_string_t<Args...> fmt, Args &&...args) {
  70. log(source_loc{}, lvl, fmt, std::forward<Args>(args)...);
  71. }
  72. template <typename T>
  73. void log(level::level_enum lvl, const T &msg) {
  74. log(source_loc{}, lvl, msg);
  75. }
  76. // T cannot be statically converted to format string (including string_view/wstring_view)
  77. template <class T,
  78. typename std::enable_if<!is_convertible_to_any_format_string<const T &>::value,
  79. int>::type = 0>
  80. void log(source_loc loc, level::level_enum lvl, const T &msg) {
  81. log(loc, lvl, "{}", msg);
  82. }
  83. void log(log_clock::time_point log_time,
  84. source_loc loc,
  85. level::level_enum lvl,
  86. string_view_t msg) {
  87. bool log_enabled = should_log(lvl);
  88. bool traceback_enabled = tracer_.enabled();
  89. if (!log_enabled && !traceback_enabled) {
  90. return;
  91. }
  92. details::log_msg log_msg(log_time, loc, name_, lvl, msg);
  93. log_it_(log_msg, log_enabled, traceback_enabled);
  94. }
  95. void log(source_loc loc, level::level_enum lvl, string_view_t msg) {
  96. bool log_enabled = should_log(lvl);
  97. bool traceback_enabled = tracer_.enabled();
  98. if (!log_enabled && !traceback_enabled) {
  99. return;
  100. }
  101. details::log_msg log_msg(loc, name_, lvl, msg);
  102. log_it_(log_msg, log_enabled, traceback_enabled);
  103. }
  104. void log(level::level_enum lvl, string_view_t msg) { log(source_loc{}, lvl, msg); }
  105. template <typename... Args>
  106. void trace(format_string_t<Args...> fmt, Args &&...args) {
  107. log(level::trace, fmt, std::forward<Args>(args)...);
  108. }
  109. template <typename... Args>
  110. void debug(format_string_t<Args...> fmt, Args &&...args) {
  111. log(level::debug, fmt, std::forward<Args>(args)...);
  112. }
  113. template <typename... Args>
  114. void info(format_string_t<Args...> fmt, Args &&...args) {
  115. log(level::info, fmt, std::forward<Args>(args)...);
  116. }
  117. template <typename... Args>
  118. void warn(format_string_t<Args...> fmt, Args &&...args) {
  119. log(level::warn, fmt, std::forward<Args>(args)...);
  120. }
  121. template <typename... Args>
  122. void error(format_string_t<Args...> fmt, Args &&...args) {
  123. log(level::err, fmt, std::forward<Args>(args)...);
  124. }
  125. template <typename... Args>
  126. void critical(format_string_t<Args...> fmt, Args &&...args) {
  127. log(level::critical, fmt, std::forward<Args>(args)...);
  128. }
  129. #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
  130. template <typename... Args>
  131. void log(source_loc loc, level::level_enum lvl, wformat_string_t<Args...> fmt, Args &&...args) {
  132. log_(loc, lvl, details::to_string_view(fmt), std::forward<Args>(args)...);
  133. }
  134. template <typename... Args>
  135. void log(level::level_enum lvl, wformat_string_t<Args...> fmt, Args &&...args) {
  136. log(source_loc{}, lvl, fmt, std::forward<Args>(args)...);
  137. }
  138. void log(log_clock::time_point log_time,
  139. source_loc loc,
  140. level::level_enum lvl,
  141. wstring_view_t msg) {
  142. bool log_enabled = should_log(lvl);
  143. bool traceback_enabled = tracer_.enabled();
  144. if (!log_enabled && !traceback_enabled) {
  145. return;
  146. }
  147. memory_buf_t buf;
  148. details::os::wstr_to_utf8buf(wstring_view_t(msg.data(), msg.size()), buf);
  149. details::log_msg log_msg(log_time, loc, name_, lvl, string_view_t(buf.data(), buf.size()));
  150. log_it_(log_msg, log_enabled, traceback_enabled);
  151. }
  152. void log(source_loc loc, level::level_enum lvl, wstring_view_t msg) {
  153. bool log_enabled = should_log(lvl);
  154. bool traceback_enabled = tracer_.enabled();
  155. if (!log_enabled && !traceback_enabled) {
  156. return;
  157. }
  158. memory_buf_t buf;
  159. details::os::wstr_to_utf8buf(wstring_view_t(msg.data(), msg.size()), buf);
  160. details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()));
  161. log_it_(log_msg, log_enabled, traceback_enabled);
  162. }
  163. void log(level::level_enum lvl, wstring_view_t msg) { log(source_loc{}, lvl, msg); }
  164. template <typename... Args>
  165. void trace(wformat_string_t<Args...> fmt, Args &&...args) {
  166. log(level::trace, fmt, std::forward<Args>(args)...);
  167. }
  168. template <typename... Args>
  169. void debug(wformat_string_t<Args...> fmt, Args &&...args) {
  170. log(level::debug, fmt, std::forward<Args>(args)...);
  171. }
  172. template <typename... Args>
  173. void info(wformat_string_t<Args...> fmt, Args &&...args) {
  174. log(level::info, fmt, std::forward<Args>(args)...);
  175. }
  176. template <typename... Args>
  177. void warn(wformat_string_t<Args...> fmt, Args &&...args) {
  178. log(level::warn, fmt, std::forward<Args>(args)...);
  179. }
  180. template <typename... Args>
  181. void error(wformat_string_t<Args...> fmt, Args &&...args) {
  182. log(level::err, fmt, std::forward<Args>(args)...);
  183. }
  184. template <typename... Args>
  185. void critical(wformat_string_t<Args...> fmt, Args &&...args) {
  186. log(level::critical, fmt, std::forward<Args>(args)...);
  187. }
  188. #endif
  189. template <typename T>
  190. void trace(const T &msg) {
  191. log(level::trace, msg);
  192. }
  193. template <typename T>
  194. void debug(const T &msg) {
  195. log(level::debug, msg);
  196. }
  197. template <typename T>
  198. void info(const T &msg) {
  199. log(level::info, msg);
  200. }
  201. template <typename T>
  202. void warn(const T &msg) {
  203. log(level::warn, msg);
  204. }
  205. template <typename T>
  206. void error(const T &msg) {
  207. log(level::err, msg);
  208. }
  209. template <typename T>
  210. void critical(const T &msg) {
  211. log(level::critical, msg);
  212. }
  213. // return true logging is enabled for the given level.
  214. bool should_log(level::level_enum msg_level) const {
  215. return msg_level >= level_.load(std::memory_order_relaxed);
  216. }
  217. // return true if backtrace logging is enabled.
  218. bool should_backtrace() const { return tracer_.enabled(); }
  219. void set_level(level::level_enum log_level);
  220. level::level_enum level() const;
  221. const std::string &name() const;
  222. // set formatting for the sinks in this logger.
  223. // each sink will get a separate instance of the formatter object.
  224. void set_formatter(std::unique_ptr<formatter> f);
  225. // set formatting for the sinks in this logger.
  226. // equivalent to
  227. // set_formatter(make_unique<pattern_formatter>(pattern, time_type))
  228. // Note: each sink will get a new instance of a formatter object, replacing the old one.
  229. void set_pattern(std::string pattern, pattern_time_type time_type = pattern_time_type::local);
  230. // backtrace support.
  231. // efficiently store all debug/trace messages in a circular buffer until needed for debugging.
  232. void enable_backtrace(size_t n_messages);
  233. void disable_backtrace();
  234. void dump_backtrace();
  235. // flush functions
  236. void flush();
  237. void flush_on(level::level_enum log_level);
  238. level::level_enum flush_level() const;
  239. // sinks
  240. const std::vector<sink_ptr> &sinks() const;
  241. std::vector<sink_ptr> &sinks();
  242. // error handler
  243. void set_error_handler(err_handler);
  244. // create new logger with same sinks and configuration.
  245. virtual std::shared_ptr<logger> clone(std::string logger_name);
  246. protected:
  247. std::string name_;
  248. std::vector<sink_ptr> sinks_;
  249. spdlog::level_t level_{level::info};
  250. spdlog::level_t flush_level_{level::off};
  251. err_handler custom_err_handler_{nullptr};
  252. details::backtracer tracer_;
  253. // common implementation for after templated public api has been resolved
  254. template <typename... Args>
  255. void log_(source_loc loc, level::level_enum lvl, string_view_t fmt, Args &&...args) {
  256. bool log_enabled = should_log(lvl);
  257. bool traceback_enabled = tracer_.enabled();
  258. if (!log_enabled && !traceback_enabled) {
  259. return;
  260. }
  261. SPDLOG_TRY {
  262. memory_buf_t buf;
  263. #ifdef SPDLOG_USE_STD_FORMAT
  264. fmt_lib::vformat_to(std::back_inserter(buf), fmt, fmt_lib::make_format_args(args...));
  265. #else
  266. fmt::vformat_to(fmt::appender(buf), fmt, fmt::make_format_args(args...));
  267. #endif
  268. details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()));
  269. log_it_(log_msg, log_enabled, traceback_enabled);
  270. }
  271. SPDLOG_LOGGER_CATCH(loc)
  272. }
  273. #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
  274. template <typename... Args>
  275. void log_(source_loc loc, level::level_enum lvl, wstring_view_t fmt, Args &&...args) {
  276. bool log_enabled = should_log(lvl);
  277. bool traceback_enabled = tracer_.enabled();
  278. if (!log_enabled && !traceback_enabled) {
  279. return;
  280. }
  281. SPDLOG_TRY {
  282. // format to wmemory_buffer and convert to utf8
  283. wmemory_buf_t wbuf;
  284. fmt_lib::vformat_to(std::back_inserter(wbuf), fmt,
  285. fmt_lib::make_format_args<fmt_lib::wformat_context>(args...));
  286. memory_buf_t buf;
  287. details::os::wstr_to_utf8buf(wstring_view_t(wbuf.data(), wbuf.size()), buf);
  288. details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()));
  289. log_it_(log_msg, log_enabled, traceback_enabled);
  290. }
  291. SPDLOG_LOGGER_CATCH(loc)
  292. }
  293. #endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT
  294. // log the given message (if the given log level is high enough),
  295. // and save backtrace (if backtrace is enabled).
  296. void log_it_(const details::log_msg &log_msg, bool log_enabled, bool traceback_enabled);
  297. virtual void sink_it_(const details::log_msg &msg);
  298. virtual void flush_();
  299. void dump_backtrace_();
  300. bool should_flush_(const details::log_msg &msg);
  301. // handle errors during logging.
  302. // default handler prints the error to stderr at max rate of 1 message/sec.
  303. void err_handler_(const std::string &msg);
  304. };
  305. void swap(logger &a, logger &b);
  306. } // namespace spdlog
  307. #ifdef SPDLOG_HEADER_ONLY
  308. #include "logger-inl.h"
  309. #endif