诸暨麻将添加redis
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.
 
 
 
 
 
 

1318 lines
39 KiB

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