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#include <spdlog/details/os.h>
23#endif
24
25#include <vector>
26#ifndef SPDLOG_NO_EXCEPTIONS
27#define SPDLOG_LOGGER_CATCH() \
28 catch (const std::exception &ex) \
29 { \
30 err_handler_(ex.what()); \
31 } \
32 catch (...) \
33 { \
34 err_handler_("Unknown exception in logger"); \
35 }
36#else
37#define SPDLOG_LOGGER_CATCH()
38#endif
39
40namespace spdlog {
41
42class logger
43{
44public:
45 // Empty logger
46 explicit logger(std::string name)
47 : name_(std::move(name))
48 , sinks_()
49 {}
50
51 // Logger with range on sinks
52 template<typename It>
53 logger(std::string name, It begin, It end)
54 : name_(std::move(name))
55 , sinks_(begin, end)
56 {}
57
58 // Logger with single sink
59 logger(std::string name, sink_ptr single_sink)
60 : logger(std::move(name), {std::move(single_sink)})
61 {}
62
63 // Logger with sinks init list
64 logger(std::string name, sinks_init_list sinks)
65 : logger(std::move(name), sinks.begin(), sinks.end())
66 {}
67
68 virtual ~logger() = default;
69
70 logger(const logger &other);
71 logger(logger &&other) SPDLOG_NOEXCEPT;
72 logger &operator=(logger other) SPDLOG_NOEXCEPT;
73
74 void swap(spdlog::logger &other) SPDLOG_NOEXCEPT;
75
76 template<typename... Args>
77 void log(source_loc loc, level::level_enum lvl, string_view_t fmt, const Args &... args)
78 {
79 bool log_enabled = should_log(lvl);
80 bool traceback_enabled = tracer_.enabled();
81 if (!log_enabled && !traceback_enabled)
82 {
83 return;
84 }
85 SPDLOG_TRY
86 {
87 memory_buf_t buf;
88 fmt::format_to(buf, fmt, args...);
89 details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()));
90 log_it_(log_msg, log_enabled, traceback_enabled);
91 }
92 SPDLOG_LOGGER_CATCH()
93 }
94
95 template<typename... Args>
96 void log(level::level_enum lvl, string_view_t fmt, const Args &... args)
97 {
98 log(source_loc{}, lvl, fmt, args...);
99 }
100
101 template<typename... Args>
102 void trace(string_view_t fmt, const Args &... args)
103 {
104 log(level::trace, fmt, args...);
105 }
106
107 template<typename... Args>
108 void debug(string_view_t fmt, const Args &... args)
109 {
110 log(level::debug, fmt, args...);
111 }
112
113 template<typename... Args>
114 void info(string_view_t fmt, const Args &... args)
115 {
116 log(level::info, fmt, args...);
117 }
118
119 template<typename... Args>
120 void warn(string_view_t fmt, const Args &... args)
121 {
122 log(level::warn, fmt, args...);
123 }
124
125 template<typename... Args>
126 void error(string_view_t fmt, const Args &... args)
127 {
128 log(level::err, fmt, args...);
129 }
130
131 template<typename... Args>
132 void critical(string_view_t fmt, const Args &... args)
133 {
134 log(level::critical, fmt, args...);
135 }
136
137 template<typename T>
138 void log(level::level_enum lvl, const T &msg)
139 {
140 log(source_loc{}, lvl, msg);
141 }
142
143 // T can be statically converted to string_view
144 template<class T, typename std::enable_if<std::is_convertible<const T &, spdlog::string_view_t>::value, T>::type * = nullptr>
145 void log(source_loc loc, level::level_enum lvl, const T &msg)
146 {
147 bool log_enabled = should_log(lvl);
148 bool traceback_enabled = tracer_.enabled();
149 if (!log_enabled && !traceback_enabled)
150 {
151 return;
152 }
153
154 details::log_msg log_msg(loc, name_, lvl, msg);
155 log_it_(log_msg, log_enabled, traceback_enabled);
156 }
157
158 void log(level::level_enum lvl, string_view_t msg)
159 {
160 log(source_loc{}, lvl, msg);
161 }
162
163 // T cannot be statically converted to string_view or wstring_view
164 template<class T, typename std::enable_if<!std::is_convertible<const T &, spdlog::string_view_t>::value &&
165 !is_convertible_to_wstring_view<const T &>::value,
166 T>::type * = nullptr>
167 void log(source_loc loc, level::level_enum lvl, const T &msg)
168 {
169 log(loc, lvl, "{}", msg);
170 }
171
172 template<typename T>
173 void trace(const T &msg)
174 {
175 log(level::trace, msg);
176 }
177
178 template<typename T>
179 void debug(const T &msg)
180 {
181 log(level::debug, msg);
182 }
183
184 template<typename T>
185 void info(const T &msg)
186 {
187 log(level::info, msg);
188 }
189
190 template<typename T>
191 void warn(const T &msg)
192 {
193 log(level::warn, msg);
194 }
195
196 template<typename T>
197 void error(const T &msg)
198 {
199 log(level::err, msg);
200 }
201
202 template<typename T>
203 void critical(const T &msg)
204 {
205 log(level::critical, msg);
206 }
207
208#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
209#ifndef _WIN32
210#error SPDLOG_WCHAR_TO_UTF8_SUPPORT only supported on windows
211#else
212
213 template<typename... Args>
214 void log(source_loc loc, level::level_enum lvl, wstring_view_t fmt, const Args &... args)
215 {
216 bool log_enabled = should_log(lvl);
217 bool traceback_enabled = tracer_.enabled();
218 if (!log_enabled && !traceback_enabled)
219 {
220 return;
221 }
222 SPDLOG_TRY
223 {
224 // format to wmemory_buffer and convert to utf8
225 fmt::wmemory_buffer wbuf;
226 fmt::format_to(wbuf, fmt, args...);
227
228 memory_buf_t buf;
229 details::os::wstr_to_utf8buf(wstring_view_t(wbuf.data(), wbuf.size()), buf);
230 details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()));
231 log_it_(log_msg, log_enabled, traceback_enabled);
232 }
233 SPDLOG_LOGGER_CATCH()
234 }
235
236 template<typename... Args>
237 void log(level::level_enum lvl, wstring_view_t fmt, const Args &... args)
238 {
239 log(source_loc{}, lvl, fmt, args...);
240 }
241
242 template<typename... Args>
243 void trace(wstring_view_t fmt, const Args &... args)
244 {
245 log(level::trace, fmt, args...);
246 }
247
248 template<typename... Args>
249 void debug(wstring_view_t fmt, const Args &... args)
250 {
251 log(level::debug, fmt, args...);
252 }
253
254 template<typename... Args>
255 void info(wstring_view_t fmt, const Args &... args)
256 {
257 log(level::info, fmt, args...);
258 }
259
260 template<typename... Args>
261 void warn(wstring_view_t fmt, const Args &... args)
262 {
263 log(level::warn, fmt, args...);
264 }
265
266 template<typename... Args>
267 void error(wstring_view_t fmt, const Args &... args)
268 {
269 log(level::err, fmt, args...);
270 }
271
272 template<typename... Args>
273 void critical(wstring_view_t fmt, const Args &... args)
274 {
275 log(level::critical, fmt, args...);
276 }
277
278 // T can be statically converted to wstring_view
279 template<class T, typename std::enable_if<is_convertible_to_wstring_view<const T &>::value, T>::type * = nullptr>
280 void log(source_loc loc, level::level_enum lvl, const T &msg)
281 {
282 bool log_enabled = should_log(lvl);
283 bool traceback_enabled = tracer_.enabled();
284 if (!log_enabled && !traceback_enabled)
285 {
286 return;
287 }
288
289 SPDLOG_TRY
290 {
291 memory_buf_t buf;
292 details::os::wstr_to_utf8buf(msg, buf);
293 details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()));
294 log_it_(log_msg, log_enabled, traceback_enabled);
295 }
296 SPDLOG_LOGGER_CATCH()
297 }
298#endif // _WIN32
299#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT
300
301 // return true logging is enabled for the given level.
302 bool should_log(level::level_enum msg_level) const
303 {
304 return msg_level >= level_.load(std::memory_order_relaxed);
305 }
306
307 // return true if backtrace logging is enabled.
308 bool should_backtrace() const
309 {
310 return tracer_.enabled();
311 }
312
313 void set_level(level::level_enum log_level);
314
315 level::level_enum level() const;
316
317 const std::string &name() const;
318
319 // set formatting for the sinks in this logger.
320 // each sink will get a separate instance of the formatter object.
321 void set_formatter(std::unique_ptr<formatter> f);
322
323 void set_pattern(std::string pattern, pattern_time_type time_type = pattern_time_type::local);
324
325 // backtrace support.
326 // efficiently store all debug/trace messages in a circular buffer until needed for debugging.
327 void enable_backtrace(size_t n_messages);
328 void disable_backtrace();
329 void dump_backtrace();
330
331 // flush functions
332 void flush();
333 void flush_on(level::level_enum log_level);
334 level::level_enum flush_level() const;
335
336 // sinks
337 const std::vector<sink_ptr> &sinks() const;
338
339 std::vector<sink_ptr> &sinks();
340
341 // error handler
342 void set_error_handler(err_handler);
343
344 // create new logger with same sinks and configuration.
345 virtual std::shared_ptr<logger> clone(std::string logger_name);
346
347protected:
348 std::string name_;
349 std::vector<sink_ptr> sinks_;
350 spdlog::level_t level_{level::info};
351 spdlog::level_t flush_level_{level::off};
352 err_handler custom_err_handler_{nullptr};
353 details::backtracer tracer_;
354
355 // log the given message (if the given log level is high enough),
356 // and save backtrace (if backtrace is enabled).
357 void log_it_(const details::log_msg &log_msg, bool log_enabled, bool traceback_enabled);
358 virtual void sink_it_(const details::log_msg &msg);
359 virtual void flush_();
360 void dump_backtrace_();
361 bool should_flush_(const details::log_msg &msg);
362
363 // handle errors during logging.
364 // default handler prints the error to stderr at max rate of 1 message/sec.
365 void err_handler_(const std::string &msg);
366};
367
368void swap(logger &a, logger &b);
369
370} // namespace spdlog
371
372#ifdef SPDLOG_HEADER_ONLY
373#include "logger-inl.h"
374#endif
375