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 | |
40 | namespace spdlog { |
41 | |
42 | class logger |
43 | { |
44 | public: |
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 | |
347 | protected: |
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 | |
368 | void swap(logger &a, logger &b); |
369 | |
370 | } // namespace spdlog |
371 | |
372 | #ifdef SPDLOG_HEADER_ONLY |
373 | #include "logger-inl.h" |
374 | #endif |
375 | |