source: trunk/GDE/SINA/builddir/include/spdlog/details/pattern_formatter.h

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