選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

1318 行
38KB

  1. // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
  2. // Distributed under the MIT License (http://opensource.org/licenses/MIT)
  3. #pragma once
  4. #ifndef SPDLOG_HEADER_ONLY
  5. #include "spdlog/details/pattern_formatter.h"
  6. #endif
  7. #include "spdlog/details/fmt_helper.h"
  8. #include "spdlog/details/log_msg.h"
  9. #include "spdlog/details/os.h"
  10. #include "spdlog/fmt/fmt.h"
  11. #include "spdlog/formatter.h"
  12. #include <array>
  13. #include <chrono>
  14. #include <ctime>
  15. #include <cctype>
  16. #include <cstring>
  17. #include <memory>
  18. #include <mutex>
  19. #include <string>
  20. #include <thread>
  21. #include <utility>
  22. #include <vector>
  23. namespace spdlog {
  24. namespace details {
  25. ///////////////////////////////////////////////////////////////////////
  26. // name & level pattern appender
  27. ///////////////////////////////////////////////////////////////////////
  28. class scoped_padder
  29. {
  30. public:
  31. scoped_padder(size_t wrapped_size, const padding_info &padinfo, memory_buf_t &dest)
  32. : padinfo_(padinfo)
  33. , dest_(dest)
  34. {
  35. if (padinfo_.width_ <= wrapped_size)
  36. {
  37. total_pad_ = 0;
  38. return;
  39. }
  40. total_pad_ = padinfo.width_ - wrapped_size;
  41. if (padinfo_.side_ == padding_info::left)
  42. {
  43. pad_it(total_pad_);
  44. total_pad_ = 0;
  45. }
  46. else if (padinfo_.side_ == padding_info::center)
  47. {
  48. auto half_pad = total_pad_ / 2;
  49. auto reminder = total_pad_ & 1;
  50. pad_it(half_pad);
  51. total_pad_ = half_pad + reminder; // for the right side
  52. }
  53. }
  54. ~scoped_padder()
  55. {
  56. if (total_pad_)
  57. {
  58. pad_it(total_pad_);
  59. }
  60. }
  61. private:
  62. void pad_it(size_t count)
  63. {
  64. // count = std::min(count, spaces_.size());
  65. assert(count <= spaces_.size());
  66. fmt_helper::append_string_view(string_view_t(spaces_.data(), count), dest_);
  67. }
  68. const padding_info &padinfo_;
  69. memory_buf_t &dest_;
  70. size_t total_pad_;
  71. string_view_t spaces_{" ", 64};
  72. };
  73. struct null_scoped_padder
  74. {
  75. null_scoped_padder(size_t /*wrapped_size*/, const padding_info & /*padinfo*/, memory_buf_t & /*dest*/) {}
  76. };
  77. template<typename ScopedPadder>
  78. class name_formatter : public flag_formatter
  79. {
  80. public:
  81. explicit name_formatter(padding_info padinfo)
  82. : flag_formatter(padinfo)
  83. {}
  84. void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override
  85. {
  86. ScopedPadder p(msg.logger_name.size(), padinfo_, dest);
  87. fmt_helper::append_string_view(msg.logger_name, dest);
  88. }
  89. };
  90. // log level appender
  91. template<typename ScopedPadder>
  92. class level_formatter : public flag_formatter
  93. {
  94. public:
  95. explicit level_formatter(padding_info padinfo)
  96. : flag_formatter(padinfo)
  97. {}
  98. void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override
  99. {
  100. string_view_t &level_name = level::to_string_view(msg.level);
  101. ScopedPadder p(level_name.size(), padinfo_, dest);
  102. fmt_helper::append_string_view(level_name, dest);
  103. }
  104. };
  105. // short log level appender
  106. template<typename ScopedPadder>
  107. class short_level_formatter : public flag_formatter
  108. {
  109. public:
  110. explicit short_level_formatter(padding_info padinfo)
  111. : flag_formatter(padinfo)
  112. {}
  113. void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override
  114. {
  115. string_view_t level_name{level::to_short_c_str(msg.level)};
  116. ScopedPadder p(level_name.size(), padinfo_, dest);
  117. fmt_helper::append_string_view(level_name, dest);
  118. }
  119. };
  120. ///////////////////////////////////////////////////////////////////////
  121. // Date time pattern appenders
  122. ///////////////////////////////////////////////////////////////////////
  123. static const char *ampm(const tm &t)
  124. {
  125. return t.tm_hour >= 12 ? "PM" : "AM";
  126. }
  127. static int to12h(const tm &t)
  128. {
  129. return t.tm_hour > 12 ? t.tm_hour - 12 : t.tm_hour;
  130. }
  131. // Abbreviated weekday name
  132. static std::array<const char *, 7> days{{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}};
  133. template<typename ScopedPadder>
  134. class a_formatter : public flag_formatter
  135. {
  136. public:
  137. explicit a_formatter(padding_info padinfo)
  138. : flag_formatter(padinfo)
  139. {}
  140. void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override
  141. {
  142. string_view_t field_value{days[static_cast<size_t>(tm_time.tm_wday)]};
  143. ScopedPadder p(field_value.size(), padinfo_, dest);
  144. fmt_helper::append_string_view(field_value, dest);
  145. }
  146. };
  147. // Full weekday name
  148. static std::array<const char *, 7> full_days{{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}};
  149. template<typename ScopedPadder>
  150. class A_formatter : public flag_formatter
  151. {
  152. public:
  153. explicit A_formatter(padding_info padinfo)
  154. : flag_formatter(padinfo)
  155. {}
  156. void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override
  157. {
  158. string_view_t field_value{full_days[static_cast<size_t>(tm_time.tm_wday)]};
  159. ScopedPadder p(field_value.size(), padinfo_, dest);
  160. fmt_helper::append_string_view(field_value, dest);
  161. }
  162. };
  163. // Abbreviated month
  164. static const std::array<const char *, 12> months{{"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"}};
  165. template<typename ScopedPadder>
  166. class b_formatter : public flag_formatter
  167. {
  168. public:
  169. explicit b_formatter(padding_info padinfo)
  170. : flag_formatter(padinfo)
  171. {}
  172. void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override
  173. {
  174. string_view_t field_value{months[static_cast<size_t>(tm_time.tm_mon)]};
  175. ScopedPadder p(field_value.size(), padinfo_, dest);
  176. fmt_helper::append_string_view(field_value, dest);
  177. }
  178. };
  179. // Full month name
  180. static const std::array<const char *, 12> full_months{
  181. {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}};
  182. template<typename ScopedPadder>
  183. class B_formatter : public flag_formatter
  184. {
  185. public:
  186. explicit B_formatter(padding_info padinfo)
  187. : flag_formatter(padinfo)
  188. {}
  189. void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override
  190. {
  191. string_view_t field_value{full_months[static_cast<size_t>(tm_time.tm_mon)]};
  192. ScopedPadder p(field_value.size(), padinfo_, dest);
  193. fmt_helper::append_string_view(field_value, dest);
  194. }
  195. };
  196. // Date and time representation (Thu Aug 23 15:35:46 2014)
  197. template<typename ScopedPadder>
  198. class c_formatter final : public flag_formatter
  199. {
  200. public:
  201. explicit c_formatter(padding_info padinfo)
  202. : flag_formatter(padinfo)
  203. {}
  204. void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override
  205. {
  206. const size_t field_size = 24;
  207. ScopedPadder p(field_size, padinfo_, dest);
  208. fmt_helper::append_string_view(days[static_cast<size_t>(tm_time.tm_wday)], dest);
  209. dest.push_back(' ');
  210. fmt_helper::append_string_view(months[static_cast<size_t>(tm_time.tm_mon)], dest);
  211. dest.push_back(' ');
  212. fmt_helper::append_int(tm_time.tm_mday, dest);
  213. dest.push_back(' ');
  214. // time
  215. fmt_helper::pad2(tm_time.tm_hour, dest);
  216. dest.push_back(':');
  217. fmt_helper::pad2(tm_time.tm_min, dest);
  218. dest.push_back(':');
  219. fmt_helper::pad2(tm_time.tm_sec, dest);
  220. dest.push_back(' ');
  221. fmt_helper::append_int(tm_time.tm_year + 1900, dest);
  222. }
  223. };
  224. // year - 2 digit
  225. template<typename ScopedPadder>
  226. class C_formatter final : public flag_formatter
  227. {
  228. public:
  229. explicit C_formatter(padding_info padinfo)
  230. : flag_formatter(padinfo)
  231. {}
  232. void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override
  233. {
  234. const size_t field_size = 2;
  235. ScopedPadder p(field_size, padinfo_, dest);
  236. fmt_helper::pad2(tm_time.tm_year % 100, dest);
  237. }
  238. };
  239. // Short MM/DD/YY date, equivalent to %m/%d/%y 08/23/01
  240. template<typename ScopedPadder>
  241. class D_formatter final : public flag_formatter
  242. {
  243. public:
  244. explicit D_formatter(padding_info padinfo)
  245. : flag_formatter(padinfo)
  246. {}
  247. void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override
  248. {
  249. const size_t field_size = 10;
  250. ScopedPadder p(field_size, padinfo_, dest);
  251. fmt_helper::pad2(tm_time.tm_mon + 1, dest);
  252. dest.push_back('/');
  253. fmt_helper::pad2(tm_time.tm_mday, dest);
  254. dest.push_back('/');
  255. fmt_helper::pad2(tm_time.tm_year % 100, dest);
  256. }
  257. };
  258. // year - 4 digit
  259. template<typename ScopedPadder>
  260. class Y_formatter final : public flag_formatter
  261. {
  262. public:
  263. explicit Y_formatter(padding_info padinfo)
  264. : flag_formatter(padinfo)
  265. {}
  266. void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override
  267. {
  268. const size_t field_size = 4;
  269. ScopedPadder p(field_size, padinfo_, dest);
  270. fmt_helper::append_int(tm_time.tm_year + 1900, dest);
  271. }
  272. };
  273. // month 1-12
  274. template<typename ScopedPadder>
  275. class m_formatter final : public flag_formatter
  276. {
  277. public:
  278. explicit m_formatter(padding_info padinfo)
  279. : flag_formatter(padinfo)
  280. {}
  281. void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override
  282. {
  283. const size_t field_size = 2;
  284. ScopedPadder p(field_size, padinfo_, dest);
  285. fmt_helper::pad2(tm_time.tm_mon + 1, dest);
  286. }
  287. };
  288. // day of month 1-31
  289. template<typename ScopedPadder>
  290. class d_formatter final : public flag_formatter
  291. {
  292. public:
  293. explicit d_formatter(padding_info padinfo)
  294. : flag_formatter(padinfo)
  295. {}
  296. void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override
  297. {
  298. const size_t field_size = 2;
  299. ScopedPadder p(field_size, padinfo_, dest);
  300. fmt_helper::pad2(tm_time.tm_mday, dest);
  301. }
  302. };
  303. // hours in 24 format 0-23
  304. template<typename ScopedPadder>
  305. class H_formatter final : public flag_formatter
  306. {
  307. public:
  308. explicit H_formatter(padding_info padinfo)
  309. : flag_formatter(padinfo)
  310. {}
  311. void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override
  312. {
  313. const size_t field_size = 2;
  314. ScopedPadder p(field_size, padinfo_, dest);
  315. fmt_helper::pad2(tm_time.tm_hour, dest);
  316. }
  317. };
  318. // hours in 12 format 1-12
  319. template<typename ScopedPadder>
  320. class I_formatter final : public flag_formatter
  321. {
  322. public:
  323. explicit I_formatter(padding_info padinfo)
  324. : flag_formatter(padinfo)
  325. {}
  326. void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override
  327. {
  328. const size_t field_size = 2;
  329. ScopedPadder p(field_size, padinfo_, dest);
  330. fmt_helper::pad2(to12h(tm_time), dest);
  331. }
  332. };
  333. // minutes 0-59
  334. template<typename ScopedPadder>
  335. class M_formatter final : public flag_formatter
  336. {
  337. public:
  338. explicit M_formatter(padding_info padinfo)
  339. : flag_formatter(padinfo)
  340. {}
  341. void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override
  342. {
  343. const size_t field_size = 2;
  344. ScopedPadder p(field_size, padinfo_, dest);
  345. fmt_helper::pad2(tm_time.tm_min, dest);
  346. }
  347. };
  348. // seconds 0-59
  349. template<typename ScopedPadder>
  350. class S_formatter final : public flag_formatter
  351. {
  352. public:
  353. explicit S_formatter(padding_info padinfo)
  354. : flag_formatter(padinfo)
  355. {}
  356. void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override
  357. {
  358. const size_t field_size = 2;
  359. ScopedPadder p(field_size, padinfo_, dest);
  360. fmt_helper::pad2(tm_time.tm_sec, dest);
  361. }
  362. };
  363. // milliseconds
  364. template<typename ScopedPadder>
  365. class e_formatter final : public flag_formatter
  366. {
  367. public:
  368. explicit e_formatter(padding_info padinfo)
  369. : flag_formatter(padinfo)
  370. {}
  371. void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override
  372. {
  373. auto millis = fmt_helper::time_fraction<std::chrono::milliseconds>(msg.time);
  374. const size_t field_size = 3;
  375. ScopedPadder p(field_size, padinfo_, dest);
  376. fmt_helper::pad3(static_cast<uint32_t>(millis.count()), dest);
  377. }
  378. };
  379. // microseconds
  380. template<typename ScopedPadder>
  381. class f_formatter final : public flag_formatter
  382. {
  383. public:
  384. explicit f_formatter(padding_info padinfo)
  385. : flag_formatter(padinfo)
  386. {}
  387. void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override
  388. {
  389. auto micros = fmt_helper::time_fraction<std::chrono::microseconds>(msg.time);
  390. const size_t field_size = 6;
  391. ScopedPadder p(field_size, padinfo_, dest);
  392. fmt_helper::pad6(static_cast<size_t>(micros.count()), dest);
  393. }
  394. };
  395. // nanoseconds
  396. template<typename ScopedPadder>
  397. class F_formatter final : public flag_formatter
  398. {
  399. public:
  400. explicit F_formatter(padding_info padinfo)
  401. : flag_formatter(padinfo)
  402. {}
  403. void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override
  404. {
  405. auto ns = fmt_helper::time_fraction<std::chrono::nanoseconds>(msg.time);
  406. const size_t field_size = 9;
  407. ScopedPadder p(field_size, padinfo_, dest);
  408. fmt_helper::pad9(static_cast<size_t>(ns.count()), dest);
  409. }
  410. };
  411. // seconds since epoch
  412. template<typename ScopedPadder>
  413. class E_formatter final : public flag_formatter
  414. {
  415. public:
  416. explicit E_formatter(padding_info padinfo)
  417. : flag_formatter(padinfo)
  418. {}
  419. void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override
  420. {
  421. const size_t field_size = 10;
  422. ScopedPadder p(field_size, padinfo_, dest);
  423. auto duration = msg.time.time_since_epoch();
  424. auto seconds = std::chrono::duration_cast<std::chrono::seconds>(duration).count();
  425. fmt_helper::append_int(seconds, dest);
  426. }
  427. };
  428. // AM/PM
  429. template<typename ScopedPadder>
  430. class p_formatter final : public flag_formatter
  431. {
  432. public:
  433. explicit p_formatter(padding_info padinfo)
  434. : flag_formatter(padinfo)
  435. {}
  436. void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override
  437. {
  438. const size_t field_size = 2;
  439. ScopedPadder p(field_size, padinfo_, dest);
  440. fmt_helper::append_string_view(ampm(tm_time), dest);
  441. }
  442. };
  443. // 12 hour clock 02:55:02 pm
  444. template<typename ScopedPadder>
  445. class r_formatter final : public flag_formatter
  446. {
  447. public:
  448. explicit r_formatter(padding_info padinfo)
  449. : flag_formatter(padinfo)
  450. {}
  451. void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override
  452. {
  453. const size_t field_size = 11;
  454. ScopedPadder p(field_size, padinfo_, dest);
  455. fmt_helper::pad2(to12h(tm_time), dest);
  456. dest.push_back(':');
  457. fmt_helper::pad2(tm_time.tm_min, dest);
  458. dest.push_back(':');
  459. fmt_helper::pad2(tm_time.tm_sec, dest);
  460. dest.push_back(' ');
  461. fmt_helper::append_string_view(ampm(tm_time), dest);
  462. }
  463. };
  464. // 24-hour HH:MM time, equivalent to %H:%M
  465. template<typename ScopedPadder>
  466. class R_formatter final : public flag_formatter
  467. {
  468. public:
  469. explicit R_formatter(padding_info padinfo)
  470. : flag_formatter(padinfo)
  471. {}
  472. void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override
  473. {
  474. const size_t field_size = 5;
  475. ScopedPadder p(field_size, padinfo_, dest);
  476. fmt_helper::pad2(tm_time.tm_hour, dest);
  477. dest.push_back(':');
  478. fmt_helper::pad2(tm_time.tm_min, dest);
  479. }
  480. };
  481. // ISO 8601 time format (HH:MM:SS), equivalent to %H:%M:%S
  482. template<typename ScopedPadder>
  483. class T_formatter final : public flag_formatter
  484. {
  485. public:
  486. explicit T_formatter(padding_info padinfo)
  487. : flag_formatter(padinfo)
  488. {}
  489. void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override
  490. {
  491. const size_t field_size = 8;
  492. ScopedPadder p(field_size, padinfo_, dest);
  493. fmt_helper::pad2(tm_time.tm_hour, dest);
  494. dest.push_back(':');
  495. fmt_helper::pad2(tm_time.tm_min, dest);
  496. dest.push_back(':');
  497. fmt_helper::pad2(tm_time.tm_sec, dest);
  498. }
  499. };
  500. // ISO 8601 offset from UTC in timezone (+-HH:MM)
  501. template<typename ScopedPadder>
  502. class z_formatter final : public flag_formatter
  503. {
  504. public:
  505. explicit z_formatter(padding_info padinfo)
  506. : flag_formatter(padinfo)
  507. {}
  508. z_formatter() = default;
  509. z_formatter(const z_formatter &) = delete;
  510. z_formatter &operator=(const z_formatter &) = delete;
  511. void format(const details::log_msg &msg, const std::tm &tm_time, memory_buf_t &dest) override
  512. {
  513. const size_t field_size = 6;
  514. ScopedPadder p(field_size, padinfo_, dest);
  515. #ifdef _WIN32
  516. int total_minutes = get_cached_offset(msg, tm_time);
  517. #else
  518. // No need to chache under gcc,
  519. // it is very fast (already stored in tm.tm_gmtoff)
  520. (void)(msg);
  521. int total_minutes = os::utc_minutes_offset(tm_time);
  522. #endif
  523. bool is_negative = total_minutes < 0;
  524. if (is_negative)
  525. {
  526. total_minutes = -total_minutes;
  527. dest.push_back('-');
  528. }
  529. else
  530. {
  531. dest.push_back('+');
  532. }
  533. fmt_helper::pad2(total_minutes / 60, dest); // hours
  534. dest.push_back(':');
  535. fmt_helper::pad2(total_minutes % 60, dest); // minutes
  536. }
  537. private:
  538. log_clock::time_point last_update_{std::chrono::seconds(0)};
  539. #ifdef _WIN32
  540. int offset_minutes_{0};
  541. int get_cached_offset(const log_msg &msg, const std::tm &tm_time)
  542. {
  543. // refresh every 10 seconds
  544. if (msg.time - last_update_ >= std::chrono::seconds(10))
  545. {
  546. offset_minutes_ = os::utc_minutes_offset(tm_time);
  547. last_update_ = msg.time;
  548. }
  549. return offset_minutes_;
  550. }
  551. #endif
  552. };
  553. // Thread id
  554. template<typename ScopedPadder>
  555. class t_formatter final : public flag_formatter
  556. {
  557. public:
  558. explicit t_formatter(padding_info padinfo)
  559. : flag_formatter(padinfo)
  560. {}
  561. void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override
  562. {
  563. const auto field_size = fmt_helper::count_digits(msg.thread_id);
  564. ScopedPadder p(field_size, padinfo_, dest);
  565. fmt_helper::append_int(msg.thread_id, dest);
  566. }
  567. };
  568. // Current pid
  569. template<typename ScopedPadder>
  570. class pid_formatter final : public flag_formatter
  571. {
  572. public:
  573. explicit pid_formatter(padding_info padinfo)
  574. : flag_formatter(padinfo)
  575. {}
  576. void format(const details::log_msg &, const std::tm &, memory_buf_t &dest) override
  577. {
  578. const auto pid = static_cast<uint32_t>(details::os::pid());
  579. auto field_size = fmt_helper::count_digits(pid);
  580. ScopedPadder p(field_size, padinfo_, dest);
  581. fmt_helper::append_int(pid, dest);
  582. }
  583. };
  584. template<typename ScopedPadder>
  585. class v_formatter final : public flag_formatter
  586. {
  587. public:
  588. explicit v_formatter(padding_info padinfo)
  589. : flag_formatter(padinfo)
  590. {}
  591. void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override
  592. {
  593. ScopedPadder p(msg.payload.size(), padinfo_, dest);
  594. fmt_helper::append_string_view(msg.payload, dest);
  595. }
  596. };
  597. class ch_formatter final : public flag_formatter
  598. {
  599. public:
  600. explicit ch_formatter(char ch)
  601. : ch_(ch)
  602. {}
  603. void format(const details::log_msg &, const std::tm &, memory_buf_t &dest) override
  604. {
  605. dest.push_back(ch_);
  606. }
  607. private:
  608. char ch_;
  609. };
  610. // aggregate user chars to display as is
  611. class aggregate_formatter final : public flag_formatter
  612. {
  613. public:
  614. aggregate_formatter() = default;
  615. void add_ch(char ch)
  616. {
  617. str_ += ch;
  618. }
  619. void format(const details::log_msg &, const std::tm &, memory_buf_t &dest) override
  620. {
  621. fmt_helper::append_string_view(str_, dest);
  622. }
  623. private:
  624. std::string str_;
  625. };
  626. // mark the color range. expect it to be in the form of "%^colored text%$"
  627. class color_start_formatter final : public flag_formatter
  628. {
  629. public:
  630. explicit color_start_formatter(padding_info padinfo)
  631. : flag_formatter(padinfo)
  632. {}
  633. void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override
  634. {
  635. msg.color_range_start = dest.size();
  636. }
  637. };
  638. class color_stop_formatter final : public flag_formatter
  639. {
  640. public:
  641. explicit color_stop_formatter(padding_info padinfo)
  642. : flag_formatter(padinfo)
  643. {}
  644. void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override
  645. {
  646. msg.color_range_end = dest.size();
  647. }
  648. };
  649. // print source location
  650. template<typename ScopedPadder>
  651. class source_location_formatter final : public flag_formatter
  652. {
  653. public:
  654. explicit source_location_formatter(padding_info padinfo)
  655. : flag_formatter(padinfo)
  656. {}
  657. void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override
  658. {
  659. if (msg.source.empty())
  660. {
  661. return;
  662. }
  663. size_t text_size =
  664. padinfo_.enabled() ? std::char_traits<char>::length(msg.source.filename) + fmt_helper::count_digits(msg.source.line) + 1 : 0;
  665. ScopedPadder p(text_size, padinfo_, dest);
  666. fmt_helper::append_string_view(msg.source.filename, dest);
  667. dest.push_back(':');
  668. fmt_helper::append_int(msg.source.line, dest);
  669. }
  670. };
  671. // print source filename
  672. template<typename ScopedPadder>
  673. class source_filename_formatter final : public flag_formatter
  674. {
  675. public:
  676. explicit source_filename_formatter(padding_info padinfo)
  677. : flag_formatter(padinfo)
  678. {}
  679. void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override
  680. {
  681. if (msg.source.empty())
  682. {
  683. return;
  684. }
  685. size_t text_size = padinfo_.enabled() ? std::char_traits<char>::length(msg.source.filename) : 0;
  686. ScopedPadder p(text_size, padinfo_, dest);
  687. fmt_helper::append_string_view(msg.source.filename, dest);
  688. }
  689. };
  690. template<typename ScopedPadder>
  691. class short_filename_formatter final : public flag_formatter
  692. {
  693. public:
  694. explicit short_filename_formatter(padding_info padinfo)
  695. : flag_formatter(padinfo)
  696. {}
  697. static const char *basename(const char *filename)
  698. {
  699. const char *rv = std::strrchr(filename, os::folder_sep);
  700. return rv != nullptr ? rv + 1 : filename;
  701. }
  702. void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override
  703. {
  704. if (msg.source.empty())
  705. {
  706. return;
  707. }
  708. auto filename = basename(msg.source.filename);
  709. size_t text_size = padinfo_.enabled() ? std::char_traits<char>::length(filename) : 0;
  710. ScopedPadder p(text_size, padinfo_, dest);
  711. fmt_helper::append_string_view(filename, dest);
  712. }
  713. };
  714. template<typename ScopedPadder>
  715. class source_linenum_formatter final : public flag_formatter
  716. {
  717. public:
  718. explicit source_linenum_formatter(padding_info padinfo)
  719. : flag_formatter(padinfo)
  720. {}
  721. void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override
  722. {
  723. if (msg.source.empty())
  724. {
  725. return;
  726. }
  727. auto field_size = fmt_helper::count_digits(msg.source.line);
  728. ScopedPadder p(field_size, padinfo_, dest);
  729. fmt_helper::append_int(msg.source.line, dest);
  730. }
  731. };
  732. // print source funcname
  733. template<typename ScopedPadder>
  734. class source_funcname_formatter final : public flag_formatter
  735. {
  736. public:
  737. explicit source_funcname_formatter(padding_info padinfo)
  738. : flag_formatter(padinfo)
  739. {}
  740. void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override
  741. {
  742. if (msg.source.empty())
  743. {
  744. return;
  745. }
  746. size_t text_size = padinfo_.enabled() ? std::char_traits<char>::length(msg.source.funcname) : 0;
  747. ScopedPadder p(text_size, padinfo_, dest);
  748. fmt_helper::append_string_view(msg.source.funcname, dest);
  749. }
  750. };
  751. // print elapsed time since last message
  752. template<typename ScopedPadder, typename Units>
  753. class elapsed_formatter final : public flag_formatter
  754. {
  755. public:
  756. using DurationUnits = Units;
  757. explicit elapsed_formatter(padding_info padinfo)
  758. : flag_formatter(padinfo)
  759. , last_message_time_(log_clock::now())
  760. {}
  761. void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override
  762. {
  763. auto delta = (std::max)(msg.time - last_message_time_, log_clock::duration::zero());
  764. auto delta_units = std::chrono::duration_cast<DurationUnits>(delta);
  765. last_message_time_ = msg.time;
  766. ScopedPadder p(6, padinfo_, dest);
  767. fmt_helper::pad6(static_cast<size_t>(delta_units.count()), dest);
  768. }
  769. protected:
  770. log_clock::time_point last_message_time_;
  771. };
  772. // Full info formatter
  773. // pattern: [%Y-%m-%d %H:%M:%S.%e] [%n] [%l] %v
  774. class full_formatter final : public flag_formatter
  775. {
  776. public:
  777. explicit full_formatter(padding_info padinfo)
  778. : flag_formatter(padinfo)
  779. {}
  780. void format(const details::log_msg &msg, const std::tm &tm_time, memory_buf_t &dest) override
  781. {
  782. using std::chrono::duration_cast;
  783. using std::chrono::milliseconds;
  784. using std::chrono::seconds;
  785. #ifndef SPDLOG_NO_DATETIME
  786. // cache the date/time part for the next second.
  787. auto duration = msg.time.time_since_epoch();
  788. auto secs = duration_cast<seconds>(duration);
  789. if (cache_timestamp_ != secs || cached_datetime_.size() == 0)
  790. {
  791. cached_datetime_.clear();
  792. cached_datetime_.push_back('[');
  793. fmt_helper::append_int(tm_time.tm_year + 1900, cached_datetime_);
  794. cached_datetime_.push_back('-');
  795. fmt_helper::pad2(tm_time.tm_mon + 1, cached_datetime_);
  796. cached_datetime_.push_back('-');
  797. fmt_helper::pad2(tm_time.tm_mday, cached_datetime_);
  798. cached_datetime_.push_back(' ');
  799. fmt_helper::pad2(tm_time.tm_hour, cached_datetime_);
  800. cached_datetime_.push_back(':');
  801. fmt_helper::pad2(tm_time.tm_min, cached_datetime_);
  802. cached_datetime_.push_back(':');
  803. fmt_helper::pad2(tm_time.tm_sec, cached_datetime_);
  804. cached_datetime_.push_back('.');
  805. cache_timestamp_ = secs;
  806. }
  807. dest.append(cached_datetime_.begin(), cached_datetime_.end());
  808. auto millis = fmt_helper::time_fraction<milliseconds>(msg.time);
  809. fmt_helper::pad3(static_cast<uint32_t>(millis.count()), dest);
  810. dest.push_back(']');
  811. dest.push_back(' ');
  812. #else // no datetime needed
  813. (void)tm_time;
  814. #endif
  815. #ifndef SPDLOG_NO_NAME
  816. if (msg.logger_name.size() > 0)
  817. {
  818. dest.push_back('[');
  819. // fmt_helper::append_str(*msg.logger_name, dest);
  820. fmt_helper::append_string_view(msg.logger_name, dest);
  821. dest.push_back(']');
  822. dest.push_back(' ');
  823. }
  824. #endif
  825. dest.push_back('[');
  826. // wrap the level name with color
  827. msg.color_range_start = dest.size();
  828. // fmt_helper::append_string_view(level::to_c_str(msg.level), dest);
  829. fmt_helper::append_string_view(level::to_string_view(msg.level), dest);
  830. msg.color_range_end = dest.size();
  831. dest.push_back(']');
  832. dest.push_back(' ');
  833. // add source location if present
  834. if (!msg.source.empty())
  835. {
  836. dest.push_back('[');
  837. const char *filename = details::short_filename_formatter<details::null_scoped_padder>::basename(msg.source.filename);
  838. fmt_helper::append_string_view(filename, dest);
  839. dest.push_back(':');
  840. fmt_helper::append_int(msg.source.line, dest);
  841. dest.push_back(']');
  842. dest.push_back(' ');
  843. }
  844. // fmt_helper::append_string_view(msg.msg(), dest);
  845. fmt_helper::append_string_view(msg.payload, dest);
  846. }
  847. private:
  848. std::chrono::seconds cache_timestamp_{0};
  849. memory_buf_t cached_datetime_;
  850. };
  851. } // namespace details
  852. SPDLOG_INLINE pattern_formatter::pattern_formatter(std::string pattern, pattern_time_type time_type, std::string eol)
  853. : pattern_(std::move(pattern))
  854. , eol_(std::move(eol))
  855. , pattern_time_type_(time_type)
  856. , last_log_secs_(0)
  857. {
  858. std::memset(&cached_tm_, 0, sizeof(cached_tm_));
  859. compile_pattern_(pattern_);
  860. }
  861. // use by default full formatter for if pattern is not given
  862. SPDLOG_INLINE pattern_formatter::pattern_formatter(pattern_time_type time_type, std::string eol)
  863. : pattern_("%+")
  864. , eol_(std::move(eol))
  865. , pattern_time_type_(time_type)
  866. , last_log_secs_(0)
  867. {
  868. std::memset(&cached_tm_, 0, sizeof(cached_tm_));
  869. formatters_.push_back(details::make_unique<details::full_formatter>(details::padding_info{}));
  870. }
  871. SPDLOG_INLINE std::unique_ptr<formatter> pattern_formatter::clone() const
  872. {
  873. return details::make_unique<pattern_formatter>(pattern_, pattern_time_type_, eol_);
  874. }
  875. SPDLOG_INLINE void pattern_formatter::format(const details::log_msg &msg, memory_buf_t &dest)
  876. {
  877. #ifndef SPDLOG_NO_DATETIME
  878. auto secs = std::chrono::duration_cast<std::chrono::seconds>(msg.time.time_since_epoch());
  879. if (secs != last_log_secs_)
  880. {
  881. cached_tm_ = get_time_(msg);
  882. last_log_secs_ = secs;
  883. }
  884. #endif
  885. for (auto &f : formatters_)
  886. {
  887. f->format(msg, cached_tm_, dest);
  888. }
  889. // write eol
  890. details::fmt_helper::append_string_view(eol_, dest);
  891. }
  892. SPDLOG_INLINE std::tm pattern_formatter::get_time_(const details::log_msg &msg)
  893. {
  894. if (pattern_time_type_ == pattern_time_type::local)
  895. {
  896. return details::os::localtime(log_clock::to_time_t(msg.time));
  897. }
  898. return details::os::gmtime(log_clock::to_time_t(msg.time));
  899. }
  900. template<typename Padder>
  901. SPDLOG_INLINE void pattern_formatter::handle_flag_(char flag, details::padding_info padding)
  902. {
  903. switch (flag)
  904. {
  905. case ('+'): // default formatter
  906. formatters_.push_back(details::make_unique<details::full_formatter>(padding));
  907. break;
  908. case 'n': // logger name
  909. formatters_.push_back(details::make_unique<details::name_formatter<Padder>>(padding));
  910. break;
  911. case 'l': // level
  912. formatters_.push_back(details::make_unique<details::level_formatter<Padder>>(padding));
  913. break;
  914. case 'L': // short level
  915. formatters_.push_back(details::make_unique<details::short_level_formatter<Padder>>(padding));
  916. break;
  917. case ('t'): // thread id
  918. formatters_.push_back(details::make_unique<details::t_formatter<Padder>>(padding));
  919. break;
  920. case ('v'): // the message text
  921. formatters_.push_back(details::make_unique<details::v_formatter<Padder>>(padding));
  922. break;
  923. case ('a'): // weekday
  924. formatters_.push_back(details::make_unique<details::a_formatter<Padder>>(padding));
  925. break;
  926. case ('A'): // short weekday
  927. formatters_.push_back(details::make_unique<details::A_formatter<Padder>>(padding));
  928. break;
  929. case ('b'):
  930. case ('h'): // month
  931. formatters_.push_back(details::make_unique<details::b_formatter<Padder>>(padding));
  932. break;
  933. case ('B'): // short month
  934. formatters_.push_back(details::make_unique<details::B_formatter<Padder>>(padding));
  935. break;
  936. case ('c'): // datetime
  937. formatters_.push_back(details::make_unique<details::c_formatter<Padder>>(padding));
  938. break;
  939. case ('C'): // year 2 digits
  940. formatters_.push_back(details::make_unique<details::C_formatter<Padder>>(padding));
  941. break;
  942. case ('Y'): // year 4 digits
  943. formatters_.push_back(details::make_unique<details::Y_formatter<Padder>>(padding));
  944. break;
  945. case ('D'):
  946. case ('x'): // datetime MM/DD/YY
  947. formatters_.push_back(details::make_unique<details::D_formatter<Padder>>(padding));
  948. break;
  949. case ('m'): // month 1-12
  950. formatters_.push_back(details::make_unique<details::m_formatter<Padder>>(padding));
  951. break;
  952. case ('d'): // day of month 1-31
  953. formatters_.push_back(details::make_unique<details::d_formatter<Padder>>(padding));
  954. break;
  955. case ('H'): // hours 24
  956. formatters_.push_back(details::make_unique<details::H_formatter<Padder>>(padding));
  957. break;
  958. case ('I'): // hours 12
  959. formatters_.push_back(details::make_unique<details::I_formatter<Padder>>(padding));
  960. break;
  961. case ('M'): // minutes
  962. formatters_.push_back(details::make_unique<details::M_formatter<Padder>>(padding));
  963. break;
  964. case ('S'): // seconds
  965. formatters_.push_back(details::make_unique<details::S_formatter<Padder>>(padding));
  966. break;
  967. case ('e'): // milliseconds
  968. formatters_.push_back(details::make_unique<details::e_formatter<Padder>>(padding));
  969. break;
  970. case ('f'): // microseconds
  971. formatters_.push_back(details::make_unique<details::f_formatter<Padder>>(padding));
  972. break;
  973. case ('F'): // nanoseconds
  974. formatters_.push_back(details::make_unique<details::F_formatter<Padder>>(padding));
  975. break;
  976. case ('E'): // seconds since epoch
  977. formatters_.push_back(details::make_unique<details::E_formatter<Padder>>(padding));
  978. break;
  979. case ('p'): // am/pm
  980. formatters_.push_back(details::make_unique<details::p_formatter<Padder>>(padding));
  981. break;
  982. case ('r'): // 12 hour clock 02:55:02 pm
  983. formatters_.push_back(details::make_unique<details::r_formatter<Padder>>(padding));
  984. break;
  985. case ('R'): // 24-hour HH:MM time
  986. formatters_.push_back(details::make_unique<details::R_formatter<Padder>>(padding));
  987. break;
  988. case ('T'):
  989. case ('X'): // ISO 8601 time format (HH:MM:SS)
  990. formatters_.push_back(details::make_unique<details::T_formatter<Padder>>(padding));
  991. break;
  992. case ('z'): // timezone
  993. formatters_.push_back(details::make_unique<details::z_formatter<Padder>>(padding));
  994. break;
  995. case ('P'): // pid
  996. formatters_.push_back(details::make_unique<details::pid_formatter<Padder>>(padding));
  997. break;
  998. case ('^'): // color range start
  999. formatters_.push_back(details::make_unique<details::color_start_formatter>(padding));
  1000. break;
  1001. case ('$'): // color range end
  1002. formatters_.push_back(details::make_unique<details::color_stop_formatter>(padding));
  1003. break;
  1004. case ('@'): // source location (filename:filenumber)
  1005. formatters_.push_back(details::make_unique<details::source_location_formatter<Padder>>(padding));
  1006. break;
  1007. case ('s'): // short source filename - without directory name
  1008. formatters_.push_back(details::make_unique<details::short_filename_formatter<Padder>>(padding));
  1009. break;
  1010. case ('g'): // full source filename
  1011. formatters_.push_back(details::make_unique<details::source_filename_formatter<Padder>>(padding));
  1012. break;
  1013. case ('#'): // source line number
  1014. formatters_.push_back(details::make_unique<details::source_linenum_formatter<Padder>>(padding));
  1015. break;
  1016. case ('!'): // source funcname
  1017. formatters_.push_back(details::make_unique<details::source_funcname_formatter<Padder>>(padding));
  1018. break;
  1019. case ('%'): // % char
  1020. formatters_.push_back(details::make_unique<details::ch_formatter>('%'));
  1021. break;
  1022. case ('u'): // elapsed time since last log message in nanos
  1023. formatters_.push_back(details::make_unique<details::elapsed_formatter<Padder, std::chrono::nanoseconds>>(padding));
  1024. break;
  1025. case ('i'): // elapsed time since last log message in micros
  1026. formatters_.push_back(details::make_unique<details::elapsed_formatter<Padder, std::chrono::microseconds>>(padding));
  1027. break;
  1028. case ('o'): // elapsed time since last log message in millis
  1029. formatters_.push_back(details::make_unique<details::elapsed_formatter<Padder, std::chrono::milliseconds>>(padding));
  1030. break;
  1031. case ('O'): // elapsed time since last log message in seconds
  1032. formatters_.push_back(details::make_unique<details::elapsed_formatter<Padder, std::chrono::seconds>>(padding));
  1033. break;
  1034. default: // Unknown flag appears as is
  1035. auto unknown_flag = details::make_unique<details::aggregate_formatter>();
  1036. unknown_flag->add_ch('%');
  1037. unknown_flag->add_ch(flag);
  1038. formatters_.push_back((std::move(unknown_flag)));
  1039. break;
  1040. }
  1041. }
  1042. // Extract given pad spec (e.g. %8X)
  1043. // Advance the given it pass the end of the padding spec found (if any)
  1044. // Return padding.
  1045. SPDLOG_INLINE details::padding_info pattern_formatter::handle_padspec_(std::string::const_iterator &it, std::string::const_iterator end)
  1046. {
  1047. using details::padding_info;
  1048. using details::scoped_padder;
  1049. const size_t max_width = 64;
  1050. if (it == end)
  1051. {
  1052. return padding_info{};
  1053. }
  1054. padding_info::pad_side side;
  1055. switch (*it)
  1056. {
  1057. case '-':
  1058. side = padding_info::right;
  1059. ++it;
  1060. break;
  1061. case '=':
  1062. side = padding_info::center;
  1063. ++it;
  1064. break;
  1065. default:
  1066. side = details::padding_info::left;
  1067. break;
  1068. }
  1069. if (it == end || !std::isdigit(static_cast<unsigned char>(*it)))
  1070. {
  1071. return padding_info{0, side};
  1072. }
  1073. auto width = static_cast<size_t>(*it) - '0';
  1074. for (++it; it != end && std::isdigit(static_cast<unsigned char>(*it)); ++it)
  1075. {
  1076. auto digit = static_cast<size_t>(*it) - '0';
  1077. width = width * 10 + digit;
  1078. }
  1079. return details::padding_info{std::min<size_t>(width, max_width), side};
  1080. }
  1081. SPDLOG_INLINE void pattern_formatter::compile_pattern_(const std::string &pattern)
  1082. {
  1083. auto end = pattern.end();
  1084. std::unique_ptr<details::aggregate_formatter> user_chars;
  1085. formatters_.clear();
  1086. for (auto it = pattern.begin(); it != end; ++it)
  1087. {
  1088. if (*it == '%')
  1089. {
  1090. if (user_chars) // append user chars found so far
  1091. {
  1092. formatters_.push_back(std::move(user_chars));
  1093. }
  1094. auto padding = handle_padspec_(++it, end);
  1095. if (it != end)
  1096. {
  1097. if (padding.enabled())
  1098. {
  1099. handle_flag_<details::scoped_padder>(*it, padding);
  1100. }
  1101. else
  1102. {
  1103. handle_flag_<details::null_scoped_padder>(*it, padding);
  1104. }
  1105. }
  1106. else
  1107. {
  1108. break;
  1109. }
  1110. }
  1111. else // chars not following the % sign should be displayed as is
  1112. {
  1113. if (!user_chars)
  1114. {
  1115. user_chars = details::make_unique<details::aggregate_formatter>();
  1116. }
  1117. user_chars->add_ch(*it);
  1118. }
  1119. }
  1120. if (user_chars) // append raw chars found so far
  1121. {
  1122. formatters_.push_back(std::move(user_chars));
  1123. }
  1124. }
  1125. } // namespace spdlog