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.

pattern_formatter_impl.h 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636
  1. //
  2. // Copyright(c) 2015 Gabi Melman.
  3. // Distributed under the MIT License (http://opensource.org/licenses/MIT)
  4. //
  5. #pragma once
  6. #include <spdlog/formatter.h>
  7. #include <spdlog/details/log_msg.h>
  8. #include <spdlog/details/os.h>
  9. #include <spdlog/fmt/fmt.h>
  10. #include <chrono>
  11. #include <ctime>
  12. #include <memory>
  13. #include <mutex>
  14. #include <string>
  15. #include <thread>
  16. #include <utility>
  17. #include <vector>
  18. namespace spdlog
  19. {
  20. namespace details
  21. {
  22. class flag_formatter
  23. {
  24. public:
  25. virtual ~flag_formatter()
  26. {}
  27. virtual void format(details::log_msg& msg, const std::tm& tm_time) = 0;
  28. };
  29. ///////////////////////////////////////////////////////////////////////
  30. // name & level pattern appenders
  31. ///////////////////////////////////////////////////////////////////////
  32. namespace
  33. {
  34. class name_formatter:public flag_formatter
  35. {
  36. void format(details::log_msg& msg, const std::tm&) override
  37. {
  38. msg.formatted << *msg.logger_name;
  39. }
  40. };
  41. }
  42. // log level appender
  43. class level_formatter:public flag_formatter
  44. {
  45. void format(details::log_msg& msg, const std::tm&) override
  46. {
  47. msg.formatted << level::to_str(msg.level);
  48. }
  49. };
  50. // short log level appender
  51. class short_level_formatter:public flag_formatter
  52. {
  53. void format(details::log_msg& msg, const std::tm&) override
  54. {
  55. msg.formatted << level::to_short_str(msg.level);
  56. }
  57. };
  58. ///////////////////////////////////////////////////////////////////////
  59. // Date time pattern appenders
  60. ///////////////////////////////////////////////////////////////////////
  61. static const char* ampm(const tm& t)
  62. {
  63. return t.tm_hour >= 12 ? "PM" : "AM";
  64. }
  65. static int to12h(const tm& t)
  66. {
  67. return t.tm_hour > 12 ? t.tm_hour - 12 : t.tm_hour;
  68. }
  69. //Abbreviated weekday name
  70. static const std::string days[] { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
  71. class a_formatter:public flag_formatter
  72. {
  73. void format(details::log_msg& msg, const std::tm& tm_time) override
  74. {
  75. msg.formatted << days[tm_time.tm_wday];
  76. }
  77. };
  78. //Full weekday name
  79. static const std::string full_days[] { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
  80. class A_formatter:public flag_formatter
  81. {
  82. void format(details::log_msg& msg, const std::tm& tm_time) override
  83. {
  84. msg.formatted << full_days[tm_time.tm_wday];
  85. }
  86. };
  87. //Abbreviated month
  88. static const std::string months[] { "Jan", "Feb", "Mar", "Apr", "May", "June", "July", "Aug", "Sept", "Oct", "Nov", "Dec" };
  89. class b_formatter:public flag_formatter
  90. {
  91. void format(details::log_msg& msg, const std::tm& tm_time) override
  92. {
  93. msg.formatted << months[tm_time.tm_mon];
  94. }
  95. };
  96. //Full month name
  97. static const std::string full_months[] { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
  98. class B_formatter:public flag_formatter
  99. {
  100. void format(details::log_msg& msg, const std::tm& tm_time) override
  101. {
  102. msg.formatted << full_months[tm_time.tm_mon];
  103. }
  104. };
  105. //write 2 ints seperated by sep with padding of 2
  106. static fmt::MemoryWriter& pad_n_join(fmt::MemoryWriter& w, int v1, int v2, char sep)
  107. {
  108. w << fmt::pad(v1, 2, '0') << sep << fmt::pad(v2, 2, '0');
  109. return w;
  110. }
  111. //write 3 ints seperated by sep with padding of 2
  112. static fmt::MemoryWriter& pad_n_join(fmt::MemoryWriter& w, int v1, int v2, int v3, char sep)
  113. {
  114. w << fmt::pad(v1, 2, '0') << sep << fmt::pad(v2, 2, '0') << sep << fmt::pad(v3, 2, '0');
  115. return w;
  116. }
  117. //Date and time representation (Thu Aug 23 15:35:46 2014)
  118. class c_formatter:public flag_formatter
  119. {
  120. void format(details::log_msg& msg, const std::tm& tm_time) override
  121. {
  122. msg.formatted << days[tm_time.tm_wday] << ' ' << months[tm_time.tm_mon] << ' ' << tm_time.tm_mday << ' ';
  123. pad_n_join(msg.formatted, tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec, ':') << ' ' << tm_time.tm_year + 1900;
  124. }
  125. };
  126. // year - 2 digit
  127. class C_formatter:public flag_formatter
  128. {
  129. void format(details::log_msg& msg, const std::tm& tm_time) override
  130. {
  131. msg.formatted << fmt::pad(tm_time.tm_year % 100, 2, '0');
  132. }
  133. };
  134. // Short MM/DD/YY date, equivalent to %m/%d/%y 08/23/01
  135. class D_formatter:public flag_formatter
  136. {
  137. void format(details::log_msg& msg, const std::tm& tm_time) override
  138. {
  139. pad_n_join(msg.formatted, tm_time.tm_mon + 1, tm_time.tm_mday, tm_time.tm_year % 100, '/');
  140. }
  141. };
  142. // year - 4 digit
  143. class Y_formatter:public flag_formatter
  144. {
  145. void format(details::log_msg& msg, const std::tm& tm_time) override
  146. {
  147. msg.formatted << tm_time.tm_year + 1900;
  148. }
  149. };
  150. // month 1-12
  151. class m_formatter:public flag_formatter
  152. {
  153. void format(details::log_msg& msg, const std::tm& tm_time) override
  154. {
  155. msg.formatted << fmt::pad(tm_time.tm_mon + 1, 2, '0');
  156. }
  157. };
  158. // day of month 1-31
  159. class d_formatter:public flag_formatter
  160. {
  161. void format(details::log_msg& msg, const std::tm& tm_time) override
  162. {
  163. msg.formatted << fmt::pad(tm_time.tm_mday, 2, '0');
  164. }
  165. };
  166. // hours in 24 format 0-23
  167. class H_formatter:public flag_formatter
  168. {
  169. void format(details::log_msg& msg, const std::tm& tm_time) override
  170. {
  171. msg.formatted << fmt::pad(tm_time.tm_hour, 2, '0');
  172. }
  173. };
  174. // hours in 12 format 1-12
  175. class I_formatter:public flag_formatter
  176. {
  177. void format(details::log_msg& msg, const std::tm& tm_time) override
  178. {
  179. msg.formatted << fmt::pad(to12h(tm_time), 2, '0');
  180. }
  181. };
  182. // minutes 0-59
  183. class M_formatter:public flag_formatter
  184. {
  185. void format(details::log_msg& msg, const std::tm& tm_time) override
  186. {
  187. msg.formatted << fmt::pad(tm_time.tm_min, 2, '0');
  188. }
  189. };
  190. // seconds 0-59
  191. class S_formatter:public flag_formatter
  192. {
  193. void format(details::log_msg& msg, const std::tm& tm_time) override
  194. {
  195. msg.formatted << fmt::pad(tm_time.tm_sec, 2, '0');
  196. }
  197. };
  198. // milliseconds
  199. class e_formatter:public flag_formatter
  200. {
  201. void format(details::log_msg& msg, const std::tm&) override
  202. {
  203. auto duration = msg.time.time_since_epoch();
  204. auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count() % 1000;
  205. msg.formatted << fmt::pad(static_cast<int>(millis), 3, '0');
  206. }
  207. };
  208. // microseconds
  209. class f_formatter:public flag_formatter
  210. {
  211. void format(details::log_msg& msg, const std::tm&) override
  212. {
  213. auto duration = msg.time.time_since_epoch();
  214. auto micros = std::chrono::duration_cast<std::chrono::microseconds>(duration).count() % 1000000;
  215. msg.formatted << fmt::pad(static_cast<int>(micros), 6, '0');
  216. }
  217. };
  218. // nanoseconds
  219. class F_formatter:public flag_formatter
  220. {
  221. void format(details::log_msg& msg, const std::tm&) override
  222. {
  223. auto duration = msg.time.time_since_epoch();
  224. auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(duration).count() % 1000000000;
  225. msg.formatted << fmt::pad(static_cast<int>(ns), 9, '0');
  226. }
  227. };
  228. // AM/PM
  229. class p_formatter:public flag_formatter
  230. {
  231. void format(details::log_msg& msg, const std::tm& tm_time) override
  232. {
  233. msg.formatted << ampm(tm_time);
  234. }
  235. };
  236. // 12 hour clock 02:55:02 pm
  237. class r_formatter:public flag_formatter
  238. {
  239. void format(details::log_msg& msg, const std::tm& tm_time) override
  240. {
  241. pad_n_join(msg.formatted, to12h(tm_time), tm_time.tm_min, tm_time.tm_sec, ':') << ' ' << ampm(tm_time);
  242. }
  243. };
  244. // 24-hour HH:MM time, equivalent to %H:%M
  245. class R_formatter:public flag_formatter
  246. {
  247. void format(details::log_msg& msg, const std::tm& tm_time) override
  248. {
  249. pad_n_join(msg.formatted, tm_time.tm_hour, tm_time.tm_min, ':');
  250. }
  251. };
  252. // ISO 8601 time format (HH:MM:SS), equivalent to %H:%M:%S
  253. class T_formatter:public flag_formatter
  254. {
  255. void format(details::log_msg& msg, const std::tm& tm_time) override
  256. {
  257. pad_n_join(msg.formatted, tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec, ':');
  258. }
  259. };
  260. // ISO 8601 offset from UTC in timezone (+-HH:MM)
  261. class z_formatter:public flag_formatter
  262. {
  263. public:
  264. const std::chrono::seconds cache_refresh = std::chrono::seconds(5);
  265. z_formatter():_last_update(std::chrono::seconds(0))
  266. {}
  267. z_formatter(const z_formatter&) = delete;
  268. z_formatter& operator=(const z_formatter&) = delete;
  269. void format(details::log_msg& msg, const std::tm& tm_time) override
  270. {
  271. #ifdef _WIN32
  272. int total_minutes = get_cached_offset(msg, tm_time);
  273. #else
  274. // No need to chache under gcc,
  275. // it is very fast (already stored in tm.tm_gmtoff)
  276. int total_minutes = os::utc_minutes_offset(tm_time);
  277. #endif
  278. bool is_negative = total_minutes < 0;
  279. char sign;
  280. if (is_negative)
  281. {
  282. total_minutes = -total_minutes;
  283. sign = '-';
  284. }
  285. else
  286. {
  287. sign = '+';
  288. }
  289. int h = total_minutes / 60;
  290. int m = total_minutes % 60;
  291. msg.formatted << sign;
  292. pad_n_join(msg.formatted, h, m, ':');
  293. }
  294. private:
  295. log_clock::time_point _last_update;
  296. int _offset_minutes;
  297. std::mutex _mutex;
  298. int get_cached_offset(const log_msg& msg, const std::tm& tm_time)
  299. {
  300. using namespace std::chrono;
  301. std::lock_guard<std::mutex> l(_mutex);
  302. if (msg.time - _last_update >= cache_refresh)
  303. {
  304. _offset_minutes = os::utc_minutes_offset(tm_time);
  305. _last_update = msg.time;
  306. }
  307. return _offset_minutes;
  308. }
  309. };
  310. //Thread id
  311. class t_formatter:public flag_formatter
  312. {
  313. void format(details::log_msg& msg, const std::tm&) override
  314. {
  315. msg.formatted << msg.thread_id;
  316. }
  317. };
  318. class v_formatter:public flag_formatter
  319. {
  320. void format(details::log_msg& msg, const std::tm&) override
  321. {
  322. msg.formatted << fmt::StringRef(msg.raw.data(), msg.raw.size());
  323. }
  324. };
  325. class ch_formatter:public flag_formatter
  326. {
  327. public:
  328. explicit ch_formatter(char ch): _ch(ch)
  329. {}
  330. void format(details::log_msg& msg, const std::tm&) override
  331. {
  332. msg.formatted << _ch;
  333. }
  334. private:
  335. char _ch;
  336. };
  337. //aggregate user chars to display as is
  338. class aggregate_formatter:public flag_formatter
  339. {
  340. public:
  341. aggregate_formatter()
  342. {}
  343. void add_ch(char ch)
  344. {
  345. _str += ch;
  346. }
  347. void format(details::log_msg& msg, const std::tm&) override
  348. {
  349. msg.formatted << _str;
  350. }
  351. private:
  352. std::string _str;
  353. };
  354. // Full info formatter
  355. // pattern: [%Y-%m-%d %H:%M:%S.%e] [%n] [%l] %v
  356. class full_formatter:public flag_formatter
  357. {
  358. void format(details::log_msg& msg, const std::tm& tm_time) override
  359. {
  360. #ifndef SPDLOG_NO_DATETIME
  361. auto duration = msg.time.time_since_epoch();
  362. auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count() % 1000;
  363. /* Slower version(while still very fast - about 3.2 million lines/sec under 10 threads),
  364. msg.formatted.write("[{:d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}.{:03d}] [{}] [{}] {} ",
  365. tm_time.tm_year + 1900,
  366. tm_time.tm_mon + 1,
  367. tm_time.tm_mday,
  368. tm_time.tm_hour,
  369. tm_time.tm_min,
  370. tm_time.tm_sec,
  371. static_cast<int>(millis),
  372. msg.logger_name,
  373. level::to_str(msg.level),
  374. msg.raw.str());*/
  375. // Faster (albeit uglier) way to format the line (5.6 million lines/sec under 10 threads)
  376. msg.formatted << '[' << static_cast<unsigned int>(tm_time.tm_year + 1900) << '-'
  377. << fmt::pad(static_cast<unsigned int>(tm_time.tm_mon + 1), 2, '0') << '-'
  378. << fmt::pad(static_cast<unsigned int>(tm_time.tm_mday), 2, '0') << ' '
  379. << fmt::pad(static_cast<unsigned int>(tm_time.tm_hour), 2, '0') << ':'
  380. << fmt::pad(static_cast<unsigned int>(tm_time.tm_min), 2, '0') << ':'
  381. << fmt::pad(static_cast<unsigned int>(tm_time.tm_sec), 2, '0') << '.'
  382. << fmt::pad(static_cast<unsigned int>(millis), 3, '0') << "] ";
  383. //no datetime needed
  384. #else
  385. (void)tm_time;
  386. #endif
  387. #ifndef SPDLOG_NO_NAME
  388. msg.formatted << '[' << *msg.logger_name << "] ";
  389. #endif
  390. msg.formatted << '[' << level::to_str(msg.level) << "] ";
  391. msg.formatted << fmt::StringRef(msg.raw.data(), msg.raw.size());
  392. }
  393. };
  394. }
  395. }
  396. ///////////////////////////////////////////////////////////////////////////////
  397. // pattern_formatter inline impl
  398. ///////////////////////////////////////////////////////////////////////////////
  399. inline spdlog::pattern_formatter::pattern_formatter(const std::string& pattern)
  400. {
  401. compile_pattern(pattern);
  402. }
  403. inline void spdlog::pattern_formatter::compile_pattern(const std::string& pattern)
  404. {
  405. auto end = pattern.end();
  406. std::unique_ptr<details::aggregate_formatter> user_chars;
  407. for (auto it = pattern.begin(); it != end; ++it)
  408. {
  409. if (*it == '%')
  410. {
  411. if (user_chars) //append user chars found so far
  412. _formatters.push_back(std::move(user_chars));
  413. if (++it != end)
  414. handle_flag(*it);
  415. else
  416. break;
  417. }
  418. else // chars not following the % sign should be displayed as is
  419. {
  420. if (!user_chars)
  421. user_chars = std::unique_ptr<details::aggregate_formatter>(new details::aggregate_formatter());
  422. user_chars->add_ch(*it);
  423. }
  424. }
  425. if (user_chars) //append raw chars found so far
  426. {
  427. _formatters.push_back(std::move(user_chars));
  428. }
  429. }
  430. inline void spdlog::pattern_formatter::handle_flag(char flag)
  431. {
  432. switch (flag)
  433. {
  434. // logger name
  435. case 'n':
  436. _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::name_formatter()));
  437. break;
  438. case 'l':
  439. _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::level_formatter()));
  440. break;
  441. case 'L':
  442. _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::short_level_formatter()));
  443. break;
  444. case('t'):
  445. _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::t_formatter()));
  446. break;
  447. case('v'):
  448. _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::v_formatter()));
  449. break;
  450. case('a'):
  451. _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::a_formatter()));
  452. break;
  453. case('A'):
  454. _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::A_formatter()));
  455. break;
  456. case('b'):
  457. case('h'):
  458. _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::b_formatter()));
  459. break;
  460. case('B'):
  461. _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::B_formatter()));
  462. break;
  463. case('c'):
  464. _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::c_formatter()));
  465. break;
  466. case('C'):
  467. _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::C_formatter()));
  468. break;
  469. case('Y'):
  470. _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::Y_formatter()));
  471. break;
  472. case('D'):
  473. case('x'):
  474. _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::D_formatter()));
  475. break;
  476. case('m'):
  477. _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::m_formatter()));
  478. break;
  479. case('d'):
  480. _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::d_formatter()));
  481. break;
  482. case('H'):
  483. _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::H_formatter()));
  484. break;
  485. case('I'):
  486. _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::I_formatter()));
  487. break;
  488. case('M'):
  489. _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::M_formatter()));
  490. break;
  491. case('S'):
  492. _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::S_formatter()));
  493. break;
  494. case('e'):
  495. _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::e_formatter()));
  496. break;
  497. case('f'):
  498. _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::f_formatter()));
  499. break;
  500. case('F'):
  501. _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::F_formatter()));
  502. break;
  503. case('p'):
  504. _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::p_formatter()));
  505. break;
  506. case('r'):
  507. _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::r_formatter()));
  508. break;
  509. case('R'):
  510. _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::R_formatter()));
  511. break;
  512. case('T'):
  513. case('X'):
  514. _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::T_formatter()));
  515. break;
  516. case('z'):
  517. _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::z_formatter()));
  518. break;
  519. case ('+'):
  520. _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::full_formatter()));
  521. break;
  522. default: //Unkown flag appears as is
  523. _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::ch_formatter('%')));
  524. _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::ch_formatter(flag)));
  525. break;
  526. }
  527. }
  528. inline void spdlog::pattern_formatter::format(details::log_msg& msg)
  529. {
  530. #ifndef SPDLOG_NO_DATETIME
  531. auto tm_time = details::os::localtime(log_clock::to_time_t(msg.time));
  532. #else
  533. std::tm tm_time;
  534. #endif
  535. for (auto &f : _formatters)
  536. {
  537. f->format(msg, tm_time);
  538. }
  539. //write eol
  540. msg.formatted.write(details::os::eol, details::os::eol_size);
  541. }