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
19namespace spdlog {
20namespace details {
21
22// padding information.
23struct padding_info
24{
25 enum class pad_side
26 {
27 left,
28 right,
29 center
30 };
31
32 padding_info() = default;
33 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
40 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
50class SPDLOG_API flag_formatter
51{
52public:
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
60protected:
61 padding_info padinfo_;
62};
63
64} // namespace details
65
66class SPDLOG_API custom_flag_formatter : public details::flag_formatter
67{
68public:
69 virtual std::unique_ptr<custom_flag_formatter> clone() const = 0;
70
71 void set_padding_info(const details::padding_info &padding)
72 {
73 flag_formatter::padinfo_ = padding;
74 }
75};
76
77class SPDLOG_API pattern_formatter final : public formatter
78{
79public:
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>
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 void need_localtime(bool need = true);
102
103private:
104 std::string pattern_;
105 std::string eol_;
106 pattern_time_type pattern_time_type_;
107 bool need_localtime_;
108 std::tm cached_tm_;
109 std::chrono::seconds last_log_secs_;
110 std::vector<std::unique_ptr<details::flag_formatter>> formatters_;
111 custom_flags custom_handlers_;
112
113 std::tm get_time_(const details::log_msg &msg);
114 template<typename Padder>
115 void handle_flag_(char flag, details::padding_info padding);
116
117 // Extract given pad spec (e.g. %8X)
118 // Advance the given it pass the end of the padding spec found (if any)
119 // Return padding.
120 static details::padding_info handle_padspec_(std::string::const_iterator &it, std::string::const_iterator end);
121
122 void compile_pattern_(const std::string &pattern);
123};
124} // namespace spdlog
125
126#ifdef SPDLOG_HEADER_ONLY
127# include "pattern_formatter-inl.h"
128#endif
129