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// Thread safe logger (except for set_error_handler())
7// Has name, log level, vector of std::shared sink pointers and formatter
8// Upon each log write the logger:
9// 1. Checks if its log level is enough to log the message and if yes:
10// 2. Call the underlying sinks to do the job.
11// 3. Each sink use its own private copy of a formatter to format the message
12// and send to its destination.
13//
14// The use of private formatter per sink provides the opportunity to cache some
15// formatted data, and support for different format per sink.
16
17#include <spdlog/common.h>
18#include <spdlog/details/log_msg.h>
19#include <spdlog/details/backtracer.h>
20
21#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
22# ifndef _WIN32
23# error SPDLOG_WCHAR_TO_UTF8_SUPPORT only supported on windows
24# endif
25# include <spdlog/details/os.h>
26#endif
27
28#include <vector>
29
30#ifndef SPDLOG_NO_EXCEPTIONS
31# define SPDLOG_LOGGER_CATCH(location) \
32 catch (const std::exception &ex) \
33 { \
34 if (location.filename) \
35 { \
36 err_handler_(fmt_lib::format(SPDLOG_FMT_STRING("{} [{}({})]"), ex.what(), location.filename, location.line)); \
37 } \
38 else \
39 { \
40 err_handler_(ex.what()); \
41 } \
42 } \
43 catch (...) \
44 { \
45 err_handler_("Rethrowing unknown exception in logger"); \
46 throw; \
47 }
48#else
49# define SPDLOG_LOGGER_CATCH(location)
50#endif
51
52namespace spdlog {
53
54class SPDLOG_API logger
55{
56public:
57 // Empty logger
58 explicit logger(std::string name)
59 : name_(std::move(name))
60 , sinks_()
61 {}
62
63 // Logger with range on sinks
64 template<typename It>
65 logger(std::string name, It begin, It end)
66 : name_(std::move(name))
67 , sinks_(begin, end)
68 {}
69
70 // Logger with single sink
71 logger(std::string name, sink_ptr single_sink)
72 : logger(std::move(name), {std::move(single_sink)})
73 {}
74
75 // Logger with sinks init list
76 logger(std::string name, sinks_init_list sinks)
77 : logger(std::move(name), sinks.begin(), sinks.end())
78 {}
79
80 virtual ~logger() = default;
81
82 logger(const logger &other);
83 logger(logger &&other) SPDLOG_NOEXCEPT;
84 logger &operator=(logger other) SPDLOG_NOEXCEPT;
85 void swap(spdlog::logger &other) SPDLOG_NOEXCEPT;
86
87 template<typename... Args>
88 void log(source_loc loc, level::level_enum lvl, format_string_t<Args...> fmt, Args &&... args)
89 {
90 log_(loc, lvl, details::to_string_view(fmt), std::forward<Args>(args)...);
91 }
92
93 template<typename... Args>
94 void log(level::level_enum lvl, format_string_t<Args...> fmt, Args &&... args)
95 {
96 log(source_loc{}, lvl, fmt, std::forward<Args>(args)...);
97 }
98
99 template<typename T>
100 void log(level::level_enum lvl, const T &msg)
101 {
102 log(source_loc{}, lvl, msg);
103 }
104
105 // T cannot be statically converted to format string (including string_view/wstring_view)
106 template<class T, typename std::enable_if<!is_convertible_to_any_format_string<const T &>::value, int>::type = 0>
107 void log(source_loc loc, level::level_enum lvl, const T &msg)
108 {
109 log(loc, lvl, "{}", msg);
110 }
111
112 void log(log_clock::time_point log_time, source_loc loc, level::level_enum lvl, string_view_t msg)
113 {
114 bool log_enabled = should_log(lvl);
115 bool traceback_enabled = tracer_.enabled();
116 if (!log_enabled && !traceback_enabled)
117 {
118 return;
119 }
120
121 details::log_msg log_msg(log_time, loc, name_, lvl, msg);
122 log_it_(log_msg, log_enabled, traceback_enabled);
123 }
124
125 void log(source_loc loc, level::level_enum lvl, string_view_t msg)
126 {
127 bool log_enabled = should_log(lvl);
128 bool traceback_enabled = tracer_.enabled();
129 if (!log_enabled && !traceback_enabled)
130 {
131 return;
132 }
133
134 details::log_msg log_msg(loc, name_, lvl, msg);
135 log_it_(log_msg, log_enabled, traceback_enabled);
136 }
137
138 void log(level::level_enum lvl, string_view_t msg)
139 {
140 log(source_loc{}, lvl, msg);
141 }
142
143 template<typename... Args>
144 void trace(format_string_t<Args...> fmt, Args &&... args)
145 {
146 log(level::trace, fmt, std::forward<Args>(args)...);
147 }
148
149 template<typename... Args>
150 void debug(format_string_t<Args...> fmt, Args &&... args)
151 {
152 log(level::debug, fmt, std::forward<Args>(args)...);
153 }
154
155 template<typename... Args>
156 void info(format_string_t<Args...> fmt, Args &&... args)
157 {
158 log(level::info, fmt, std::forward<Args>(args)...);
159 }
160
161 template<typename... Args>
162 void warn(format_string_t<Args...> fmt, Args &&... args)
163 {
164 log(level::warn, fmt, std::forward<Args>(args)...);
165 }
166
167 template<typename... Args>
168 void error(format_string_t<Args...> fmt, Args &&... args)
169 {
170 log(level::err, fmt, std::forward<Args>(args)...);
171 }
172
173 template<typename... Args>
174 void critical(format_string_t<Args...> fmt, Args &&... args)
175 {
176 log(level::critical, fmt, std::forward<Args>(args)...);
177 }
178
179#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
180 template<typename... Args>
181 void log(source_loc loc, level::level_enum lvl, wformat_string_t<Args...> fmt, Args &&... args)
182 {
183 log_(loc, lvl, details::to_string_view(fmt), std::forward<Args>(args)...);
184 }
185
186 template<typename... Args>
187 void log(level::level_enum lvl, wformat_string_t<Args...> fmt, Args &&... args)
188 {
189 log(source_loc{}, lvl, fmt, std::forward<Args>(args)...);
190 }
191
192 void log(log_clock::time_point log_time, source_loc loc, level::level_enum lvl, wstring_view_t msg)
193 {
194 bool log_enabled = should_log(lvl);
195 bool traceback_enabled = tracer_.enabled();
196 if (!log_enabled && !traceback_enabled)
197 {
198 return;
199 }
200
201 memory_buf_t buf;
202 details::os::wstr_to_utf8buf(wstring_view_t(msg.data(), msg.size()), buf);
203 details::log_msg log_msg(log_time, loc, name_, lvl, string_view_t(buf.data(), buf.size()));
204 log_it_(log_msg, log_enabled, traceback_enabled);
205 }
206
207 void log(source_loc loc, level::level_enum lvl, wstring_view_t msg)
208 {
209 bool log_enabled = should_log(lvl);
210 bool traceback_enabled = tracer_.enabled();
211 if (!log_enabled && !traceback_enabled)
212 {
213 return;
214 }
215
216 memory_buf_t buf;
217 details::os::wstr_to_utf8buf(wstring_view_t(msg.data(), msg.size()), buf);
218 details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()));
219 log_it_(log_msg, log_enabled, traceback_enabled);
220 }
221
222 void log(level::level_enum lvl, wstring_view_t msg)
223 {
224 log(source_loc{}, lvl, msg);
225 }
226
227 template<typename... Args>
228 void trace(wformat_string_t<Args...> fmt, Args &&... args)
229 {
230 log(level::trace, fmt, std::forward<Args>(args)...);
231 }
232
233 template<typename... Args>
234 void debug(wformat_string_t<Args...> fmt, Args &&... args)
235 {
236 log(level::debug, fmt, std::forward<Args>(args)...);
237 }
238
239 template<typename... Args>
240 void info(wformat_string_t<Args...> fmt, Args &&... args)
241 {
242 log(level::info, fmt, std::forward<Args>(args)...);
243 }
244
245 template<typename... Args>
246 void warn(wformat_string_t<Args...> fmt, Args &&... args)
247 {
248 log(level::warn, fmt, std::forward<Args>(args)...);
249 }
250
251 template<typename... Args>
252 void error(wformat_string_t<Args...> fmt, Args &&... args)
253 {
254 log(level::err, fmt, std::forward<Args>(args)...);
255 }
256
257 template<typename... Args>
258 void critical(wformat_string_t<Args...> fmt, Args &&... args)
259 {
260 log(level::critical, fmt, std::forward<Args>(args)...);
261 }
262#endif
263
264 template<typename T>
265 void trace(const T &msg)
266 {
267 log(level::trace, msg);
268 }
269
270 template<typename T>
271 void debug(const T &msg)
272 {
273 log(level::debug, msg);
274 }
275
276 template<typename T>
277 void info(const T &msg)
278 {
279 log(level::info, msg);
280 }
281
282 template<typename T>
283 void warn(const T &msg)
284 {
285 log(level::warn, msg);
286 }
287
288 template<typename T>
289 void error(const T &msg)
290 {
291 log(level::err, msg);
292 }
293
294 template<typename T>
295 void critical(const T &msg)
296 {
297 log(level::critical, msg);
298 }
299
300 // return true logging is enabled for the given level.
301 bool should_log(level::level_enum msg_level) const
302 {
303 return msg_level >= level_.load(std::memory_order_relaxed);
304 }
305
306 // return true if backtrace logging is enabled.
307 bool should_backtrace() const
308 {
309 return tracer_.enabled();
310 }
311
312 void set_level(level::level_enum log_level);
313
314 level::level_enum level() const;
315
316 const std::string &name() const;
317
318 // set formatting for the sinks in this logger.
319 // each sink will get a separate instance of the formatter object.
320 void set_formatter(std::unique_ptr<formatter> f);
321
322 // set formatting for the sinks in this logger.
323 // equivalent to
324 // set_formatter(make_unique<pattern_formatter>(pattern, time_type))
325 // Note: each sink will get a new instance of a formatter object, replacing the old one.
326 void set_pattern(std::string pattern, pattern_time_type time_type = pattern_time_type::local);
327
328 // backtrace support.
329 // efficiently store all debug/trace messages in a circular buffer until needed for debugging.
330 void enable_backtrace(size_t n_messages);
331 void disable_backtrace();
332 void dump_backtrace();
333
334 // flush functions
335 void flush();
336 void flush_on(level::level_enum log_level);
337 level::level_enum flush_level() const;
338
339 // sinks
340 const std::vector<sink_ptr> &sinks() const;
341
342 std::vector<sink_ptr> &sinks();
343
344 // error handler
345 void set_error_handler(err_handler);
346
347 // create new logger with same sinks and configuration.
348 virtual std::shared_ptr<logger> clone(std::string logger_name);
349
350protected:
351 std::string name_;
352 std::vector<sink_ptr> sinks_;
353 spdlog::level_t level_{level::info};
354 spdlog::level_t flush_level_{level::off};
355 err_handler custom_err_handler_{nullptr};
356 details::backtracer tracer_;
357
358 // common implementation for after templated public api has been resolved
359 template<typename... Args>
360 void log_(source_loc loc, level::level_enum lvl, string_view_t fmt, Args &&... args)
361 {
362 bool log_enabled = should_log(lvl);
363 bool traceback_enabled = tracer_.enabled();
364 if (!log_enabled && !traceback_enabled)
365 {
366 return;
367 }
368 SPDLOG_TRY
369 {
370 memory_buf_t buf;
371#ifdef SPDLOG_USE_STD_FORMAT
372 fmt_lib::vformat_to(std::back_inserter(buf), fmt, fmt_lib::make_format_args(std::forward<Args>(args)...));
373#else
374 fmt::vformat_to(fmt::appender(buf), fmt, fmt::make_format_args(std::forward<Args>(args)...));
375#endif
376
377 details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()));
378 log_it_(log_msg, log_enabled, traceback_enabled);
379 }
380 SPDLOG_LOGGER_CATCH(loc)
381 }
382
383#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
384 template<typename... Args>
385 void log_(source_loc loc, level::level_enum lvl, wstring_view_t fmt, Args &&... args)
386 {
387 bool log_enabled = should_log(lvl);
388 bool traceback_enabled = tracer_.enabled();
389 if (!log_enabled && !traceback_enabled)
390 {
391 return;
392 }
393 SPDLOG_TRY
394 {
395 // format to wmemory_buffer and convert to utf8
396 wmemory_buf_t wbuf;
397 fmt_lib::vformat_to(
398 std::back_inserter(wbuf), fmt, fmt_lib::make_format_args<fmt_lib::wformat_context>(std::forward<Args>(args)...));
399
400 memory_buf_t buf;
401 details::os::wstr_to_utf8buf(wstring_view_t(wbuf.data(), wbuf.size()), buf);
402 details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()));
403 log_it_(log_msg, log_enabled, traceback_enabled);
404 }
405 SPDLOG_LOGGER_CATCH(loc)
406 }
407#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT
408
409 // log the given message (if the given log level is high enough),
410 // and save backtrace (if backtrace is enabled).
411 void log_it_(const details::log_msg &log_msg, bool log_enabled, bool traceback_enabled);
412 virtual void sink_it_(const details::log_msg &msg);
413 virtual void flush_();
414 void dump_backtrace_();
415 bool should_flush_(const details::log_msg &msg);
416
417 // handle errors during logging.
418 // default handler prints the error to stderr at max rate of 1 message/sec.
419 void err_handler_(const std::string &msg);
420};
421
422void swap(logger &a, logger &b);
423
424} // namespace spdlog
425
426#ifdef SPDLOG_HEADER_ONLY
427# include "logger-inl.h"
428#endif
429