Coverage Report

Created: 2026-02-14 07:07

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