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 | |
---|
10 | #include <memory> |
---|
11 | #include <string> |
---|
12 | |
---|
13 | #define SPDLOG_CATCH_AND_HANDLE \ |
---|
14 | catch (const std::exception &ex) \ |
---|
15 | { \ |
---|
16 | err_handler_(ex.what()); \ |
---|
17 | } \ |
---|
18 | catch (...) \ |
---|
19 | { \ |
---|
20 | err_handler_("Unknown exception in logger"); \ |
---|
21 | } |
---|
22 | |
---|
23 | // create logger with given name, sinks and the default pattern formatter |
---|
24 | // all other ctors will call this one |
---|
25 | template<typename It> |
---|
26 | inline spdlog::logger::logger(std::string logger_name, It begin, It end) |
---|
27 | : name_(std::move(logger_name)) |
---|
28 | , sinks_(begin, end) |
---|
29 | { |
---|
30 | } |
---|
31 | |
---|
32 | // ctor with sinks as init list |
---|
33 | inline spdlog::logger::logger(std::string logger_name, sinks_init_list sinks_list) |
---|
34 | : logger(std::move(logger_name), sinks_list.begin(), sinks_list.end()) |
---|
35 | { |
---|
36 | } |
---|
37 | |
---|
38 | // ctor with single sink |
---|
39 | inline spdlog::logger::logger(std::string logger_name, spdlog::sink_ptr single_sink) |
---|
40 | : logger(std::move(logger_name), {std::move(single_sink)}) |
---|
41 | { |
---|
42 | } |
---|
43 | |
---|
44 | inline spdlog::logger::~logger() = default; |
---|
45 | |
---|
46 | inline void spdlog::logger::set_formatter(std::unique_ptr<spdlog::formatter> f) |
---|
47 | { |
---|
48 | for (auto &sink : sinks_) |
---|
49 | { |
---|
50 | sink->set_formatter(f->clone()); |
---|
51 | } |
---|
52 | } |
---|
53 | |
---|
54 | inline void spdlog::logger::set_pattern(std::string pattern, pattern_time_type time_type) |
---|
55 | { |
---|
56 | auto new_formatter = details::make_unique<spdlog::pattern_formatter>(std::move(pattern), time_type); |
---|
57 | set_formatter(std::move(new_formatter)); |
---|
58 | } |
---|
59 | |
---|
60 | template<typename... Args> |
---|
61 | inline void spdlog::logger::log(source_loc source, level::level_enum lvl, const char *fmt, const Args &... args) |
---|
62 | { |
---|
63 | if (!should_log(lvl)) |
---|
64 | { |
---|
65 | return; |
---|
66 | } |
---|
67 | |
---|
68 | try |
---|
69 | { |
---|
70 | using details::fmt_helper::to_string_view; |
---|
71 | fmt::memory_buffer buf; |
---|
72 | fmt::format_to(buf, fmt, args...); |
---|
73 | details::log_msg log_msg(source, &name_, lvl, to_string_view(buf)); |
---|
74 | sink_it_(log_msg); |
---|
75 | } |
---|
76 | SPDLOG_CATCH_AND_HANDLE |
---|
77 | } |
---|
78 | |
---|
79 | template<typename... Args> |
---|
80 | inline void spdlog::logger::log(level::level_enum lvl, const char *fmt, const Args &... args) |
---|
81 | { |
---|
82 | log(source_loc{}, lvl, fmt, args...); |
---|
83 | } |
---|
84 | |
---|
85 | inline void spdlog::logger::log(source_loc source, level::level_enum lvl, const char *msg) |
---|
86 | { |
---|
87 | if (!should_log(lvl)) |
---|
88 | { |
---|
89 | return; |
---|
90 | } |
---|
91 | |
---|
92 | try |
---|
93 | { |
---|
94 | details::log_msg log_msg(source, &name_, lvl, spdlog::string_view_t(msg)); |
---|
95 | sink_it_(log_msg); |
---|
96 | } |
---|
97 | SPDLOG_CATCH_AND_HANDLE |
---|
98 | } |
---|
99 | |
---|
100 | inline void spdlog::logger::log(level::level_enum lvl, const char *msg) |
---|
101 | { |
---|
102 | log(source_loc{}, lvl, msg); |
---|
103 | } |
---|
104 | |
---|
105 | template<class T, typename std::enable_if<std::is_convertible<T, spdlog::string_view_t>::value, T>::type *> |
---|
106 | inline void spdlog::logger::log(source_loc source, level::level_enum lvl, const T &msg) |
---|
107 | { |
---|
108 | if (!should_log(lvl)) |
---|
109 | { |
---|
110 | return; |
---|
111 | } |
---|
112 | try |
---|
113 | { |
---|
114 | details::log_msg log_msg(source, &name_, lvl, msg); |
---|
115 | sink_it_(log_msg); |
---|
116 | } |
---|
117 | SPDLOG_CATCH_AND_HANDLE |
---|
118 | } |
---|
119 | |
---|
120 | template<class T, typename std::enable_if<std::is_convertible<T, spdlog::string_view_t>::value, T>::type *> |
---|
121 | inline void spdlog::logger::log(level::level_enum lvl, const T &msg) |
---|
122 | { |
---|
123 | log(source_loc{}, lvl, msg); |
---|
124 | } |
---|
125 | |
---|
126 | template<class T, typename std::enable_if<!std::is_convertible<T, spdlog::string_view_t>::value, T>::type *> |
---|
127 | inline void spdlog::logger::log(source_loc source, level::level_enum lvl, const T &msg) |
---|
128 | { |
---|
129 | if (!should_log(lvl)) |
---|
130 | { |
---|
131 | return; |
---|
132 | } |
---|
133 | try |
---|
134 | { |
---|
135 | using details::fmt_helper::to_string_view; |
---|
136 | fmt::memory_buffer buf; |
---|
137 | fmt::format_to(buf, "{}", msg); |
---|
138 | details::log_msg log_msg(source, &name_, lvl, to_string_view(buf)); |
---|
139 | sink_it_(log_msg); |
---|
140 | } |
---|
141 | SPDLOG_CATCH_AND_HANDLE |
---|
142 | } |
---|
143 | |
---|
144 | template<class T, typename std::enable_if<!std::is_convertible<T, spdlog::string_view_t>::value, T>::type *> |
---|
145 | inline void spdlog::logger::log(level::level_enum lvl, const T &msg) |
---|
146 | { |
---|
147 | log(source_loc{}, lvl, msg); |
---|
148 | } |
---|
149 | |
---|
150 | template<typename... Args> |
---|
151 | inline void spdlog::logger::trace(const char *fmt, const Args &... args) |
---|
152 | { |
---|
153 | log(level::trace, fmt, args...); |
---|
154 | } |
---|
155 | |
---|
156 | template<typename... Args> |
---|
157 | inline void spdlog::logger::debug(const char *fmt, const Args &... args) |
---|
158 | { |
---|
159 | log(level::debug, fmt, args...); |
---|
160 | } |
---|
161 | |
---|
162 | template<typename... Args> |
---|
163 | inline void spdlog::logger::info(const char *fmt, const Args &... args) |
---|
164 | { |
---|
165 | log(level::info, fmt, args...); |
---|
166 | } |
---|
167 | |
---|
168 | template<typename... Args> |
---|
169 | inline void spdlog::logger::warn(const char *fmt, const Args &... args) |
---|
170 | { |
---|
171 | log(level::warn, fmt, args...); |
---|
172 | } |
---|
173 | |
---|
174 | template<typename... Args> |
---|
175 | inline void spdlog::logger::error(const char *fmt, const Args &... args) |
---|
176 | { |
---|
177 | log(level::err, fmt, args...); |
---|
178 | } |
---|
179 | |
---|
180 | template<typename... Args> |
---|
181 | inline void spdlog::logger::critical(const char *fmt, const Args &... args) |
---|
182 | { |
---|
183 | log(level::critical, fmt, args...); |
---|
184 | } |
---|
185 | |
---|
186 | template<typename T> |
---|
187 | inline void spdlog::logger::trace(const T &msg) |
---|
188 | { |
---|
189 | log(level::trace, msg); |
---|
190 | } |
---|
191 | |
---|
192 | template<typename T> |
---|
193 | inline void spdlog::logger::debug(const T &msg) |
---|
194 | { |
---|
195 | log(level::debug, msg); |
---|
196 | } |
---|
197 | |
---|
198 | template<typename T> |
---|
199 | inline void spdlog::logger::info(const T &msg) |
---|
200 | { |
---|
201 | log(level::info, msg); |
---|
202 | } |
---|
203 | |
---|
204 | template<typename T> |
---|
205 | inline void spdlog::logger::warn(const T &msg) |
---|
206 | { |
---|
207 | log(level::warn, msg); |
---|
208 | } |
---|
209 | |
---|
210 | template<typename T> |
---|
211 | inline void spdlog::logger::error(const T &msg) |
---|
212 | { |
---|
213 | log(level::err, msg); |
---|
214 | } |
---|
215 | |
---|
216 | template<typename T> |
---|
217 | inline void spdlog::logger::critical(const T &msg) |
---|
218 | { |
---|
219 | log(level::critical, msg); |
---|
220 | } |
---|
221 | |
---|
222 | #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT |
---|
223 | |
---|
224 | inline void wbuf_to_utf8buf(const fmt::wmemory_buffer &wbuf, fmt::memory_buffer &target) |
---|
225 | { |
---|
226 | int wbuf_size = static_cast<int>(wbuf.size()); |
---|
227 | if (wbuf_size == 0) |
---|
228 | { |
---|
229 | return; |
---|
230 | } |
---|
231 | |
---|
232 | auto result_size = ::WideCharToMultiByte(CP_UTF8, 0, wbuf.data(), wbuf_size, NULL, 0, NULL, NULL); |
---|
233 | |
---|
234 | if (result_size > 0) |
---|
235 | { |
---|
236 | target.resize(result_size); |
---|
237 | ::WideCharToMultiByte(CP_UTF8, 0, wbuf.data(), wbuf_size, &target.data()[0], result_size, NULL, NULL); |
---|
238 | } |
---|
239 | else |
---|
240 | { |
---|
241 | throw spdlog::spdlog_ex(fmt::format("WideCharToMultiByte failed. Last error: {}", ::GetLastError())); |
---|
242 | } |
---|
243 | } |
---|
244 | |
---|
245 | template<typename... Args> |
---|
246 | inline void spdlog::logger::log(source_loc source, level::level_enum lvl, const wchar_t *fmt, const Args &... args) |
---|
247 | { |
---|
248 | if (!should_log(lvl)) |
---|
249 | { |
---|
250 | return; |
---|
251 | } |
---|
252 | |
---|
253 | try |
---|
254 | { |
---|
255 | // format to wmemory_buffer and convert to utf8 |
---|
256 | using details::fmt_helper::to_string_view; |
---|
257 | fmt::wmemory_buffer wbuf; |
---|
258 | fmt::format_to(wbuf, fmt, args...); |
---|
259 | fmt::memory_buffer buf; |
---|
260 | wbuf_to_utf8buf(wbuf, buf); |
---|
261 | details::log_msg log_msg(source, &name_, lvl, to_string_view(buf)); |
---|
262 | sink_it_(log_msg); |
---|
263 | } |
---|
264 | SPDLOG_CATCH_AND_HANDLE |
---|
265 | } |
---|
266 | |
---|
267 | template<typename... Args> |
---|
268 | inline void spdlog::logger::log(level::level_enum lvl, const wchar_t *fmt, const Args &... args) |
---|
269 | { |
---|
270 | log(source_loc{}, lvl, fmt, args...); |
---|
271 | } |
---|
272 | |
---|
273 | template<typename... Args> |
---|
274 | inline void spdlog::logger::trace(const wchar_t *fmt, const Args &... args) |
---|
275 | { |
---|
276 | log(level::trace, fmt, args...); |
---|
277 | } |
---|
278 | |
---|
279 | template<typename... Args> |
---|
280 | inline void spdlog::logger::debug(const wchar_t *fmt, const Args &... args) |
---|
281 | { |
---|
282 | log(level::debug, fmt, args...); |
---|
283 | } |
---|
284 | |
---|
285 | template<typename... Args> |
---|
286 | inline void spdlog::logger::info(const wchar_t *fmt, const Args &... args) |
---|
287 | { |
---|
288 | log(level::info, fmt, args...); |
---|
289 | } |
---|
290 | |
---|
291 | template<typename... Args> |
---|
292 | inline void spdlog::logger::warn(const wchar_t *fmt, const Args &... args) |
---|
293 | { |
---|
294 | log(level::warn, fmt, args...); |
---|
295 | } |
---|
296 | |
---|
297 | template<typename... Args> |
---|
298 | inline void spdlog::logger::error(const wchar_t *fmt, const Args &... args) |
---|
299 | { |
---|
300 | log(level::err, fmt, args...); |
---|
301 | } |
---|
302 | |
---|
303 | template<typename... Args> |
---|
304 | inline void spdlog::logger::critical(const wchar_t *fmt, const Args &... args) |
---|
305 | { |
---|
306 | log(level::critical, fmt, args...); |
---|
307 | } |
---|
308 | |
---|
309 | #endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT |
---|
310 | |
---|
311 | // |
---|
312 | // name and level |
---|
313 | // |
---|
314 | inline const std::string &spdlog::logger::name() const |
---|
315 | { |
---|
316 | return name_; |
---|
317 | } |
---|
318 | |
---|
319 | inline void spdlog::logger::set_level(spdlog::level::level_enum log_level) |
---|
320 | { |
---|
321 | level_.store(log_level); |
---|
322 | } |
---|
323 | |
---|
324 | inline void spdlog::logger::set_error_handler(spdlog::log_err_handler err_handler) |
---|
325 | { |
---|
326 | err_handler_ = std::move(err_handler); |
---|
327 | } |
---|
328 | |
---|
329 | inline spdlog::log_err_handler spdlog::logger::error_handler() const |
---|
330 | { |
---|
331 | return err_handler_; |
---|
332 | } |
---|
333 | |
---|
334 | inline void spdlog::logger::flush() |
---|
335 | { |
---|
336 | try |
---|
337 | { |
---|
338 | flush_(); |
---|
339 | } |
---|
340 | SPDLOG_CATCH_AND_HANDLE |
---|
341 | } |
---|
342 | |
---|
343 | inline void spdlog::logger::flush_on(level::level_enum log_level) |
---|
344 | { |
---|
345 | flush_level_.store(log_level); |
---|
346 | } |
---|
347 | |
---|
348 | inline spdlog::level::level_enum spdlog::logger::flush_level() const |
---|
349 | { |
---|
350 | return static_cast<spdlog::level::level_enum>(flush_level_.load(std::memory_order_relaxed)); |
---|
351 | } |
---|
352 | |
---|
353 | inline bool spdlog::logger::should_flush_(const details::log_msg &msg) |
---|
354 | { |
---|
355 | auto flush_level = flush_level_.load(std::memory_order_relaxed); |
---|
356 | return (msg.level >= flush_level) && (msg.level != level::off); |
---|
357 | } |
---|
358 | |
---|
359 | inline spdlog::level::level_enum spdlog::logger::default_level() |
---|
360 | { |
---|
361 | return static_cast<spdlog::level::level_enum>(SPDLOG_ACTIVE_LEVEL); |
---|
362 | } |
---|
363 | |
---|
364 | inline spdlog::level::level_enum spdlog::logger::level() const |
---|
365 | { |
---|
366 | return static_cast<spdlog::level::level_enum>(level_.load(std::memory_order_relaxed)); |
---|
367 | } |
---|
368 | |
---|
369 | inline bool spdlog::logger::should_log(spdlog::level::level_enum msg_level) const |
---|
370 | { |
---|
371 | return msg_level >= level_.load(std::memory_order_relaxed); |
---|
372 | } |
---|
373 | |
---|
374 | // |
---|
375 | // protected virtual called at end of each user log call (if enabled) by the |
---|
376 | // line_logger |
---|
377 | // |
---|
378 | inline void spdlog::logger::sink_it_(details::log_msg &msg) |
---|
379 | { |
---|
380 | #if defined(SPDLOG_ENABLE_MESSAGE_COUNTER) |
---|
381 | incr_msg_counter_(msg); |
---|
382 | #endif |
---|
383 | for (auto &sink : sinks_) |
---|
384 | { |
---|
385 | if (sink->should_log(msg.level)) |
---|
386 | { |
---|
387 | sink->log(msg); |
---|
388 | } |
---|
389 | } |
---|
390 | |
---|
391 | if (should_flush_(msg)) |
---|
392 | { |
---|
393 | flush_(); |
---|
394 | } |
---|
395 | } |
---|
396 | |
---|
397 | inline void spdlog::logger::flush_() |
---|
398 | { |
---|
399 | for (auto &sink : sinks_) |
---|
400 | { |
---|
401 | sink->flush(); |
---|
402 | } |
---|
403 | } |
---|
404 | |
---|
405 | inline void spdlog::logger::default_err_handler_(const std::string &msg) |
---|
406 | { |
---|
407 | auto now = time(nullptr); |
---|
408 | if (now - last_err_time_ < 60) |
---|
409 | { |
---|
410 | return; |
---|
411 | } |
---|
412 | last_err_time_ = now; |
---|
413 | auto tm_time = details::os::localtime(now); |
---|
414 | char date_buf[100]; |
---|
415 | std::strftime(date_buf, sizeof(date_buf), "%Y-%m-%d %H:%M:%S", &tm_time); |
---|
416 | fmt::print(stderr, "[*** LOG ERROR ***] [{}] [{}] {}\n", date_buf, name(), msg); |
---|
417 | } |
---|
418 | |
---|
419 | inline void spdlog::logger::incr_msg_counter_(details::log_msg &msg) |
---|
420 | { |
---|
421 | msg.msg_id = msg_counter_.fetch_add(1, std::memory_order_relaxed); |
---|
422 | } |
---|
423 | |
---|
424 | inline const std::vector<spdlog::sink_ptr> &spdlog::logger::sinks() const |
---|
425 | { |
---|
426 | return sinks_; |
---|
427 | } |
---|
428 | |
---|
429 | inline std::vector<spdlog::sink_ptr> &spdlog::logger::sinks() |
---|
430 | { |
---|
431 | return sinks_; |
---|
432 | } |
---|
433 | |
---|
434 | inline std::shared_ptr<spdlog::logger> spdlog::logger::clone(std::string logger_name) |
---|
435 | { |
---|
436 | auto cloned = std::make_shared<spdlog::logger>(std::move(logger_name), sinks_.begin(), sinks_.end()); |
---|
437 | cloned->set_level(this->level()); |
---|
438 | cloned->flush_on(this->flush_level()); |
---|
439 | cloned->set_error_handler(this->error_handler()); |
---|
440 | return cloned; |
---|
441 | } |
---|