File indexing completed on 2025-12-24 10:32:35
0001
0002
0003
0004 #pragma once
0005
0006 #ifndef SPDLOG_HEADER_ONLY
0007 #include <spdlog/pattern_formatter.h>
0008 #endif
0009
0010 #include <spdlog/details/fmt_helper.h>
0011 #include <spdlog/details/log_msg.h>
0012 #include <spdlog/details/os.h>
0013
0014 #ifndef SPDLOG_NO_TLS
0015 #include <spdlog/mdc.h>
0016 #endif
0017
0018 #include <spdlog/fmt/fmt.h>
0019 #include <spdlog/formatter.h>
0020
0021 #include <algorithm>
0022 #include <array>
0023 #include <cctype>
0024 #include <chrono>
0025 #include <cstring>
0026 #include <ctime>
0027 #include <iterator>
0028 #include <memory>
0029 #include <mutex>
0030 #include <string>
0031 #include <thread>
0032 #include <utility>
0033 #include <vector>
0034
0035 namespace spdlog {
0036 namespace details {
0037
0038
0039
0040
0041
0042 class scoped_padder {
0043 public:
0044 scoped_padder(size_t wrapped_size, const padding_info &padinfo, memory_buf_t &dest)
0045 : padinfo_(padinfo),
0046 dest_(dest) {
0047 remaining_pad_ = static_cast<long>(padinfo.width_) - static_cast<long>(wrapped_size);
0048 if (remaining_pad_ <= 0) {
0049 return;
0050 }
0051
0052 if (padinfo_.side_ == padding_info::pad_side::left) {
0053 pad_it(remaining_pad_);
0054 remaining_pad_ = 0;
0055 } else if (padinfo_.side_ == padding_info::pad_side::center) {
0056 auto half_pad = remaining_pad_ / 2;
0057 auto reminder = remaining_pad_ & 1;
0058 pad_it(half_pad);
0059 remaining_pad_ = half_pad + reminder;
0060 }
0061 }
0062
0063 template <typename T>
0064 static unsigned int count_digits(T n) {
0065 return fmt_helper::count_digits(n);
0066 }
0067
0068 ~scoped_padder() {
0069 if (remaining_pad_ >= 0) {
0070 pad_it(remaining_pad_);
0071 } else if (padinfo_.truncate_) {
0072 long new_size = static_cast<long>(dest_.size()) + remaining_pad_;
0073 if (new_size < 0) {
0074 new_size = 0;
0075 }
0076 dest_.resize(static_cast<size_t>(new_size));
0077 }
0078 }
0079
0080 private:
0081 void pad_it(long count) {
0082 fmt_helper::append_string_view(string_view_t(spaces_.data(), static_cast<size_t>(count)),
0083 dest_);
0084 }
0085
0086 const padding_info &padinfo_;
0087 memory_buf_t &dest_;
0088 long remaining_pad_;
0089 string_view_t spaces_{" ", 64};
0090 };
0091
0092 struct null_scoped_padder {
0093 null_scoped_padder(size_t ,
0094 const padding_info & ,
0095 memory_buf_t & ) {}
0096
0097 template <typename T>
0098 static unsigned int count_digits(T ) {
0099 return 0;
0100 }
0101 };
0102
0103 template <typename ScopedPadder>
0104 class name_formatter final : public flag_formatter {
0105 public:
0106 explicit name_formatter(padding_info padinfo)
0107 : flag_formatter(padinfo) {}
0108
0109 void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override {
0110 ScopedPadder p(msg.logger_name.size(), padinfo_, dest);
0111 fmt_helper::append_string_view(msg.logger_name, dest);
0112 }
0113 };
0114
0115
0116 template <typename ScopedPadder>
0117 class level_formatter final : public flag_formatter {
0118 public:
0119 explicit level_formatter(padding_info padinfo)
0120 : flag_formatter(padinfo) {}
0121
0122 void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override {
0123 const string_view_t &level_name = level::to_string_view(msg.level);
0124 ScopedPadder p(level_name.size(), padinfo_, dest);
0125 fmt_helper::append_string_view(level_name, dest);
0126 }
0127 };
0128
0129
0130 template <typename ScopedPadder>
0131 class short_level_formatter final : public flag_formatter {
0132 public:
0133 explicit short_level_formatter(padding_info padinfo)
0134 : flag_formatter(padinfo) {}
0135
0136 void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override {
0137 string_view_t level_name{level::to_short_c_str(msg.level)};
0138 ScopedPadder p(level_name.size(), padinfo_, dest);
0139 fmt_helper::append_string_view(level_name, dest);
0140 }
0141 };
0142
0143
0144
0145
0146
0147 static const char *ampm(const tm &t) { return t.tm_hour >= 12 ? "PM" : "AM"; }
0148
0149 static int to12h(const tm &t) { return t.tm_hour > 12 ? t.tm_hour - 12 : t.tm_hour; }
0150
0151
0152 static std::array<const char *, 7> days{{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}};
0153
0154 template <typename ScopedPadder>
0155 class a_formatter final : public flag_formatter {
0156 public:
0157 explicit a_formatter(padding_info padinfo)
0158 : flag_formatter(padinfo) {}
0159
0160 void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override {
0161 string_view_t field_value{days[static_cast<size_t>(tm_time.tm_wday)]};
0162 ScopedPadder p(field_value.size(), padinfo_, dest);
0163 fmt_helper::append_string_view(field_value, dest);
0164 }
0165 };
0166
0167
0168 static std::array<const char *, 7> full_days{
0169 {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}};
0170
0171 template <typename ScopedPadder>
0172 class A_formatter : public flag_formatter {
0173 public:
0174 explicit A_formatter(padding_info padinfo)
0175 : flag_formatter(padinfo) {}
0176
0177 void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override {
0178 string_view_t field_value{full_days[static_cast<size_t>(tm_time.tm_wday)]};
0179 ScopedPadder p(field_value.size(), padinfo_, dest);
0180 fmt_helper::append_string_view(field_value, dest);
0181 }
0182 };
0183
0184
0185 static const std::array<const char *, 12> months{
0186 {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}};
0187
0188 template <typename ScopedPadder>
0189 class b_formatter final : public flag_formatter {
0190 public:
0191 explicit b_formatter(padding_info padinfo)
0192 : flag_formatter(padinfo) {}
0193
0194 void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override {
0195 string_view_t field_value{months[static_cast<size_t>(tm_time.tm_mon)]};
0196 ScopedPadder p(field_value.size(), padinfo_, dest);
0197 fmt_helper::append_string_view(field_value, dest);
0198 }
0199 };
0200
0201
0202 static const std::array<const char *, 12> full_months{{"January", "February", "March", "April",
0203 "May", "June", "July", "August", "September",
0204 "October", "November", "December"}};
0205
0206 template <typename ScopedPadder>
0207 class B_formatter final : public flag_formatter {
0208 public:
0209 explicit B_formatter(padding_info padinfo)
0210 : flag_formatter(padinfo) {}
0211
0212 void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override {
0213 string_view_t field_value{full_months[static_cast<size_t>(tm_time.tm_mon)]};
0214 ScopedPadder p(field_value.size(), padinfo_, dest);
0215 fmt_helper::append_string_view(field_value, dest);
0216 }
0217 };
0218
0219
0220 template <typename ScopedPadder>
0221 class c_formatter final : public flag_formatter {
0222 public:
0223 explicit c_formatter(padding_info padinfo)
0224 : flag_formatter(padinfo) {}
0225
0226 void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override {
0227 const size_t field_size = 24;
0228 ScopedPadder p(field_size, padinfo_, dest);
0229
0230 fmt_helper::append_string_view(days[static_cast<size_t>(tm_time.tm_wday)], dest);
0231 dest.push_back(' ');
0232 fmt_helper::append_string_view(months[static_cast<size_t>(tm_time.tm_mon)], dest);
0233 dest.push_back(' ');
0234 fmt_helper::append_int(tm_time.tm_mday, dest);
0235 dest.push_back(' ');
0236
0237
0238 fmt_helper::pad2(tm_time.tm_hour, dest);
0239 dest.push_back(':');
0240 fmt_helper::pad2(tm_time.tm_min, dest);
0241 dest.push_back(':');
0242 fmt_helper::pad2(tm_time.tm_sec, dest);
0243 dest.push_back(' ');
0244 fmt_helper::append_int(tm_time.tm_year + 1900, dest);
0245 }
0246 };
0247
0248
0249 template <typename ScopedPadder>
0250 class C_formatter final : public flag_formatter {
0251 public:
0252 explicit C_formatter(padding_info padinfo)
0253 : flag_formatter(padinfo) {}
0254
0255 void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override {
0256 const size_t field_size = 2;
0257 ScopedPadder p(field_size, padinfo_, dest);
0258 fmt_helper::pad2(tm_time.tm_year % 100, dest);
0259 }
0260 };
0261
0262
0263 template <typename ScopedPadder>
0264 class D_formatter final : public flag_formatter {
0265 public:
0266 explicit D_formatter(padding_info padinfo)
0267 : flag_formatter(padinfo) {}
0268
0269 void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override {
0270 const size_t field_size = 8;
0271 ScopedPadder p(field_size, padinfo_, dest);
0272
0273 fmt_helper::pad2(tm_time.tm_mon + 1, dest);
0274 dest.push_back('/');
0275 fmt_helper::pad2(tm_time.tm_mday, dest);
0276 dest.push_back('/');
0277 fmt_helper::pad2(tm_time.tm_year % 100, dest);
0278 }
0279 };
0280
0281
0282 template <typename ScopedPadder>
0283 class Y_formatter final : public flag_formatter {
0284 public:
0285 explicit Y_formatter(padding_info padinfo)
0286 : flag_formatter(padinfo) {}
0287
0288 void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override {
0289 const size_t field_size = 4;
0290 ScopedPadder p(field_size, padinfo_, dest);
0291 fmt_helper::append_int(tm_time.tm_year + 1900, dest);
0292 }
0293 };
0294
0295
0296 template <typename ScopedPadder>
0297 class m_formatter final : public flag_formatter {
0298 public:
0299 explicit m_formatter(padding_info padinfo)
0300 : flag_formatter(padinfo) {}
0301
0302 void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override {
0303 const size_t field_size = 2;
0304 ScopedPadder p(field_size, padinfo_, dest);
0305 fmt_helper::pad2(tm_time.tm_mon + 1, dest);
0306 }
0307 };
0308
0309
0310 template <typename ScopedPadder>
0311 class d_formatter final : public flag_formatter {
0312 public:
0313 explicit d_formatter(padding_info padinfo)
0314 : flag_formatter(padinfo) {}
0315
0316 void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override {
0317 const size_t field_size = 2;
0318 ScopedPadder p(field_size, padinfo_, dest);
0319 fmt_helper::pad2(tm_time.tm_mday, dest);
0320 }
0321 };
0322
0323
0324 template <typename ScopedPadder>
0325 class H_formatter final : public flag_formatter {
0326 public:
0327 explicit H_formatter(padding_info padinfo)
0328 : flag_formatter(padinfo) {}
0329
0330 void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override {
0331 const size_t field_size = 2;
0332 ScopedPadder p(field_size, padinfo_, dest);
0333 fmt_helper::pad2(tm_time.tm_hour, dest);
0334 }
0335 };
0336
0337
0338 template <typename ScopedPadder>
0339 class I_formatter final : public flag_formatter {
0340 public:
0341 explicit I_formatter(padding_info padinfo)
0342 : flag_formatter(padinfo) {}
0343
0344 void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override {
0345 const size_t field_size = 2;
0346 ScopedPadder p(field_size, padinfo_, dest);
0347 fmt_helper::pad2(to12h(tm_time), dest);
0348 }
0349 };
0350
0351
0352 template <typename ScopedPadder>
0353 class M_formatter final : public flag_formatter {
0354 public:
0355 explicit M_formatter(padding_info padinfo)
0356 : flag_formatter(padinfo) {}
0357
0358 void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override {
0359 const size_t field_size = 2;
0360 ScopedPadder p(field_size, padinfo_, dest);
0361 fmt_helper::pad2(tm_time.tm_min, dest);
0362 }
0363 };
0364
0365
0366 template <typename ScopedPadder>
0367 class S_formatter final : public flag_formatter {
0368 public:
0369 explicit S_formatter(padding_info padinfo)
0370 : flag_formatter(padinfo) {}
0371
0372 void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override {
0373 const size_t field_size = 2;
0374 ScopedPadder p(field_size, padinfo_, dest);
0375 fmt_helper::pad2(tm_time.tm_sec, dest);
0376 }
0377 };
0378
0379
0380 template <typename ScopedPadder>
0381 class e_formatter final : public flag_formatter {
0382 public:
0383 explicit e_formatter(padding_info padinfo)
0384 : flag_formatter(padinfo) {}
0385
0386 void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override {
0387 auto millis = fmt_helper::time_fraction<std::chrono::milliseconds>(msg.time);
0388 const size_t field_size = 3;
0389 ScopedPadder p(field_size, padinfo_, dest);
0390 fmt_helper::pad3(static_cast<uint32_t>(millis.count()), dest);
0391 }
0392 };
0393
0394
0395 template <typename ScopedPadder>
0396 class f_formatter final : public flag_formatter {
0397 public:
0398 explicit f_formatter(padding_info padinfo)
0399 : flag_formatter(padinfo) {}
0400
0401 void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override {
0402 auto micros = fmt_helper::time_fraction<std::chrono::microseconds>(msg.time);
0403
0404 const size_t field_size = 6;
0405 ScopedPadder p(field_size, padinfo_, dest);
0406 fmt_helper::pad6(static_cast<size_t>(micros.count()), dest);
0407 }
0408 };
0409
0410
0411 template <typename ScopedPadder>
0412 class F_formatter final : public flag_formatter {
0413 public:
0414 explicit F_formatter(padding_info padinfo)
0415 : flag_formatter(padinfo) {}
0416
0417 void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override {
0418 auto ns = fmt_helper::time_fraction<std::chrono::nanoseconds>(msg.time);
0419 const size_t field_size = 9;
0420 ScopedPadder p(field_size, padinfo_, dest);
0421 fmt_helper::pad9(static_cast<size_t>(ns.count()), dest);
0422 }
0423 };
0424
0425
0426 template <typename ScopedPadder>
0427 class E_formatter final : public flag_formatter {
0428 public:
0429 explicit E_formatter(padding_info padinfo)
0430 : flag_formatter(padinfo) {}
0431
0432 void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override {
0433 const size_t field_size = 10;
0434 ScopedPadder p(field_size, padinfo_, dest);
0435 auto duration = msg.time.time_since_epoch();
0436 auto seconds = std::chrono::duration_cast<std::chrono::seconds>(duration).count();
0437 fmt_helper::append_int(seconds, dest);
0438 }
0439 };
0440
0441
0442 template <typename ScopedPadder>
0443 class p_formatter final : public flag_formatter {
0444 public:
0445 explicit p_formatter(padding_info padinfo)
0446 : flag_formatter(padinfo) {}
0447
0448 void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override {
0449 const size_t field_size = 2;
0450 ScopedPadder p(field_size, padinfo_, dest);
0451 fmt_helper::append_string_view(ampm(tm_time), dest);
0452 }
0453 };
0454
0455
0456 template <typename ScopedPadder>
0457 class r_formatter final : public flag_formatter {
0458 public:
0459 explicit r_formatter(padding_info padinfo)
0460 : flag_formatter(padinfo) {}
0461
0462 void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override {
0463 const size_t field_size = 11;
0464 ScopedPadder p(field_size, padinfo_, dest);
0465
0466 fmt_helper::pad2(to12h(tm_time), dest);
0467 dest.push_back(':');
0468 fmt_helper::pad2(tm_time.tm_min, dest);
0469 dest.push_back(':');
0470 fmt_helper::pad2(tm_time.tm_sec, dest);
0471 dest.push_back(' ');
0472 fmt_helper::append_string_view(ampm(tm_time), dest);
0473 }
0474 };
0475
0476
0477 template <typename ScopedPadder>
0478 class R_formatter final : public flag_formatter {
0479 public:
0480 explicit R_formatter(padding_info padinfo)
0481 : flag_formatter(padinfo) {}
0482
0483 void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override {
0484 const size_t field_size = 5;
0485 ScopedPadder p(field_size, padinfo_, dest);
0486
0487 fmt_helper::pad2(tm_time.tm_hour, dest);
0488 dest.push_back(':');
0489 fmt_helper::pad2(tm_time.tm_min, dest);
0490 }
0491 };
0492
0493
0494 template <typename ScopedPadder>
0495 class T_formatter final : public flag_formatter {
0496 public:
0497 explicit T_formatter(padding_info padinfo)
0498 : flag_formatter(padinfo) {}
0499
0500 void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override {
0501 const size_t field_size = 8;
0502 ScopedPadder p(field_size, padinfo_, dest);
0503
0504 fmt_helper::pad2(tm_time.tm_hour, dest);
0505 dest.push_back(':');
0506 fmt_helper::pad2(tm_time.tm_min, dest);
0507 dest.push_back(':');
0508 fmt_helper::pad2(tm_time.tm_sec, dest);
0509 }
0510 };
0511
0512
0513 template <typename ScopedPadder>
0514 class z_formatter final : public flag_formatter {
0515 public:
0516 explicit z_formatter(padding_info padinfo)
0517 : flag_formatter(padinfo) {}
0518
0519 z_formatter() = default;
0520 z_formatter(const z_formatter &) = delete;
0521 z_formatter &operator=(const z_formatter &) = delete;
0522
0523 void format(const details::log_msg &msg, const std::tm &tm_time, memory_buf_t &dest) override {
0524 const size_t field_size = 6;
0525 ScopedPadder p(field_size, padinfo_, dest);
0526
0527 auto total_minutes = get_cached_offset(msg, tm_time);
0528 bool is_negative = total_minutes < 0;
0529 if (is_negative) {
0530 total_minutes = -total_minutes;
0531 dest.push_back('-');
0532 } else {
0533 dest.push_back('+');
0534 }
0535
0536 fmt_helper::pad2(total_minutes / 60, dest);
0537 dest.push_back(':');
0538 fmt_helper::pad2(total_minutes % 60, dest);
0539 }
0540
0541 private:
0542 log_clock::time_point last_update_{std::chrono::seconds(0)};
0543 int offset_minutes_{0};
0544
0545 int get_cached_offset(const log_msg &msg, const std::tm &tm_time) {
0546
0547 if (msg.time - last_update_ >= std::chrono::seconds(10)) {
0548 offset_minutes_ = os::utc_minutes_offset(tm_time);
0549 last_update_ = msg.time;
0550 }
0551 return offset_minutes_;
0552 }
0553 };
0554
0555
0556 template <typename ScopedPadder>
0557 class t_formatter final : public flag_formatter {
0558 public:
0559 explicit t_formatter(padding_info padinfo)
0560 : flag_formatter(padinfo) {}
0561
0562 void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override {
0563 const auto field_size = ScopedPadder::count_digits(msg.thread_id);
0564 ScopedPadder p(field_size, padinfo_, dest);
0565 fmt_helper::append_int(msg.thread_id, dest);
0566 }
0567 };
0568
0569
0570 template <typename ScopedPadder>
0571 class pid_formatter final : public flag_formatter {
0572 public:
0573 explicit pid_formatter(padding_info padinfo)
0574 : flag_formatter(padinfo) {}
0575
0576 void format(const details::log_msg &, const std::tm &, memory_buf_t &dest) override {
0577 const auto pid = static_cast<uint32_t>(details::os::pid());
0578 auto field_size = ScopedPadder::count_digits(pid);
0579 ScopedPadder p(field_size, padinfo_, dest);
0580 fmt_helper::append_int(pid, dest);
0581 }
0582 };
0583
0584 template <typename ScopedPadder>
0585 class v_formatter final : public flag_formatter {
0586 public:
0587 explicit v_formatter(padding_info padinfo)
0588 : flag_formatter(padinfo) {}
0589
0590 void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override {
0591 ScopedPadder p(msg.payload.size(), padinfo_, dest);
0592 fmt_helper::append_string_view(msg.payload, dest);
0593 }
0594 };
0595
0596 class ch_formatter final : public flag_formatter {
0597 public:
0598 explicit ch_formatter(char ch)
0599 : ch_(ch) {}
0600
0601 void format(const details::log_msg &, const std::tm &, memory_buf_t &dest) override {
0602 dest.push_back(ch_);
0603 }
0604
0605 private:
0606 char ch_;
0607 };
0608
0609
0610 class aggregate_formatter final : public flag_formatter {
0611 public:
0612 aggregate_formatter() = default;
0613
0614 void add_ch(char ch) { str_ += ch; }
0615 void format(const details::log_msg &, const std::tm &, memory_buf_t &dest) override {
0616 fmt_helper::append_string_view(str_, dest);
0617 }
0618
0619 private:
0620 std::string str_;
0621 };
0622
0623
0624 class color_start_formatter final : public flag_formatter {
0625 public:
0626 explicit color_start_formatter(padding_info padinfo)
0627 : flag_formatter(padinfo) {}
0628
0629 void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override {
0630 msg.color_range_start = dest.size();
0631 }
0632 };
0633
0634 class color_stop_formatter final : public flag_formatter {
0635 public:
0636 explicit color_stop_formatter(padding_info padinfo)
0637 : flag_formatter(padinfo) {}
0638
0639 void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override {
0640 msg.color_range_end = dest.size();
0641 }
0642 };
0643
0644
0645 template <typename ScopedPadder>
0646 class source_location_formatter final : public flag_formatter {
0647 public:
0648 explicit source_location_formatter(padding_info padinfo)
0649 : flag_formatter(padinfo) {}
0650
0651 void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override {
0652 if (msg.source.empty()) {
0653 ScopedPadder p(0, padinfo_, dest);
0654 return;
0655 }
0656
0657 size_t text_size;
0658 if (padinfo_.enabled()) {
0659
0660 text_size = std::char_traits<char>::length(msg.source.filename) +
0661 ScopedPadder::count_digits(msg.source.line) + 1;
0662 } else {
0663 text_size = 0;
0664 }
0665
0666 ScopedPadder p(text_size, padinfo_, dest);
0667 fmt_helper::append_string_view(msg.source.filename, dest);
0668 dest.push_back(':');
0669 fmt_helper::append_int(msg.source.line, dest);
0670 }
0671 };
0672
0673
0674 template <typename ScopedPadder>
0675 class source_filename_formatter final : public flag_formatter {
0676 public:
0677 explicit source_filename_formatter(padding_info padinfo)
0678 : flag_formatter(padinfo) {}
0679
0680 void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override {
0681 if (msg.source.empty()) {
0682 ScopedPadder p(0, padinfo_, dest);
0683 return;
0684 }
0685 size_t text_size =
0686 padinfo_.enabled() ? std::char_traits<char>::length(msg.source.filename) : 0;
0687 ScopedPadder p(text_size, padinfo_, dest);
0688 fmt_helper::append_string_view(msg.source.filename, dest);
0689 }
0690 };
0691
0692 template <typename ScopedPadder>
0693 class short_filename_formatter final : public flag_formatter {
0694 public:
0695 explicit short_filename_formatter(padding_info padinfo)
0696 : flag_formatter(padinfo) {}
0697
0698 #ifdef _MSC_VER
0699 #pragma warning(push)
0700 #pragma warning(disable : 4127)
0701 #endif
0702 static const char *basename(const char *filename) {
0703
0704
0705 if (sizeof(os::folder_seps) == 2) {
0706 const char *rv = std::strrchr(filename, os::folder_seps[0]);
0707 return rv != nullptr ? rv + 1 : filename;
0708 } else {
0709 const std::reverse_iterator<const char *> begin(filename + std::strlen(filename));
0710 const std::reverse_iterator<const char *> end(filename);
0711
0712 const auto it = std::find_first_of(begin, end, std::begin(os::folder_seps),
0713 std::end(os::folder_seps) - 1);
0714 return it != end ? it.base() : filename;
0715 }
0716 }
0717 #ifdef _MSC_VER
0718 #pragma warning(pop)
0719 #endif
0720
0721 void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override {
0722 if (msg.source.empty()) {
0723 ScopedPadder p(0, padinfo_, dest);
0724 return;
0725 }
0726 auto filename = basename(msg.source.filename);
0727 size_t text_size = padinfo_.enabled() ? std::char_traits<char>::length(filename) : 0;
0728 ScopedPadder p(text_size, padinfo_, dest);
0729 fmt_helper::append_string_view(filename, dest);
0730 }
0731 };
0732
0733 template <typename ScopedPadder>
0734 class source_linenum_formatter final : public flag_formatter {
0735 public:
0736 explicit source_linenum_formatter(padding_info padinfo)
0737 : flag_formatter(padinfo) {}
0738
0739 void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override {
0740 if (msg.source.empty()) {
0741 ScopedPadder p(0, padinfo_, dest);
0742 return;
0743 }
0744
0745 auto field_size = ScopedPadder::count_digits(msg.source.line);
0746 ScopedPadder p(field_size, padinfo_, dest);
0747 fmt_helper::append_int(msg.source.line, dest);
0748 }
0749 };
0750
0751
0752 template <typename ScopedPadder>
0753 class source_funcname_formatter final : public flag_formatter {
0754 public:
0755 explicit source_funcname_formatter(padding_info padinfo)
0756 : flag_formatter(padinfo) {}
0757
0758 void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override {
0759 if (msg.source.empty()) {
0760 ScopedPadder p(0, padinfo_, dest);
0761 return;
0762 }
0763 size_t text_size =
0764 padinfo_.enabled() ? std::char_traits<char>::length(msg.source.funcname) : 0;
0765 ScopedPadder p(text_size, padinfo_, dest);
0766 fmt_helper::append_string_view(msg.source.funcname, dest);
0767 }
0768 };
0769
0770
0771 template <typename ScopedPadder, typename Units>
0772 class elapsed_formatter final : public flag_formatter {
0773 public:
0774 using DurationUnits = Units;
0775
0776 explicit elapsed_formatter(padding_info padinfo)
0777 : flag_formatter(padinfo),
0778 last_message_time_(log_clock::now()) {}
0779
0780 void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override {
0781 auto delta = (std::max)(msg.time - last_message_time_, log_clock::duration::zero());
0782 auto delta_units = std::chrono::duration_cast<DurationUnits>(delta);
0783 last_message_time_ = msg.time;
0784 auto delta_count = static_cast<size_t>(delta_units.count());
0785 auto n_digits = static_cast<size_t>(ScopedPadder::count_digits(delta_count));
0786 ScopedPadder p(n_digits, padinfo_, dest);
0787 fmt_helper::append_int(delta_count, dest);
0788 }
0789
0790 private:
0791 log_clock::time_point last_message_time_;
0792 };
0793
0794
0795
0796 #ifndef SPDLOG_NO_TLS
0797 template <typename ScopedPadder>
0798 class mdc_formatter : public flag_formatter {
0799 public:
0800 explicit mdc_formatter(padding_info padinfo)
0801 : flag_formatter(padinfo) {}
0802
0803 void format(const details::log_msg &, const std::tm &, memory_buf_t &dest) override {
0804 auto &mdc_map = mdc::get_context();
0805 if (mdc_map.empty()) {
0806 ScopedPadder p(0, padinfo_, dest);
0807 return;
0808 } else {
0809 format_mdc(mdc_map, dest);
0810 }
0811 }
0812
0813 void format_mdc(const mdc::mdc_map_t &mdc_map, memory_buf_t &dest) {
0814 auto last_element = --mdc_map.end();
0815 for (auto it = mdc_map.begin(); it != mdc_map.end(); ++it) {
0816 auto &pair = *it;
0817 const auto &key = pair.first;
0818 const auto &value = pair.second;
0819 size_t content_size = key.size() + value.size() + 1;
0820
0821 if (it != last_element) {
0822 content_size++;
0823 }
0824
0825 ScopedPadder p(content_size, padinfo_, dest);
0826 fmt_helper::append_string_view(key, dest);
0827 fmt_helper::append_string_view(":", dest);
0828 fmt_helper::append_string_view(value, dest);
0829 if (it != last_element) {
0830 fmt_helper::append_string_view(" ", dest);
0831 }
0832 }
0833 }
0834 };
0835 #endif
0836
0837
0838
0839 class full_formatter final : public flag_formatter {
0840 public:
0841 explicit full_formatter(padding_info padinfo)
0842 : flag_formatter(padinfo) {}
0843
0844 void format(const details::log_msg &msg, const std::tm &tm_time, memory_buf_t &dest) override {
0845 using std::chrono::duration_cast;
0846 using std::chrono::milliseconds;
0847 using std::chrono::seconds;
0848
0849
0850 auto duration = msg.time.time_since_epoch();
0851 auto secs = duration_cast<seconds>(duration);
0852
0853 if (cache_timestamp_ != secs || cached_datetime_.size() == 0) {
0854 cached_datetime_.clear();
0855 cached_datetime_.push_back('[');
0856 fmt_helper::append_int(tm_time.tm_year + 1900, cached_datetime_);
0857 cached_datetime_.push_back('-');
0858
0859 fmt_helper::pad2(tm_time.tm_mon + 1, cached_datetime_);
0860 cached_datetime_.push_back('-');
0861
0862 fmt_helper::pad2(tm_time.tm_mday, cached_datetime_);
0863 cached_datetime_.push_back(' ');
0864
0865 fmt_helper::pad2(tm_time.tm_hour, cached_datetime_);
0866 cached_datetime_.push_back(':');
0867
0868 fmt_helper::pad2(tm_time.tm_min, cached_datetime_);
0869 cached_datetime_.push_back(':');
0870
0871 fmt_helper::pad2(tm_time.tm_sec, cached_datetime_);
0872 cached_datetime_.push_back('.');
0873
0874 cache_timestamp_ = secs;
0875 }
0876 dest.append(cached_datetime_.begin(), cached_datetime_.end());
0877
0878 auto millis = fmt_helper::time_fraction<milliseconds>(msg.time);
0879 fmt_helper::pad3(static_cast<uint32_t>(millis.count()), dest);
0880 dest.push_back(']');
0881 dest.push_back(' ');
0882
0883
0884 if (msg.logger_name.size() > 0) {
0885 dest.push_back('[');
0886 fmt_helper::append_string_view(msg.logger_name, dest);
0887 dest.push_back(']');
0888 dest.push_back(' ');
0889 }
0890
0891 dest.push_back('[');
0892
0893 msg.color_range_start = dest.size();
0894
0895 fmt_helper::append_string_view(level::to_string_view(msg.level), dest);
0896 msg.color_range_end = dest.size();
0897 dest.push_back(']');
0898 dest.push_back(' ');
0899
0900
0901 if (!msg.source.empty()) {
0902 dest.push_back('[');
0903 const char *filename =
0904 details::short_filename_formatter<details::null_scoped_padder>::basename(
0905 msg.source.filename);
0906 fmt_helper::append_string_view(filename, dest);
0907 dest.push_back(':');
0908 fmt_helper::append_int(msg.source.line, dest);
0909 dest.push_back(']');
0910 dest.push_back(' ');
0911 }
0912
0913 #ifndef SPDLOG_NO_TLS
0914
0915 auto &mdc_map = mdc::get_context();
0916 if (!mdc_map.empty()) {
0917 dest.push_back('[');
0918 mdc_formatter_.format_mdc(mdc_map, dest);
0919 dest.push_back(']');
0920 dest.push_back(' ');
0921 }
0922 #endif
0923
0924 fmt_helper::append_string_view(msg.payload, dest);
0925 }
0926
0927 private:
0928 std::chrono::seconds cache_timestamp_{0};
0929 memory_buf_t cached_datetime_;
0930
0931 #ifndef SPDLOG_NO_TLS
0932 mdc_formatter<null_scoped_padder> mdc_formatter_{padding_info {}};
0933 #endif
0934 };
0935
0936 }
0937
0938 SPDLOG_INLINE pattern_formatter::pattern_formatter(std::string pattern,
0939 pattern_time_type time_type,
0940 std::string eol,
0941 custom_flags custom_user_flags)
0942 : pattern_(std::move(pattern)),
0943 eol_(std::move(eol)),
0944 pattern_time_type_(time_type),
0945 need_localtime_(false),
0946 last_log_secs_(0),
0947 custom_handlers_(std::move(custom_user_flags)) {
0948 std::memset(&cached_tm_, 0, sizeof(cached_tm_));
0949 compile_pattern_(pattern_);
0950 }
0951
0952
0953 SPDLOG_INLINE pattern_formatter::pattern_formatter(pattern_time_type time_type, std::string eol)
0954 : pattern_("%+"),
0955 eol_(std::move(eol)),
0956 pattern_time_type_(time_type),
0957 need_localtime_(true),
0958 last_log_secs_(0) {
0959 std::memset(&cached_tm_, 0, sizeof(cached_tm_));
0960 formatters_.push_back(details::make_unique<details::full_formatter>(details::padding_info{}));
0961 }
0962
0963 SPDLOG_INLINE std::unique_ptr<formatter> pattern_formatter::clone() const {
0964 custom_flags cloned_custom_formatters;
0965 for (auto &it : custom_handlers_) {
0966 cloned_custom_formatters[it.first] = it.second->clone();
0967 }
0968 auto cloned = details::make_unique<pattern_formatter>(pattern_, pattern_time_type_, eol_,
0969 std::move(cloned_custom_formatters));
0970 cloned->need_localtime(need_localtime_);
0971 #if defined(__GNUC__) && __GNUC__ < 5
0972 return std::move(cloned);
0973 #else
0974 return cloned;
0975 #endif
0976 }
0977
0978 SPDLOG_INLINE void pattern_formatter::format(const details::log_msg &msg, memory_buf_t &dest) {
0979 if (need_localtime_) {
0980 const auto secs =
0981 std::chrono::duration_cast<std::chrono::seconds>(msg.time.time_since_epoch());
0982 if (secs != last_log_secs_) {
0983 cached_tm_ = get_time_(msg);
0984 last_log_secs_ = secs;
0985 }
0986 }
0987
0988 for (auto &f : formatters_) {
0989 f->format(msg, cached_tm_, dest);
0990 }
0991
0992 details::fmt_helper::append_string_view(eol_, dest);
0993 }
0994
0995 SPDLOG_INLINE void pattern_formatter::set_pattern(std::string pattern) {
0996 pattern_ = std::move(pattern);
0997 need_localtime_ = false;
0998 compile_pattern_(pattern_);
0999 }
1000
1001 SPDLOG_INLINE void pattern_formatter::need_localtime(bool need) { need_localtime_ = need; }
1002
1003 SPDLOG_INLINE std::tm pattern_formatter::get_time_(const details::log_msg &msg) {
1004 if (pattern_time_type_ == pattern_time_type::local) {
1005 return details::os::localtime(log_clock::to_time_t(msg.time));
1006 }
1007 return details::os::gmtime(log_clock::to_time_t(msg.time));
1008 }
1009
1010 template <typename Padder>
1011 SPDLOG_INLINE void pattern_formatter::handle_flag_(char flag, details::padding_info padding) {
1012
1013 auto it = custom_handlers_.find(flag);
1014 if (it != custom_handlers_.end()) {
1015 auto custom_handler = it->second->clone();
1016 custom_handler->set_padding_info(padding);
1017 formatters_.push_back(std::move(custom_handler));
1018 return;
1019 }
1020
1021
1022 switch (flag) {
1023 case ('+'):
1024 formatters_.push_back(details::make_unique<details::full_formatter>(padding));
1025 need_localtime_ = true;
1026 break;
1027
1028 case 'n':
1029 formatters_.push_back(details::make_unique<details::name_formatter<Padder>>(padding));
1030 break;
1031
1032 case 'l':
1033 formatters_.push_back(details::make_unique<details::level_formatter<Padder>>(padding));
1034 break;
1035
1036 case 'L':
1037 formatters_.push_back(
1038 details::make_unique<details::short_level_formatter<Padder>>(padding));
1039 break;
1040
1041 case ('t'):
1042 formatters_.push_back(details::make_unique<details::t_formatter<Padder>>(padding));
1043 break;
1044
1045 case ('v'):
1046 formatters_.push_back(details::make_unique<details::v_formatter<Padder>>(padding));
1047 break;
1048
1049 case ('a'):
1050 formatters_.push_back(details::make_unique<details::a_formatter<Padder>>(padding));
1051 need_localtime_ = true;
1052 break;
1053
1054 case ('A'):
1055 formatters_.push_back(details::make_unique<details::A_formatter<Padder>>(padding));
1056 need_localtime_ = true;
1057 break;
1058
1059 case ('b'):
1060 case ('h'):
1061 formatters_.push_back(details::make_unique<details::b_formatter<Padder>>(padding));
1062 need_localtime_ = true;
1063 break;
1064
1065 case ('B'):
1066 formatters_.push_back(details::make_unique<details::B_formatter<Padder>>(padding));
1067 need_localtime_ = true;
1068 break;
1069
1070 case ('c'):
1071 formatters_.push_back(details::make_unique<details::c_formatter<Padder>>(padding));
1072 need_localtime_ = true;
1073 break;
1074
1075 case ('C'):
1076 formatters_.push_back(details::make_unique<details::C_formatter<Padder>>(padding));
1077 need_localtime_ = true;
1078 break;
1079
1080 case ('Y'):
1081 formatters_.push_back(details::make_unique<details::Y_formatter<Padder>>(padding));
1082 need_localtime_ = true;
1083 break;
1084
1085 case ('D'):
1086 case ('x'):
1087 formatters_.push_back(details::make_unique<details::D_formatter<Padder>>(padding));
1088 need_localtime_ = true;
1089 break;
1090
1091 case ('m'):
1092 formatters_.push_back(details::make_unique<details::m_formatter<Padder>>(padding));
1093 need_localtime_ = true;
1094 break;
1095
1096 case ('d'):
1097 formatters_.push_back(details::make_unique<details::d_formatter<Padder>>(padding));
1098 need_localtime_ = true;
1099 break;
1100
1101 case ('H'):
1102 formatters_.push_back(details::make_unique<details::H_formatter<Padder>>(padding));
1103 need_localtime_ = true;
1104 break;
1105
1106 case ('I'):
1107 formatters_.push_back(details::make_unique<details::I_formatter<Padder>>(padding));
1108 need_localtime_ = true;
1109 break;
1110
1111 case ('M'):
1112 formatters_.push_back(details::make_unique<details::M_formatter<Padder>>(padding));
1113 need_localtime_ = true;
1114 break;
1115
1116 case ('S'):
1117 formatters_.push_back(details::make_unique<details::S_formatter<Padder>>(padding));
1118 need_localtime_ = true;
1119 break;
1120
1121 case ('e'):
1122 formatters_.push_back(details::make_unique<details::e_formatter<Padder>>(padding));
1123 break;
1124
1125 case ('f'):
1126 formatters_.push_back(details::make_unique<details::f_formatter<Padder>>(padding));
1127 break;
1128
1129 case ('F'):
1130 formatters_.push_back(details::make_unique<details::F_formatter<Padder>>(padding));
1131 break;
1132
1133 case ('E'):
1134 formatters_.push_back(details::make_unique<details::E_formatter<Padder>>(padding));
1135 break;
1136
1137 case ('p'):
1138 formatters_.push_back(details::make_unique<details::p_formatter<Padder>>(padding));
1139 need_localtime_ = true;
1140 break;
1141
1142 case ('r'):
1143 formatters_.push_back(details::make_unique<details::r_formatter<Padder>>(padding));
1144 need_localtime_ = true;
1145 break;
1146
1147 case ('R'):
1148 formatters_.push_back(details::make_unique<details::R_formatter<Padder>>(padding));
1149 need_localtime_ = true;
1150 break;
1151
1152 case ('T'):
1153 case ('X'):
1154 formatters_.push_back(details::make_unique<details::T_formatter<Padder>>(padding));
1155 need_localtime_ = true;
1156 break;
1157
1158 case ('z'):
1159 formatters_.push_back(details::make_unique<details::z_formatter<Padder>>(padding));
1160 need_localtime_ = true;
1161 break;
1162
1163 case ('P'):
1164 formatters_.push_back(details::make_unique<details::pid_formatter<Padder>>(padding));
1165 break;
1166
1167 case ('^'):
1168 formatters_.push_back(details::make_unique<details::color_start_formatter>(padding));
1169 break;
1170
1171 case ('$'):
1172 formatters_.push_back(details::make_unique<details::color_stop_formatter>(padding));
1173 break;
1174
1175 case ('@'):
1176 formatters_.push_back(
1177 details::make_unique<details::source_location_formatter<Padder>>(padding));
1178 break;
1179
1180 case ('s'):
1181 formatters_.push_back(
1182 details::make_unique<details::short_filename_formatter<Padder>>(padding));
1183 break;
1184
1185 case ('g'):
1186 formatters_.push_back(
1187 details::make_unique<details::source_filename_formatter<Padder>>(padding));
1188 break;
1189
1190 case ('#'):
1191 formatters_.push_back(
1192 details::make_unique<details::source_linenum_formatter<Padder>>(padding));
1193 break;
1194
1195 case ('!'):
1196 formatters_.push_back(
1197 details::make_unique<details::source_funcname_formatter<Padder>>(padding));
1198 break;
1199
1200 case ('%'):
1201 formatters_.push_back(details::make_unique<details::ch_formatter>('%'));
1202 break;
1203
1204 case ('u'):
1205 formatters_.push_back(
1206 details::make_unique<details::elapsed_formatter<Padder, std::chrono::nanoseconds>>(
1207 padding));
1208 break;
1209
1210 case ('i'):
1211 formatters_.push_back(
1212 details::make_unique<details::elapsed_formatter<Padder, std::chrono::microseconds>>(
1213 padding));
1214 break;
1215
1216 case ('o'):
1217 formatters_.push_back(
1218 details::make_unique<details::elapsed_formatter<Padder, std::chrono::milliseconds>>(
1219 padding));
1220 break;
1221
1222 case ('O'):
1223 formatters_.push_back(
1224 details::make_unique<details::elapsed_formatter<Padder, std::chrono::seconds>>(
1225 padding));
1226 break;
1227
1228 #ifndef SPDLOG_NO_TLS
1229 case ('&'):
1230 formatters_.push_back(details::make_unique<details::mdc_formatter<Padder>>(padding));
1231 break;
1232 #endif
1233
1234 default:
1235 auto unknown_flag = details::make_unique<details::aggregate_formatter>();
1236
1237 if (!padding.truncate_) {
1238 unknown_flag->add_ch('%');
1239 unknown_flag->add_ch(flag);
1240 formatters_.push_back((std::move(unknown_flag)));
1241 }
1242
1243
1244
1245 else {
1246 padding.truncate_ = false;
1247 formatters_.push_back(
1248 details::make_unique<details::source_funcname_formatter<Padder>>(padding));
1249 unknown_flag->add_ch(flag);
1250 formatters_.push_back((std::move(unknown_flag)));
1251 }
1252
1253 break;
1254 }
1255 }
1256
1257
1258
1259
1260 SPDLOG_INLINE details::padding_info pattern_formatter::handle_padspec_(
1261 std::string::const_iterator &it, std::string::const_iterator end) {
1262 using details::padding_info;
1263 using details::scoped_padder;
1264 const size_t max_width = 64;
1265 if (it == end) {
1266 return padding_info{};
1267 }
1268
1269 padding_info::pad_side side;
1270 switch (*it) {
1271 case '-':
1272 side = padding_info::pad_side::right;
1273 ++it;
1274 break;
1275 case '=':
1276 side = padding_info::pad_side::center;
1277 ++it;
1278 break;
1279 default:
1280 side = details::padding_info::pad_side::left;
1281 break;
1282 }
1283
1284 if (it == end || !std::isdigit(static_cast<unsigned char>(*it))) {
1285 return padding_info{};
1286 }
1287
1288 auto width = static_cast<size_t>(*it) - '0';
1289 for (++it; it != end && std::isdigit(static_cast<unsigned char>(*it)); ++it) {
1290 auto digit = static_cast<size_t>(*it) - '0';
1291 width = width * 10 + digit;
1292 }
1293
1294
1295 bool truncate;
1296 if (it != end && *it == '!') {
1297 truncate = true;
1298 ++it;
1299 } else {
1300 truncate = false;
1301 }
1302 return details::padding_info{std::min<size_t>(width, max_width), side, truncate};
1303 }
1304
1305 SPDLOG_INLINE void pattern_formatter::compile_pattern_(const std::string &pattern) {
1306 auto end = pattern.end();
1307 std::unique_ptr<details::aggregate_formatter> user_chars;
1308 formatters_.clear();
1309 for (auto it = pattern.begin(); it != end; ++it) {
1310 if (*it == '%') {
1311 if (user_chars)
1312 {
1313 formatters_.push_back(std::move(user_chars));
1314 }
1315
1316 auto padding = handle_padspec_(++it, end);
1317
1318 if (it != end) {
1319 if (padding.enabled()) {
1320 handle_flag_<details::scoped_padder>(*it, padding);
1321 } else {
1322 handle_flag_<details::null_scoped_padder>(*it, padding);
1323 }
1324 } else {
1325 break;
1326 }
1327 } else
1328 {
1329 if (!user_chars) {
1330 user_chars = details::make_unique<details::aggregate_formatter>();
1331 }
1332 user_chars->add_ch(*it);
1333 }
1334 }
1335 if (user_chars)
1336 {
1337 formatters_.push_back(std::move(user_chars));
1338 }
1339 }
1340 }