1 // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
2 // Distributed under the MIT License (http://opensource.org/licenses/MIT)
3 
4 #pragma once
5 
6 #include <spdlog/common.h>
7 #include <spdlog/details/log_msg.h>
8 #include <spdlog/details/os.h>
9 #include <spdlog/formatter.h>
10 
11 #include <chrono>
12 #include <ctime>
13 #include <memory>
14 
15 #include <string>
16 #include <vector>
17 #include <unordered_map>
18 
19 namespace spdlog {
20 namespace details {
21 
22 // padding information.
23 struct padding_info
24 {
25     enum class pad_side
26     {
27         left,
28         right,
29         center
30     };
31 
32     padding_info() = default;
padding_infopadding_info33     padding_info(size_t width, padding_info::pad_side side, bool truncate)
34         : width_(width)
35         , side_(side)
36         , truncate_(truncate)
37         , enabled_(true)
38     {}
39 
enabledpadding_info40     bool enabled() const
41     {
42         return enabled_;
43     }
44     size_t width_ = 0;
45     pad_side side_ = pad_side::left;
46     bool truncate_ = false;
47     bool enabled_ = false;
48 };
49 
50 class SPDLOG_API flag_formatter
51 {
52 public:
flag_formatter(padding_info padinfo)53     explicit flag_formatter(padding_info padinfo)
54         : padinfo_(padinfo)
55     {}
56     flag_formatter() = default;
57     virtual ~flag_formatter() = default;
58     virtual void format(const details::log_msg &msg, const std::tm &tm_time, memory_buf_t &dest) = 0;
59 
60 protected:
61     padding_info padinfo_;
62 };
63 
64 } // namespace details
65 
66 class SPDLOG_API custom_flag_formatter : public details::flag_formatter
67 {
68 public:
69     virtual std::unique_ptr<custom_flag_formatter> clone() const = 0;
70 
set_padding_info(details::padding_info padding)71     void set_padding_info(details::padding_info padding)
72     {
73         flag_formatter::padinfo_ = padding;
74     }
75 };
76 
77 class SPDLOG_API pattern_formatter final : public formatter
78 {
79 public:
80     using custom_flags = std::unordered_map<char, std::unique_ptr<custom_flag_formatter>>;
81 
82     explicit pattern_formatter(std::string pattern, pattern_time_type time_type = pattern_time_type::local,
83         std::string eol = spdlog::details::os::default_eol, custom_flags custom_user_flags = custom_flags());
84 
85     // use default pattern is not given
86     explicit pattern_formatter(pattern_time_type time_type = pattern_time_type::local, std::string eol = spdlog::details::os::default_eol);
87 
88     pattern_formatter(const pattern_formatter &other) = delete;
89     pattern_formatter &operator=(const pattern_formatter &other) = delete;
90 
91     std::unique_ptr<formatter> clone() const override;
92     void format(const details::log_msg &msg, memory_buf_t &dest) override;
93 
94     template<typename T, typename... Args>
add_flag(char flag,Args &&...args)95     pattern_formatter &add_flag(char flag, Args &&...args)
96     {
97         custom_handlers_[flag] = details::make_unique<T>(std::forward<Args>(args)...);
98         return *this;
99     }
100     void set_pattern(std::string pattern);
101 
102 private:
103     std::string pattern_;
104     std::string eol_;
105     pattern_time_type pattern_time_type_;
106     std::tm cached_tm_;
107     std::chrono::seconds last_log_secs_;
108     std::vector<std::unique_ptr<details::flag_formatter>> formatters_;
109     custom_flags custom_handlers_;
110 
111     std::tm get_time_(const details::log_msg &msg);
112     template<typename Padder>
113     void handle_flag_(char flag, details::padding_info padding);
114 
115     // Extract given pad spec (e.g. %8X)
116     // Advance the given it pass the end of the padding spec found (if any)
117     // Return padding.
118     static details::padding_info handle_padspec_(std::string::const_iterator &it, std::string::const_iterator end);
119 
120     void compile_pattern_(const std::string &pattern);
121 };
122 } // namespace spdlog
123 
124 #ifdef SPDLOG_HEADER_ONLY
125 #    include "pattern_formatter-inl.h"
126 #endif
127