1 | /* |
2 | * This content is released under the MIT License as specified in https://raw.githubusercontent.com/gabime/spdlog/master/LICENSE |
3 | */ |
4 | #include "includes.h" |
5 | |
6 | #ifdef SPDLOG_USE_STD_FORMAT |
7 | using filename_memory_buf_t = std::basic_string<spdlog::filename_t::value_type>; |
8 | #else |
9 | using filename_memory_buf_t = fmt::basic_memory_buffer<spdlog::filename_t::value_type, 250>; |
10 | #endif |
11 | |
12 | #ifdef SPDLOG_WCHAR_FILENAMES |
13 | std::string filename_buf_to_utf8string(const filename_memory_buf_t &w) |
14 | { |
15 | spdlog::memory_buf_t buf; |
16 | spdlog::details::os::wstr_to_utf8buf(spdlog::wstring_view_t(w.data(), w.size()), buf); |
17 | return SPDLOG_BUF_TO_STRING(buf); |
18 | } |
19 | #else |
20 | std::string filename_buf_to_utf8string(const filename_memory_buf_t &w) |
21 | { |
22 | return SPDLOG_BUF_TO_STRING(w); |
23 | } |
24 | #endif |
25 | |
26 | TEST_CASE("daily_logger with dateonly calculator" , "[daily_logger]" ) |
27 | { |
28 | using sink_type = spdlog::sinks::daily_file_sink<std::mutex, spdlog::sinks::daily_filename_calculator>; |
29 | |
30 | prepare_logdir(); |
31 | |
32 | // calculate filename (time based) |
33 | spdlog::filename_t basename = SPDLOG_FILENAME_T("test_logs/daily_dateonly" ); |
34 | std::tm tm = spdlog::details::os::localtime(); |
35 | filename_memory_buf_t w; |
36 | spdlog::fmt_lib::format_to( |
37 | std::back_inserter(w), SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}" ), basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); |
38 | |
39 | auto logger = spdlog::create<sink_type>("logger" , basename, 0, 0); |
40 | for (int i = 0; i < 10; ++i) |
41 | { |
42 | |
43 | logger->info("Test message {}" , i); |
44 | } |
45 | logger->flush(); |
46 | |
47 | require_message_count(filename_buf_to_utf8string(w), 10); |
48 | } |
49 | |
50 | struct custom_daily_file_name_calculator |
51 | { |
52 | static spdlog::filename_t calc_filename(const spdlog::filename_t &basename, const tm &now_tm) |
53 | { |
54 | filename_memory_buf_t w; |
55 | spdlog::fmt_lib::format_to(std::back_inserter(w), SPDLOG_FILENAME_T("{}{:04d}{:02d}{:02d}" ), basename, now_tm.tm_year + 1900, |
56 | now_tm.tm_mon + 1, now_tm.tm_mday); |
57 | |
58 | return SPDLOG_BUF_TO_STRING(w); |
59 | } |
60 | }; |
61 | |
62 | TEST_CASE("daily_logger with custom calculator" , "[daily_logger]" ) |
63 | { |
64 | using sink_type = spdlog::sinks::daily_file_sink<std::mutex, custom_daily_file_name_calculator>; |
65 | |
66 | prepare_logdir(); |
67 | |
68 | // calculate filename (time based) |
69 | spdlog::filename_t basename = SPDLOG_FILENAME_T("test_logs/daily_dateonly" ); |
70 | std::tm tm = spdlog::details::os::localtime(); |
71 | filename_memory_buf_t w; |
72 | spdlog::fmt_lib::format_to( |
73 | std::back_inserter(w), SPDLOG_FILENAME_T("{}{:04d}{:02d}{:02d}" ), basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); |
74 | |
75 | auto logger = spdlog::create<sink_type>("logger" , basename, 0, 0); |
76 | for (int i = 0; i < 10; ++i) |
77 | { |
78 | logger->info("Test message {}" , i); |
79 | } |
80 | |
81 | logger->flush(); |
82 | |
83 | require_message_count(filename_buf_to_utf8string(w), 10); |
84 | } |
85 | |
86 | /* |
87 | * File name calculations |
88 | */ |
89 | |
90 | TEST_CASE("rotating_file_sink::calc_filename1" , "[rotating_file_sink]]" ) |
91 | { |
92 | auto filename = spdlog::sinks::rotating_file_sink_st::calc_filename(SPDLOG_FILENAME_T("rotated.txt" ), 3); |
93 | REQUIRE(filename == SPDLOG_FILENAME_T("rotated.3.txt" )); |
94 | } |
95 | |
96 | TEST_CASE("rotating_file_sink::calc_filename2" , "[rotating_file_sink]]" ) |
97 | { |
98 | auto filename = spdlog::sinks::rotating_file_sink_st::calc_filename(SPDLOG_FILENAME_T("rotated" ), 3); |
99 | REQUIRE(filename == SPDLOG_FILENAME_T("rotated.3" )); |
100 | } |
101 | |
102 | TEST_CASE("rotating_file_sink::calc_filename3" , "[rotating_file_sink]]" ) |
103 | { |
104 | auto filename = spdlog::sinks::rotating_file_sink_st::calc_filename(SPDLOG_FILENAME_T("rotated.txt" ), 0); |
105 | REQUIRE(filename == SPDLOG_FILENAME_T("rotated.txt" )); |
106 | } |
107 | |
108 | // regex supported only from gcc 4.9 and above |
109 | #if defined(_MSC_VER) || !(__GNUC__ <= 4 && __GNUC_MINOR__ < 9) |
110 | |
111 | # include <regex> |
112 | |
113 | TEST_CASE("daily_file_sink::daily_filename_calculator" , "[daily_file_sink]]" ) |
114 | { |
115 | // daily_YYYY-MM-DD_hh-mm.txt |
116 | auto filename = |
117 | spdlog::sinks::daily_filename_calculator::calc_filename(SPDLOG_FILENAME_T("daily.txt" ), spdlog::details::os::localtime()); |
118 | // date regex based on https://www.regular-expressions.info/dates.html |
119 | std::basic_regex<spdlog::filename_t::value_type> re( |
120 | SPDLOG_FILENAME_T(R"(^daily_(19|20)\d\d-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])\.txt$)" )); |
121 | std::match_results<spdlog::filename_t::const_iterator> match; |
122 | REQUIRE(std::regex_match(filename, match, re)); |
123 | } |
124 | #endif |
125 | |
126 | TEST_CASE("daily_file_sink::daily_filename_format_calculator" , "[daily_file_sink]]" ) |
127 | { |
128 | std::tm tm = spdlog::details::os::localtime(); |
129 | // example-YYYY-MM-DD.log |
130 | auto filename = spdlog::sinks::daily_filename_format_calculator::calc_filename(SPDLOG_FILENAME_T("example-%Y-%m-%d.log" ), tm); |
131 | |
132 | REQUIRE(filename == |
133 | spdlog::fmt_lib::format(SPDLOG_FILENAME_T("example-{:04d}-{:02d}-{:02d}.log" ), tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday)); |
134 | } |
135 | |
136 | /* Test removal of old files */ |
137 | static spdlog::details::log_msg create_msg(std::chrono::seconds offset) |
138 | { |
139 | using spdlog::log_clock; |
140 | spdlog::details::log_msg msg{"test" , spdlog::level::info, "Hello Message" }; |
141 | msg.time = log_clock::now() + offset; |
142 | return msg; |
143 | } |
144 | |
145 | static void test_rotate(int days_to_run, uint16_t max_days, uint16_t expected_n_files) |
146 | { |
147 | using spdlog::log_clock; |
148 | using spdlog::details::log_msg; |
149 | using spdlog::sinks::daily_file_sink_st; |
150 | |
151 | prepare_logdir(); |
152 | |
153 | spdlog::filename_t basename = SPDLOG_FILENAME_T("test_logs/daily_rotate.txt" ); |
154 | daily_file_sink_st sink{basename, 2, 30, true, max_days}; |
155 | |
156 | // simulate messages with 24 intervals |
157 | |
158 | for (int i = 0; i < days_to_run; i++) |
159 | { |
160 | auto offset = std::chrono::seconds{24 * 3600 * i}; |
161 | sink.log(create_msg(offset)); |
162 | } |
163 | |
164 | REQUIRE(count_files("test_logs" ) == static_cast<size_t>(expected_n_files)); |
165 | } |
166 | |
167 | TEST_CASE("daily_logger rotate" , "[daily_file_sink]" ) |
168 | { |
169 | int days_to_run = 1; |
170 | test_rotate(days_to_run, 0, 1); |
171 | test_rotate(days_to_run, 1, 1); |
172 | test_rotate(days_to_run, 3, 1); |
173 | test_rotate(days_to_run, 10, 1); |
174 | |
175 | days_to_run = 10; |
176 | test_rotate(days_to_run, 0, 10); |
177 | test_rotate(days_to_run, 1, 1); |
178 | test_rotate(days_to_run, 3, 3); |
179 | test_rotate(days_to_run, 9, 9); |
180 | test_rotate(days_to_run, 10, 10); |
181 | test_rotate(days_to_run, 11, 10); |
182 | test_rotate(days_to_run, 20, 10); |
183 | } |
184 | |