Browse Source

Moved to report to spdlog allowing asyncronous console and file logging

Eyck Jentzsch 1 month ago
parent
commit
5087ea5124
79 changed files with 17677 additions and 65 deletions
  1. 28
    5
      incl/scc/report.h
  2. 93
    0
      incl/spdlog/async.h
  3. 92
    0
      incl/spdlog/async_logger-inl.h
  4. 68
    0
      incl/spdlog/async_logger.h
  5. 57
    0
      incl/spdlog/common-inl.h
  6. 246
    0
      incl/spdlog/common.h
  7. 74
    0
      incl/spdlog/details/backtracer-inl.h
  8. 46
    0
      incl/spdlog/details/backtracer.h
  9. 119
    0
      incl/spdlog/details/circular_q.h
  10. 32
    0
      incl/spdlog/details/console_globals.h
  11. 133
    0
      incl/spdlog/details/file_helper-inl.h
  12. 60
    0
      incl/spdlog/details/file_helper.h
  13. 111
    0
      incl/spdlog/details/fmt_helper.h
  14. 34
    0
      incl/spdlog/details/log_msg-inl.h
  15. 35
    0
      incl/spdlog/details/log_msg.h
  16. 60
    0
      incl/spdlog/details/log_msg_buffer-inl.h
  17. 33
    0
      incl/spdlog/details/log_msg_buffer.h
  18. 120
    0
      incl/spdlog/details/mpmc_blocking_q.h
  19. 49
    0
      incl/spdlog/details/null_mutex.h
  20. 465
    0
      incl/spdlog/details/os-inl.h
  21. 98
    0
      incl/spdlog/details/os.h
  22. 1317
    0
      incl/spdlog/details/pattern_formatter-inl.h
  23. 99
    0
      incl/spdlog/details/pattern_formatter.h
  24. 49
    0
      incl/spdlog/details/periodic_worker-inl.h
  25. 40
    0
      incl/spdlog/details/periodic_worker.h
  26. 284
    0
      incl/spdlog/details/registry-inl.h
  27. 109
    0
      incl/spdlog/details/registry.h
  28. 24
    0
      incl/spdlog/details/synchronous_factory.h
  29. 127
    0
      incl/spdlog/details/thread_pool-inl.h
  30. 120
    0
      incl/spdlog/details/thread_pool.h
  31. 175
    0
      incl/spdlog/fmt/bin_to_hex.h
  32. 27
    0
      incl/spdlog/fmt/bundled/LICENSE.rst
  33. 829
    0
      incl/spdlog/fmt/bundled/chrono.h
  34. 585
    0
      incl/spdlog/fmt/bundled/color.h
  35. 466
    0
      incl/spdlog/fmt/bundled/compile.h
  36. 1414
    0
      incl/spdlog/fmt/bundled/core.h
  37. 1000
    0
      incl/spdlog/fmt/bundled/format-inl.h
  38. 3600
    0
      incl/spdlog/fmt/bundled/format.h
  39. 77
    0
      incl/spdlog/fmt/bundled/locale.h
  40. 136
    0
      incl/spdlog/fmt/bundled/ostream.h
  41. 311
    0
      incl/spdlog/fmt/bundled/posix.h
  42. 715
    0
      incl/spdlog/fmt/bundled/printf.h
  43. 288
    0
      incl/spdlog/fmt/bundled/ranges.h
  44. 293
    0
      incl/spdlog/fmt/bundled/safe-duration-cast.h
  45. 27
    0
      incl/spdlog/fmt/fmt.h
  46. 18
    0
      incl/spdlog/fmt/ostr.h
  47. 18
    0
      incl/spdlog/formatter.h
  48. 246
    0
      incl/spdlog/logger-inl.h
  49. 383
    0
      incl/spdlog/logger.h
  50. 119
    0
      incl/spdlog/sinks/android_sink.h
  51. 136
    0
      incl/spdlog/sinks/ansicolor_sink-inl.h
  52. 113
    0
      incl/spdlog/sinks/ansicolor_sink.h
  53. 63
    0
      incl/spdlog/sinks/base_sink-inl.h
  54. 46
    0
      incl/spdlog/sinks/base_sink.h
  55. 43
    0
      incl/spdlog/sinks/basic_file_sink-inl.h
  56. 58
    0
      incl/spdlog/sinks/basic_file_sink.h
  57. 185
    0
      incl/spdlog/sinks/daily_file_sink.h
  58. 93
    0
      incl/spdlog/sinks/dist_sink.h
  59. 94
    0
      incl/spdlog/sinks/dup_filter_sink.h
  60. 48
    0
      incl/spdlog/sinks/msvc_sink.h
  61. 44
    0
      incl/spdlog/sinks/null_sink.h
  62. 50
    0
      incl/spdlog/sinks/ostream_sink.h
  63. 130
    0
      incl/spdlog/sinks/rotating_file_sink-inl.h
  64. 78
    0
      incl/spdlog/sinks/rotating_file_sink.h
  65. 25
    0
      incl/spdlog/sinks/sink-inl.h
  66. 35
    0
      incl/spdlog/sinks/sink.h
  67. 38
    0
      incl/spdlog/sinks/stdout_color_sinks-inl.h
  68. 45
    0
      incl/spdlog/sinks/stdout_color_sinks.h
  69. 94
    0
      incl/spdlog/sinks/stdout_sinks-inl.h
  70. 76
    0
      incl/spdlog/sinks/stdout_sinks.h
  71. 108
    0
      incl/spdlog/sinks/syslog_sink.h
  72. 98
    0
      incl/spdlog/sinks/systemd_sink.h
  73. 175
    0
      incl/spdlog/sinks/wincolor_sink-inl.h
  74. 92
    0
      incl/spdlog/sinks/wincolor_sink.h
  75. 115
    0
      incl/spdlog/spdlog-inl.h
  76. 342
    0
      incl/spdlog/spdlog.h
  77. 136
    0
      incl/spdlog/tweakme.h
  78. 10
    0
      incl/spdlog/version.h
  79. 158
    60
      src/report.cpp

+ 28
- 5
incl/scc/report.h View File

@@ -25,19 +25,41 @@
25 25
 #include <util/logging.h>
26 26
 #include <util/ities.h>
27 27
 
28
-namespace logging {
29
-class SystemC {};
30
-class STDIO {};
31
-}
32 28
 namespace scc {
33 29
 
34 30
 /**
35
- * initializes the SystemC logging system to use logging::Logger with a particular logging level
31
+ * initializes the SystemC logging system with a particular logging level
36 32
  *
37 33
  * @param level the logging level
34
+ * @param type_field_width width of the message type field in output, setting to zero suppresses the message type
35
+ * @param print_time wheter to print the system time stamp
38 36
  */
39 37
 void init_logging(logging::log_level level = logging::WARNING, unsigned type_field_width = 24, bool print_time = false);
40 38
 /**
39
+ * the configuration class for the logging setup
40
+ */
41
+struct LogConfig {
42
+  logging::log_level level{logging::WARNING};
43
+  unsigned msg_type_field_width{24};
44
+  bool print_sys_time{false};
45
+  bool print_sim_time{true};
46
+  bool print_severity{true};
47
+  std::string log_file_name{""};
48
+
49
+  LogConfig& setLogLevel(logging::log_level);
50
+  LogConfig& setFieldWidth( unsigned);
51
+  LogConfig& setPrintSysTime(bool);
52
+  LogConfig& setPrintSimTime(bool);
53
+  LogConfig& setPrintSeverity(bool);
54
+  LogConfig& setLogFileName(std::string&&);
55
+};
56
+/**
57
+ * initializes the SystemC logging system with a particular configuration
58
+ *
59
+ * @param log_config the logging configuration
60
+ */
61
+void init_logging(const LogConfig& log_config);
62
+/**
41 63
  * the logger class
42 64
  */
43 65
 template <sc_core::sc_severity SEVERITY> struct ScLogger {
@@ -203,6 +225,7 @@ public:
203 225
     void reset();
204 226
 protected:
205 227
     std::streamsize xsputn(const char_type* s, std::streamsize n) override;
228
+    int sync() override;
206 229
     std::ostream& os;
207 230
     logging::log_level level;
208 231
     std::streambuf* old_buf;

+ 93
- 0
incl/spdlog/async.h View File

@@ -0,0 +1,93 @@
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
+//
7
+// Async logging using global thread pool
8
+// All loggers created here share same global thread pool.
9
+// Each log message is pushed to a queue along withe a shared pointer to the
10
+// logger.
11
+// If a logger deleted while having pending messages in the queue, it's actual
12
+// destruction will defer
13
+// until all its messages are processed by the thread pool.
14
+// This is because each message in the queue holds a shared_ptr to the
15
+// originating logger.
16
+
17
+#include "spdlog/async_logger.h"
18
+#include "spdlog/details/registry.h"
19
+#include "spdlog/details/thread_pool.h"
20
+
21
+#include <memory>
22
+#include <mutex>
23
+#include <functional>
24
+
25
+namespace spdlog {
26
+
27
+namespace details {
28
+static const size_t default_async_q_size = 8192;
29
+}
30
+
31
+// async logger factory - creates async loggers backed with thread pool.
32
+// if a global thread pool doesn't already exist, create it with default queue
33
+// size of 8192 items and single thread.
34
+template<async_overflow_policy OverflowPolicy = async_overflow_policy::block>
35
+struct async_factory_impl
36
+{
37
+    template<typename Sink, typename... SinkArgs>
38
+    static std::shared_ptr<async_logger> create(std::string logger_name, SinkArgs &&... args)
39
+    {
40
+        auto &registry_inst = details::registry::instance();
41
+
42
+        // create global thread pool if not already exists..
43
+
44
+        auto &mutex = registry_inst.tp_mutex();
45
+        std::lock_guard<std::recursive_mutex> tp_lock(mutex);
46
+        auto tp = registry_inst.get_tp();
47
+        if (tp == nullptr)
48
+        {
49
+            tp = std::make_shared<details::thread_pool>(details::default_async_q_size, 1);
50
+            registry_inst.set_tp(tp);
51
+        }
52
+
53
+        auto sink = std::make_shared<Sink>(std::forward<SinkArgs>(args)...);
54
+        auto new_logger = std::make_shared<async_logger>(std::move(logger_name), std::move(sink), std::move(tp), OverflowPolicy);
55
+        registry_inst.initialize_logger(new_logger);
56
+        return new_logger;
57
+    }
58
+};
59
+
60
+using async_factory = async_factory_impl<async_overflow_policy::block>;
61
+using async_factory_nonblock = async_factory_impl<async_overflow_policy::overrun_oldest>;
62
+
63
+template<typename Sink, typename... SinkArgs>
64
+inline std::shared_ptr<spdlog::logger> create_async(std::string logger_name, SinkArgs &&... sink_args)
65
+{
66
+    return async_factory::create<Sink>(std::move(logger_name), std::forward<SinkArgs>(sink_args)...);
67
+}
68
+
69
+template<typename Sink, typename... SinkArgs>
70
+inline std::shared_ptr<spdlog::logger> create_async_nb(std::string logger_name, SinkArgs &&... sink_args)
71
+{
72
+    return async_factory_nonblock::create<Sink>(std::move(logger_name), std::forward<SinkArgs>(sink_args)...);
73
+}
74
+
75
+// set global thread pool.
76
+inline void init_thread_pool(size_t q_size, size_t thread_count, std::function<void()> on_thread_start)
77
+{
78
+    auto tp = std::make_shared<details::thread_pool>(q_size, thread_count, on_thread_start);
79
+    details::registry::instance().set_tp(std::move(tp));
80
+}
81
+
82
+// set global thread pool.
83
+inline void init_thread_pool(size_t q_size, size_t thread_count)
84
+{
85
+    init_thread_pool(q_size, thread_count, [] {});
86
+}
87
+
88
+// get the global thread pool.
89
+inline std::shared_ptr<spdlog::details::thread_pool> thread_pool()
90
+{
91
+    return details::registry::instance().get_tp();
92
+}
93
+} // namespace spdlog

+ 92
- 0
incl/spdlog/async_logger-inl.h View File

@@ -0,0 +1,92 @@
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
+#ifndef SPDLOG_HEADER_ONLY
7
+#include "spdlog/async_logger.h"
8
+#endif
9
+
10
+#include "spdlog/sinks/sink.h"
11
+#include "spdlog/details/thread_pool.h"
12
+
13
+#include <memory>
14
+#include <string>
15
+
16
+SPDLOG_INLINE spdlog::async_logger::async_logger(
17
+    std::string logger_name, sinks_init_list sinks_list, std::weak_ptr<details::thread_pool> tp, async_overflow_policy overflow_policy)
18
+    : async_logger(std::move(logger_name), sinks_list.begin(), sinks_list.end(), std::move(tp), overflow_policy)
19
+{}
20
+
21
+SPDLOG_INLINE spdlog::async_logger::async_logger(
22
+    std::string logger_name, sink_ptr single_sink, std::weak_ptr<details::thread_pool> tp, async_overflow_policy overflow_policy)
23
+    : async_logger(std::move(logger_name), {std::move(single_sink)}, std::move(tp), overflow_policy)
24
+{}
25
+
26
+// send the log message to the thread pool
27
+SPDLOG_INLINE void spdlog::async_logger::sink_it_(const details::log_msg &msg)
28
+{
29
+    if (auto pool_ptr = thread_pool_.lock())
30
+    {
31
+        pool_ptr->post_log(shared_from_this(), msg, overflow_policy_);
32
+    }
33
+    else
34
+    {
35
+        SPDLOG_THROW(spdlog_ex("async log: thread pool doesn't exist anymore"));
36
+    }
37
+}
38
+
39
+// send flush request to the thread pool
40
+SPDLOG_INLINE void spdlog::async_logger::flush_()
41
+{
42
+    if (auto pool_ptr = thread_pool_.lock())
43
+    {
44
+        pool_ptr->post_flush(shared_from_this(), overflow_policy_);
45
+    }
46
+    else
47
+    {
48
+        SPDLOG_THROW(spdlog_ex("async flush: thread pool doesn't exist anymore"));
49
+    }
50
+}
51
+
52
+//
53
+// backend functions - called from the thread pool to do the actual job
54
+//
55
+SPDLOG_INLINE void spdlog::async_logger::backend_sink_it_(const details::log_msg &msg)
56
+{
57
+    for (auto &sink : sinks_)
58
+    {
59
+        if (sink->should_log(msg.level))
60
+        {
61
+            SPDLOG_TRY
62
+            {
63
+                sink->log(msg);
64
+            }
65
+            SPDLOG_LOGGER_CATCH()
66
+        }
67
+    }
68
+
69
+    if (should_flush_(msg))
70
+    {
71
+        backend_flush_();
72
+    }
73
+}
74
+
75
+SPDLOG_INLINE void spdlog::async_logger::backend_flush_()
76
+{
77
+    for (auto &sink : sinks_)
78
+    {
79
+        SPDLOG_TRY
80
+        {
81
+            sink->flush();
82
+        }
83
+        SPDLOG_LOGGER_CATCH()
84
+    }
85
+}
86
+
87
+SPDLOG_INLINE std::shared_ptr<spdlog::logger> spdlog::async_logger::clone(std::string new_name)
88
+{
89
+    auto cloned = std::make_shared<spdlog::async_logger>(*this);
90
+    cloned->name_ = std::move(new_name);
91
+    return cloned;
92
+}

+ 68
- 0
incl/spdlog/async_logger.h View File

@@ -0,0 +1,68 @@
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
+// Fast asynchronous logger.
7
+// Uses pre allocated queue.
8
+// Creates a single back thread to pop messages from the queue and log them.
9
+//
10
+// Upon each log write the logger:
11
+//    1. Checks if its log level is enough to log the message
12
+//    2. Push a new copy of the message to a queue (or block the caller until
13
+//    space is available in the queue)
14
+// Upon destruction, logs all remaining messages in the queue before
15
+// destructing..
16
+
17
+#include "spdlog/logger.h"
18
+
19
+namespace spdlog {
20
+
21
+// Async overflow policy - block by default.
22
+enum class async_overflow_policy
23
+{
24
+    block,         // Block until message can be enqueued
25
+    overrun_oldest // Discard oldest message in the queue if full when trying to
26
+                   // add new item.
27
+};
28
+
29
+namespace details {
30
+class thread_pool;
31
+}
32
+
33
+class async_logger final : public std::enable_shared_from_this<async_logger>, public logger
34
+{
35
+    friend class details::thread_pool;
36
+
37
+public:
38
+    template<typename It>
39
+    async_logger(std::string logger_name, It begin, It end, std::weak_ptr<details::thread_pool> tp,
40
+        async_overflow_policy overflow_policy = async_overflow_policy::block)
41
+        : logger(std::move(logger_name), begin, end)
42
+        , thread_pool_(std::move(tp))
43
+        , overflow_policy_(overflow_policy)
44
+    {}
45
+
46
+    async_logger(std::string logger_name, sinks_init_list sinks_list, std::weak_ptr<details::thread_pool> tp,
47
+        async_overflow_policy overflow_policy = async_overflow_policy::block);
48
+
49
+    async_logger(std::string logger_name, sink_ptr single_sink, std::weak_ptr<details::thread_pool> tp,
50
+        async_overflow_policy overflow_policy = async_overflow_policy::block);
51
+
52
+    std::shared_ptr<logger> clone(std::string new_name) override;
53
+
54
+protected:
55
+    void sink_it_(const details::log_msg &msg) override;
56
+    void flush_() override;
57
+    void backend_sink_it_(const details::log_msg &incoming_log_msg);
58
+    void backend_flush_();
59
+
60
+private:
61
+    std::weak_ptr<details::thread_pool> thread_pool_;
62
+    async_overflow_policy overflow_policy_;
63
+};
64
+} // namespace spdlog
65
+
66
+#ifdef SPDLOG_HEADER_ONLY
67
+#include "async_logger-inl.h"
68
+#endif

+ 57
- 0
incl/spdlog/common-inl.h View File

@@ -0,0 +1,57 @@
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
+#ifndef SPDLOG_HEADER_ONLY
7
+#include "spdlog/common.h"
8
+#endif
9
+
10
+namespace spdlog {
11
+namespace level {
12
+static string_view_t level_string_views[] SPDLOG_LEVEL_NAMES;
13
+
14
+static const char *short_level_names[] SPDLOG_SHORT_LEVEL_NAMES;
15
+
16
+SPDLOG_INLINE string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT
17
+{
18
+    return level_string_views[l];
19
+}
20
+
21
+SPDLOG_INLINE const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT
22
+{
23
+    return short_level_names[l];
24
+}
25
+
26
+SPDLOG_INLINE spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT
27
+{
28
+    int level = 0;
29
+    for (const auto &level_str : level_string_views)
30
+    {
31
+        if (level_str == name)
32
+        {
33
+            return static_cast<level::level_enum>(level);
34
+        }
35
+        level++;
36
+    }
37
+    return level::off;
38
+}
39
+} // namespace level
40
+
41
+SPDLOG_INLINE spdlog_ex::spdlog_ex(std::string msg)
42
+    : msg_(std::move(msg))
43
+{}
44
+
45
+SPDLOG_INLINE spdlog_ex::spdlog_ex(const std::string &msg, int last_errno)
46
+{
47
+    memory_buf_t outbuf;
48
+    fmt::format_system_error(outbuf, last_errno, msg);
49
+    msg_ = fmt::to_string(outbuf);
50
+}
51
+
52
+SPDLOG_INLINE const char *spdlog_ex::what() const SPDLOG_NOEXCEPT
53
+{
54
+    return msg_.c_str();
55
+}
56
+
57
+} // namespace spdlog

+ 246
- 0
incl/spdlog/common.h View File

@@ -0,0 +1,246 @@
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
+#include "spdlog/tweakme.h"
7
+#include "spdlog/details/null_mutex.h"
8
+
9
+#include <atomic>
10
+#include <chrono>
11
+#include <initializer_list>
12
+#include <memory>
13
+#include <exception>
14
+#include <string>
15
+#include <type_traits>
16
+#include <functional>
17
+
18
+#ifdef _WIN32
19
+#ifndef NOMINMAX
20
+#define NOMINMAX // prevent windows redefining min/max
21
+#endif
22
+
23
+#ifndef WIN32_LEAN_AND_MEAN
24
+#define WIN32_LEAN_AND_MEAN
25
+#endif
26
+
27
+#include <windows.h>
28
+#endif //_WIN32
29
+
30
+#ifdef SPDLOG_COMPILED_LIB
31
+#undef SPDLOG_HEADER_ONLY
32
+#define SPDLOG_INLINE
33
+#else
34
+#define SPDLOG_HEADER_ONLY
35
+#define SPDLOG_INLINE inline
36
+#endif
37
+
38
+#include "spdlog/fmt/fmt.h"
39
+
40
+// visual studio upto 2013 does not support noexcept nor constexpr
41
+#if defined(_MSC_VER) && (_MSC_VER < 1900)
42
+#define SPDLOG_NOEXCEPT _NOEXCEPT
43
+#define SPDLOG_CONSTEXPR
44
+#else
45
+#define SPDLOG_NOEXCEPT noexcept
46
+#define SPDLOG_CONSTEXPR constexpr
47
+#endif
48
+
49
+#if defined(__GNUC__) || defined(__clang__)
50
+#define SPDLOG_DEPRECATED __attribute__((deprecated))
51
+#elif defined(_MSC_VER)
52
+#define SPDLOG_DEPRECATED __declspec(deprecated)
53
+#else
54
+#define SPDLOG_DEPRECATED
55
+#endif
56
+
57
+// disable thread local on msvc 2013
58
+#ifndef SPDLOG_NO_TLS
59
+#if (defined(_MSC_VER) && (_MSC_VER < 1900)) || defined(__cplusplus_winrt)
60
+#define SPDLOG_NO_TLS 1
61
+#endif
62
+#endif
63
+
64
+#ifndef SPDLOG_FUNCTION
65
+#define SPDLOG_FUNCTION __FUNCTION__
66
+#endif
67
+
68
+#ifdef SPDLOG_NO_EXCEPTIONS
69
+#define SPDLOG_TRY
70
+#define SPDLOG_THROW(ex)                                                                                                                   \
71
+    do                                                                                                                                     \
72
+    {                                                                                                                                      \
73
+        printf("spdlog fatal error: %s\n", ex.what());                                                                                     \
74
+        std::abort();                                                                                                                      \
75
+    } while (0)
76
+#define SPDLOG_CATCH_ALL()
77
+#else
78
+#define SPDLOG_TRY try
79
+#define SPDLOG_THROW(ex) throw(ex)
80
+#define SPDLOG_CATCH_ALL() catch (...)
81
+#endif
82
+
83
+namespace spdlog {
84
+
85
+class formatter;
86
+
87
+namespace sinks {
88
+class sink;
89
+}
90
+
91
+#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
92
+using filename_t = std::wstring;
93
+#define SPDLOG_FILENAME_T(s) L##s
94
+#else
95
+using filename_t = std::string;
96
+#define SPDLOG_FILENAME_T(s) s
97
+#endif
98
+
99
+using log_clock = std::chrono::system_clock;
100
+using sink_ptr = std::shared_ptr<sinks::sink>;
101
+using sinks_init_list = std::initializer_list<sink_ptr>;
102
+using err_handler = std::function<void(const std::string &err_msg)>;
103
+using string_view_t = fmt::basic_string_view<char>;
104
+using memory_buf_t = fmt::basic_memory_buffer<char, 250>;
105
+
106
+#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
107
+#ifndef _WIN32
108
+#error SPDLOG_WCHAR_TO_UTF8_SUPPORT only supported on windows
109
+#else
110
+using wstring_view_t = fmt::basic_string_view<wchar_t>;
111
+
112
+template<typename T>
113
+struct is_convertible_to_wstring_view : std::is_convertible<T, wstring_view_t>
114
+{};
115
+#endif // _WIN32
116
+#else
117
+template<typename>
118
+struct is_convertible_to_wstring_view : std::false_type
119
+{};
120
+#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT
121
+
122
+#if defined(SPDLOG_NO_ATOMIC_LEVELS)
123
+using level_t = details::null_atomic_int;
124
+#else
125
+using level_t = std::atomic<int>;
126
+#endif
127
+
128
+#define SPDLOG_LEVEL_TRACE 0
129
+#define SPDLOG_LEVEL_DEBUG 1
130
+#define SPDLOG_LEVEL_INFO 2
131
+#define SPDLOG_LEVEL_WARN 3
132
+#define SPDLOG_LEVEL_ERROR 4
133
+#define SPDLOG_LEVEL_CRITICAL 5
134
+#define SPDLOG_LEVEL_OFF 6
135
+
136
+#if !defined(SPDLOG_ACTIVE_LEVEL)
137
+#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_INFO
138
+#endif
139
+
140
+// Log level enum
141
+namespace level {
142
+enum level_enum
143
+{
144
+    trace = SPDLOG_LEVEL_TRACE,
145
+    debug = SPDLOG_LEVEL_DEBUG,
146
+    info = SPDLOG_LEVEL_INFO,
147
+    warn = SPDLOG_LEVEL_WARN,
148
+    err = SPDLOG_LEVEL_ERROR,
149
+    critical = SPDLOG_LEVEL_CRITICAL,
150
+    off = SPDLOG_LEVEL_OFF,
151
+};
152
+
153
+#if !defined(SPDLOG_LEVEL_NAMES)
154
+#define SPDLOG_LEVEL_NAMES                                                                                                                 \
155
+    {                                                                                                                                      \
156
+        "trace", "debug", "info", "warning", "error", "critical", "off"                                                                    \
157
+    }
158
+#endif
159
+
160
+#if !defined(SPDLOG_SHORT_LEVEL_NAMES)
161
+
162
+#define SPDLOG_SHORT_LEVEL_NAMES                                                                                                           \
163
+    {                                                                                                                                      \
164
+        "T", "D", "I", "W", "E", "C", "O"                                                                                                  \
165
+    }
166
+#endif
167
+
168
+string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT;
169
+const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT;
170
+spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT;
171
+
172
+using level_hasher = std::hash<int>;
173
+} // namespace level
174
+
175
+//
176
+// Color mode used by sinks with color support.
177
+//
178
+enum class color_mode
179
+{
180
+    always,
181
+    automatic,
182
+    never
183
+};
184
+
185
+//
186
+// Pattern time - specific time getting to use for pattern_formatter.
187
+// local time by default
188
+//
189
+enum class pattern_time_type
190
+{
191
+    local, // log localtime
192
+    utc    // log utc
193
+};
194
+
195
+//
196
+// Log exception
197
+//
198
+class spdlog_ex : public std::exception
199
+{
200
+public:
201
+    explicit spdlog_ex(std::string msg);
202
+    spdlog_ex(const std::string &msg, int last_errno);
203
+    const char *what() const SPDLOG_NOEXCEPT override;
204
+
205
+private:
206
+    std::string msg_;
207
+};
208
+
209
+struct source_loc
210
+{
211
+    SPDLOG_CONSTEXPR source_loc() = default;
212
+    SPDLOG_CONSTEXPR source_loc(const char *filename_in, int line_in, const char *funcname_in)
213
+        : filename{filename_in}
214
+        , line{line_in}
215
+        , funcname{funcname_in}
216
+    {}
217
+
218
+    SPDLOG_CONSTEXPR bool empty() const SPDLOG_NOEXCEPT
219
+    {
220
+        return line == 0;
221
+    }
222
+    const char *filename{nullptr};
223
+    int line{0};
224
+    const char *funcname{nullptr};
225
+};
226
+
227
+namespace details {
228
+// make_unique support for pre c++14
229
+
230
+#if __cplusplus >= 201402L // C++14 and beyond
231
+using std::make_unique;
232
+#else
233
+template<typename T, typename... Args>
234
+std::unique_ptr<T> make_unique(Args &&... args)
235
+{
236
+    static_assert(!std::is_array<T>::value, "arrays not supported");
237
+    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
238
+}
239
+#endif
240
+} // namespace details
241
+
242
+} // namespace spdlog
243
+
244
+#ifdef SPDLOG_HEADER_ONLY
245
+#include "common-inl.h"
246
+#endif

+ 74
- 0
incl/spdlog/details/backtracer-inl.h View File

@@ -0,0 +1,74 @@
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
+#ifndef SPDLOG_HEADER_ONLY
7
+#include "spdlog/details/backtracer.h"
8
+#endif
9
+namespace spdlog {
10
+namespace details {
11
+SPDLOG_INLINE backtracer::backtracer(const backtracer &other)
12
+{
13
+    std::lock_guard<std::mutex> lock(other.mutex_);
14
+    enabled_ = other.enabled();
15
+    messages_ = other.messages_;
16
+}
17
+
18
+SPDLOG_INLINE backtracer::backtracer(backtracer &&other) SPDLOG_NOEXCEPT
19
+{
20
+    std::lock_guard<std::mutex> lock(other.mutex_);
21
+    enabled_ = other.enabled();
22
+    messages_ = std::move(other.messages_);
23
+}
24
+
25
+SPDLOG_INLINE backtracer &backtracer::operator=(backtracer other)
26
+{
27
+    std::lock_guard<std::mutex> lock(mutex_);
28
+    enabled_ = other.enabled();
29
+    messages_ = other.messages_;
30
+    return *this;
31
+}
32
+
33
+SPDLOG_INLINE void backtracer::enable(size_t size)
34
+{
35
+    std::lock_guard<std::mutex> lock{mutex_};
36
+    enabled_.store(true, std::memory_order_relaxed);
37
+    messages_ = circular_q<log_msg_buffer>{size};
38
+}
39
+
40
+SPDLOG_INLINE void backtracer::disable()
41
+{
42
+    std::lock_guard<std::mutex> lock{mutex_};
43
+    enabled_.store(false, std::memory_order_relaxed);
44
+}
45
+
46
+SPDLOG_INLINE bool backtracer::enabled() const
47
+{
48
+    return enabled_.load(std::memory_order_relaxed);
49
+}
50
+
51
+SPDLOG_INLINE backtracer::operator bool() const
52
+{
53
+    return enabled();
54
+}
55
+
56
+SPDLOG_INLINE void backtracer::push_back(const log_msg &msg)
57
+{
58
+    std::lock_guard<std::mutex> lock{mutex_};
59
+    messages_.push_back(log_msg_buffer{msg});
60
+}
61
+
62
+// pop all items in the q and apply the given fun on each of them.
63
+SPDLOG_INLINE void backtracer::foreach_pop(std::function<void(const details::log_msg &)> fun)
64
+{
65
+    std::lock_guard<std::mutex> lock{mutex_};
66
+    while (!messages_.empty())
67
+    {
68
+        auto &front_msg = messages_.front();
69
+        fun(front_msg);
70
+        messages_.pop_front();
71
+    }
72
+}
73
+} // namespace details
74
+} // namespace spdlog

+ 46
- 0
incl/spdlog/details/backtracer.h View File

@@ -0,0 +1,46 @@
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
+#include "spdlog/details/log_msg_buffer.h"
7
+#include "spdlog/details/circular_q.h"
8
+
9
+#include <atomic>
10
+#include <mutex>
11
+#include <functional>
12
+
13
+// Store log messages in circular buffer.
14
+// Useful for storing debug data in case of error/warning happens.
15
+
16
+namespace spdlog {
17
+namespace details {
18
+class backtracer
19
+{
20
+    mutable std::mutex mutex_;
21
+    std::atomic<bool> enabled_{false};
22
+    circular_q<log_msg_buffer> messages_;
23
+
24
+public:
25
+    backtracer() = default;
26
+    backtracer(const backtracer &other);
27
+
28
+    backtracer(backtracer &&other) SPDLOG_NOEXCEPT;
29
+    backtracer &operator=(backtracer other);
30
+
31
+    void enable(size_t size);
32
+    void disable();
33
+    bool enabled() const;
34
+    explicit operator bool() const;
35
+    void push_back(const log_msg &msg);
36
+
37
+    // pop all items in the q and apply the given fun on each of them.
38
+    void foreach_pop(std::function<void(const details::log_msg &)> fun);
39
+};
40
+
41
+} // namespace details
42
+} // namespace spdlog
43
+
44
+#ifdef SPDLOG_HEADER_ONLY
45
+#include "backtracer-inl.h"
46
+#endif

+ 119
- 0
incl/spdlog/details/circular_q.h View File

@@ -0,0 +1,119 @@
1
+// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
2
+// Distributed under the MIT License (http://opensource.org/licenses/MIT)
3
+
4
+// cirucal q view of std::vector.
5
+#pragma once
6
+
7
+#include <vector>
8
+
9
+namespace spdlog {
10
+namespace details {
11
+template<typename T>
12
+class circular_q
13
+{
14
+    size_t max_items_ = 0;
15
+    typename std::vector<T>::size_type head_ = 0;
16
+    typename std::vector<T>::size_type tail_ = 0;
17
+    size_t overrun_counter_ = 0;
18
+    std::vector<T> v_;
19
+
20
+public:
21
+    using value_type = T;
22
+
23
+    // empty ctor - create a disabled queue with no elements allocated at all
24
+    circular_q() = default;
25
+
26
+    explicit circular_q(size_t max_items)
27
+        : max_items_(max_items + 1) // one item is reserved as marker for full q
28
+        , v_(max_items_)
29
+    {}
30
+
31
+    circular_q(const circular_q &) = default;
32
+    circular_q &operator=(const circular_q &) = default;
33
+
34
+    // move cannot be default,
35
+    // since we need to reset head_, tail_, etc to zero in the moved object
36
+    circular_q(circular_q &&other) SPDLOG_NOEXCEPT
37
+    {
38
+        copy_moveable(std::move(other));
39
+    }
40
+
41
+    circular_q &operator=(circular_q &&other) SPDLOG_NOEXCEPT
42
+    {
43
+        copy_moveable(std::move(other));
44
+        return *this;
45
+    }
46
+
47
+    // push back, overrun (oldest) item if no room left
48
+    void push_back(T &&item)
49
+    {
50
+        if (max_items_ > 0)
51
+        {
52
+            v_[tail_] = std::move(item);
53
+            tail_ = (tail_ + 1) % max_items_;
54
+
55
+            if (tail_ == head_) // overrun last item if full
56
+            {
57
+                head_ = (head_ + 1) % max_items_;
58
+                ++overrun_counter_;
59
+            }
60
+        }
61
+    }
62
+
63
+    // Return reference to the front item.
64
+    // If there are no elements in the container, the behavior is undefined.
65
+    const T &front() const
66
+    {
67
+        return v_[head_];
68
+    }
69
+
70
+    T &front()
71
+    {
72
+        return v_[head_];
73
+    }
74
+
75
+    // Pop item from front.
76
+    // If there are no elements in the container, the behavior is undefined.
77
+    void pop_front()
78
+    {
79
+        head_ = (head_ + 1) % max_items_;
80
+    }
81
+
82
+    bool empty() const
83
+    {
84
+        return tail_ == head_;
85
+    }
86
+
87
+    bool full() const
88
+    {
89
+        // head is ahead of the tail by 1
90
+        if (max_items_ > 0)
91
+        {
92
+            return ((tail_ + 1) % max_items_) == head_;
93
+        }
94
+        return false;
95
+    }
96
+
97
+    size_t overrun_counter() const
98
+    {
99
+        return overrun_counter_;
100
+    }
101
+
102
+private:
103
+    // copy from other&& and reset it to disabled state
104
+    void copy_moveable(circular_q &&other) SPDLOG_NOEXCEPT
105
+    {
106
+        max_items_ = other.max_items_;
107
+        head_ = other.head_;
108
+        tail_ = other.tail_;
109
+        overrun_counter_ = other.overrun_counter_;
110
+        v_ = std::move(other.v_);
111
+
112
+        // put &&other in disabled, but valid state
113
+        other.max_items_ = 0;
114
+        other.head_ = other.tail_ = 0;
115
+        other.overrun_counter_ = 0;
116
+    }
117
+};
118
+} // namespace details
119
+} // namespace spdlog

+ 32
- 0
incl/spdlog/details/console_globals.h View File

@@ -0,0 +1,32 @@
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
+#include "spdlog/details/null_mutex.h"
7
+#include <mutex>
8
+
9
+namespace spdlog {
10
+namespace details {
11
+
12
+struct console_mutex
13
+{
14
+    using mutex_t = std::mutex;
15
+    static mutex_t &mutex()
16
+    {
17
+        static mutex_t s_mutex;
18
+        return s_mutex;
19
+    }
20
+};
21
+
22
+struct console_nullmutex
23
+{
24
+    using mutex_t = null_mutex;
25
+    static mutex_t &mutex()
26
+    {
27
+        static mutex_t s_mutex;
28
+        return s_mutex;
29
+    }
30
+};
31
+} // namespace details
32
+} // namespace spdlog

+ 133
- 0
incl/spdlog/details/file_helper-inl.h View File

@@ -0,0 +1,133 @@
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
+#ifndef SPDLOG_HEADER_ONLY
7
+#include "spdlog/details/file_helper.h"
8
+#endif
9
+
10
+#include "spdlog/details/os.h"
11
+#include "spdlog/common.h"
12
+
13
+#include <cerrno>
14
+#include <chrono>
15
+#include <cstdio>
16
+#include <string>
17
+#include <thread>
18
+#include <tuple>
19
+
20
+namespace spdlog {
21
+namespace details {
22
+
23
+SPDLOG_INLINE file_helper::~file_helper()
24
+{
25
+    close();
26
+}
27
+
28
+SPDLOG_INLINE void file_helper::open(const filename_t &fname, bool truncate)
29
+{
30
+    close();
31
+    auto *mode = truncate ? SPDLOG_FILENAME_T("wb") : SPDLOG_FILENAME_T("ab");
32
+    _filename = fname;
33
+    for (int tries = 0; tries < open_tries; ++tries)
34
+    {
35
+        if (!os::fopen_s(&fd_, fname, mode))
36
+        {
37
+            return;
38
+        }
39
+
40
+        details::os::sleep_for_millis(open_interval);
41
+    }
42
+
43
+    SPDLOG_THROW(spdlog_ex("Failed opening file " + os::filename_to_str(_filename) + " for writing", errno));
44
+}
45
+
46
+SPDLOG_INLINE void file_helper::reopen(bool truncate)
47
+{
48
+    if (_filename.empty())
49
+    {
50
+        SPDLOG_THROW(spdlog_ex("Failed re opening file - was not opened before"));
51
+    }
52
+    open(_filename, truncate);
53
+}
54
+
55
+SPDLOG_INLINE void file_helper::flush()
56
+{
57
+    std::fflush(fd_);
58
+}
59
+
60
+SPDLOG_INLINE void file_helper::close()
61
+{
62
+    if (fd_ != nullptr)
63
+    {
64
+        std::fclose(fd_);
65
+        fd_ = nullptr;
66
+    }
67
+}
68
+
69
+SPDLOG_INLINE void file_helper::write(const memory_buf_t &buf)
70
+{
71
+    size_t msg_size = buf.size();
72
+    auto data = buf.data();
73
+    if (std::fwrite(data, 1, msg_size, fd_) != msg_size)
74
+    {
75
+        SPDLOG_THROW(spdlog_ex("Failed writing to file " + os::filename_to_str(_filename), errno));
76
+    }
77
+}
78
+
79
+SPDLOG_INLINE size_t file_helper::size() const
80
+{
81
+    if (fd_ == nullptr)
82
+    {
83
+        SPDLOG_THROW(spdlog_ex("Cannot use size() on closed file " + os::filename_to_str(_filename)));
84
+    }
85
+    return os::filesize(fd_);
86
+}
87
+
88
+SPDLOG_INLINE const filename_t &file_helper::filename() const
89
+{
90
+    return _filename;
91
+}
92
+
93
+SPDLOG_INLINE bool file_helper::file_exists(const filename_t &fname)
94
+{
95
+    return os::file_exists(fname);
96
+}
97
+
98
+//
99
+// return file path and its extension:
100
+//
101
+// "mylog.txt" => ("mylog", ".txt")
102
+// "mylog" => ("mylog", "")
103
+// "mylog." => ("mylog.", "")
104
+// "/dir1/dir2/mylog.txt" => ("/dir1/dir2/mylog", ".txt")
105
+//
106
+// the starting dot in filenames is ignored (hidden files):
107
+//
108
+// ".mylog" => (".mylog". "")
109
+// "my_folder/.mylog" => ("my_folder/.mylog", "")
110
+// "my_folder/.mylog.txt" => ("my_folder/.mylog", ".txt")
111
+SPDLOG_INLINE std::tuple<filename_t, filename_t> file_helper::split_by_extension(const filename_t &fname)
112
+{
113
+    auto ext_index = fname.rfind('.');
114
+
115
+    // no valid extension found - return whole path and empty string as
116
+    // extension
117
+    if (ext_index == filename_t::npos || ext_index == 0 || ext_index == fname.size() - 1)
118
+    {
119
+        return std::make_tuple(fname, filename_t());
120
+    }
121
+
122
+    // treat casese like "/etc/rc.d/somelogfile or "/abc/.hiddenfile"
123
+    auto folder_index = fname.rfind(details::os::folder_sep);
124
+    if (folder_index != filename_t::npos && folder_index >= ext_index - 1)
125
+    {
126
+        return std::make_tuple(fname, filename_t());
127
+    }
128
+
129
+    // finally - return a valid base and extension tuple
130
+    return std::make_tuple(fname.substr(0, ext_index), fname.substr(ext_index));
131
+}
132
+} // namespace details
133
+} // namespace spdlog

+ 60
- 0
incl/spdlog/details/file_helper.h View File

@@ -0,0 +1,60 @@
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
+#include "spdlog/common.h"
7
+#include <tuple>
8
+
9
+namespace spdlog {
10
+namespace details {
11
+
12
+// Helper class for file sinks.
13
+// When failing to open a file, retry several times(5) with a delay interval(10 ms).
14
+// Throw spdlog_ex exception on errors.
15
+
16
+class file_helper
17
+{
18
+public:
19
+    explicit file_helper() = default;
20
+
21
+    file_helper(const file_helper &) = delete;
22
+    file_helper &operator=(const file_helper &) = delete;
23
+    ~file_helper();
24
+
25
+    void open(const filename_t &fname, bool truncate = false);
26
+    void reopen(bool truncate);
27
+    void flush();
28
+    void close();
29
+    void write(const memory_buf_t &buf);
30
+    size_t size() const;
31
+    const filename_t &filename() const;
32
+    static bool file_exists(const filename_t &fname);
33
+
34
+    //
35
+    // return file path and its extension:
36
+    //
37
+    // "mylog.txt" => ("mylog", ".txt")
38
+    // "mylog" => ("mylog", "")
39
+    // "mylog." => ("mylog.", "")
40
+    // "/dir1/dir2/mylog.txt" => ("/dir1/dir2/mylog", ".txt")
41
+    //
42
+    // the starting dot in filenames is ignored (hidden files):
43
+    //
44
+    // ".mylog" => (".mylog". "")
45
+    // "my_folder/.mylog" => ("my_folder/.mylog", "")
46
+    // "my_folder/.mylog.txt" => ("my_folder/.mylog", ".txt")
47
+    static std::tuple<filename_t, filename_t> split_by_extension(const filename_t &fname);
48
+
49
+private:
50
+    const int open_tries = 5;
51
+    const int open_interval = 10;
52
+    std::FILE *fd_{nullptr};
53
+    filename_t _filename;
54
+};
55
+} // namespace details
56
+} // namespace spdlog
57
+
58
+#ifdef SPDLOG_HEADER_ONLY
59
+#include "file_helper-inl.h"
60
+#endif

+ 111
- 0
incl/spdlog/details/fmt_helper.h View File

@@ -0,0 +1,111 @@
1
+// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
2
+// Distributed under the MIT License (http://opensource.org/licenses/MIT)
3
+#pragma once
4
+
5
+#include <chrono>
6
+#include <type_traits>
7
+#include "spdlog/fmt/fmt.h"
8
+#include "spdlog/common.h"
9
+
10
+// Some fmt helpers to efficiently format and pad ints and strings
11
+namespace spdlog {
12
+namespace details {
13
+namespace fmt_helper {
14
+
15
+inline spdlog::string_view_t to_string_view(const memory_buf_t &buf) SPDLOG_NOEXCEPT
16
+{
17
+    return spdlog::string_view_t{buf.data(), buf.size()};
18
+}
19
+
20
+inline void append_string_view(spdlog::string_view_t view, memory_buf_t &dest)
21
+{
22
+    auto *buf_ptr = view.data();
23
+    if (buf_ptr != nullptr)
24
+    {
25
+        dest.append(buf_ptr, buf_ptr + view.size());
26
+    }
27
+}
28
+
29
+template<typename T>
30
+inline void append_int(T n, memory_buf_t &dest)
31
+{
32
+    fmt::format_int i(n);
33
+    dest.append(i.data(), i.data() + i.size());
34
+}
35
+
36
+template<typename T>
37
+inline unsigned count_digits(T n)
38
+{
39
+    using count_type = typename std::conditional<(sizeof(T) > sizeof(uint32_t)), uint64_t, uint32_t>::type;
40
+    return static_cast<unsigned>(fmt::internal::count_digits(static_cast<count_type>(n)));
41
+}
42
+
43
+inline void pad2(int n, memory_buf_t &dest)
44
+{
45
+    if (n > 99)
46
+    {
47
+        append_int(n, dest);
48
+    }
49
+    else if (n > 9) // 10-99
50
+    {
51
+        dest.push_back(static_cast<char>('0' + n / 10));
52
+        dest.push_back(static_cast<char>('0' + n % 10));
53
+    }
54
+    else if (n >= 0) // 0-9
55
+    {
56
+        dest.push_back('0');
57
+        dest.push_back(static_cast<char>('0' + n));
58
+    }
59
+    else // negatives (unlikely, but just in case, let fmt deal with it)
60
+    {
61
+        fmt::format_to(dest, "{:02}", n);
62
+    }
63
+}
64
+
65
+template<typename T>
66
+inline void pad_uint(T n, unsigned int width, memory_buf_t &dest)
67
+{
68
+    static_assert(std::is_unsigned<T>::value, "pad_uint must get unsigned T");
69
+    auto digits = count_digits(n);
70
+    if (width > digits)
71
+    {
72
+        const char *zeroes = "0000000000000000000";
73
+        dest.append(zeroes, zeroes + width - digits);
74
+    }
75
+    append_int(n, dest);
76
+}
77
+
78
+template<typename T>
79
+inline void pad3(T n, memory_buf_t &dest)
80
+{
81
+    pad_uint(n, 3, dest);
82
+}
83
+
84
+template<typename T>
85
+inline void pad6(T n, memory_buf_t &dest)
86
+{
87
+    pad_uint(n, 6, dest);
88
+}
89
+
90
+template<typename T>
91
+inline void pad9(T n, memory_buf_t &dest)
92
+{
93
+    pad_uint(n, 9, dest);
94
+}
95
+
96
+// return fraction of a second of the given time_point.
97
+// e.g.
98
+// fraction<std::milliseconds>(tp) -> will return the millis part of the second
99
+template<typename ToDuration>
100
+inline ToDuration time_fraction(log_clock::time_point tp)
101
+{
102
+    using std::chrono::duration_cast;
103
+    using std::chrono::seconds;
104
+    auto duration = tp.time_since_epoch();
105
+    auto secs = duration_cast<seconds>(duration);
106
+    return duration_cast<ToDuration>(duration) - duration_cast<ToDuration>(secs);
107
+}
108
+
109
+} // namespace fmt_helper
110
+} // namespace details
111
+} // namespace spdlog

+ 34
- 0
incl/spdlog/details/log_msg-inl.h View File

@@ -0,0 +1,34 @@
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
+#ifndef SPDLOG_HEADER_ONLY
7
+#include "spdlog/details/log_msg.h"
8
+#endif
9
+
10
+#include "spdlog/details/os.h"
11
+
12
+namespace spdlog {
13
+namespace details {
14
+
15
+SPDLOG_INLINE log_msg::log_msg(spdlog::source_loc loc, string_view_t logger_name, spdlog::level::level_enum lvl, spdlog::string_view_t msg)
16
+    : logger_name(logger_name)
17
+    , level(lvl)
18
+#ifndef SPDLOG_NO_DATETIME
19
+    , time(os::now())
20
+#endif
21
+
22
+#ifndef SPDLOG_NO_THREAD_ID
23
+    , thread_id(os::thread_id())
24
+#endif
25
+    , source(loc)
26
+    , payload(msg)
27
+{}
28
+
29
+SPDLOG_INLINE log_msg::log_msg(string_view_t logger_name, spdlog::level::level_enum lvl, spdlog::string_view_t msg)
30
+    : log_msg(source_loc{}, logger_name, lvl, msg)
31
+{}
32
+
33
+} // namespace details
34
+} // namespace spdlog

+ 35
- 0
incl/spdlog/details/log_msg.h View File

@@ -0,0 +1,35 @@
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
+#include "spdlog/common.h"
7
+#include <string>
8
+
9
+namespace spdlog {
10
+namespace details {
11
+struct log_msg
12
+{
13
+    log_msg() = default;
14
+    log_msg(source_loc loc, string_view_t logger_name, level::level_enum lvl, string_view_t msg);
15
+    log_msg(string_view_t logger_name, level::level_enum lvl, string_view_t msg);
16
+    log_msg(const log_msg &other) = default;
17
+
18
+    string_view_t logger_name;
19
+    level::level_enum level{level::off};
20
+    log_clock::time_point time;
21
+    size_t thread_id{0};
22
+
23
+    // wrapping the formatted text with color (updated by pattern_formatter).
24
+    mutable size_t color_range_start{0};
25
+    mutable size_t color_range_end{0};
26
+
27
+    source_loc source;
28
+    string_view_t payload;
29
+};
30
+} // namespace details
31
+} // namespace spdlog
32
+
33
+#ifdef SPDLOG_HEADER_ONLY
34
+#include "log_msg-inl.h"
35
+#endif

+ 60
- 0
incl/spdlog/details/log_msg_buffer-inl.h View File

@@ -0,0 +1,60 @@
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
+#ifndef SPDLOG_HEADER_ONLY
7
+#include "spdlog/details/log_msg_buffer.h"
8
+#endif
9
+
10
+namespace spdlog {
11
+namespace details {
12
+
13
+SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg &orig_msg)
14
+    : log_msg{orig_msg}
15
+{
16
+    buffer.append(logger_name.begin(), logger_name.end());
17
+    buffer.append(payload.begin(), payload.end());
18
+    update_string_views();
19
+}
20
+
21
+SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg_buffer &other)
22
+    : log_msg{other}
23
+{
24
+    buffer.append(logger_name.begin(), logger_name.end());
25
+    buffer.append(payload.begin(), payload.end());
26
+    update_string_views();
27
+}
28
+
29
+SPDLOG_INLINE log_msg_buffer::log_msg_buffer(log_msg_buffer &&other)
30
+    : log_msg{std::move(other)}
31
+    , buffer{std::move(other.buffer)}
32
+{
33
+    update_string_views();
34
+}
35
+
36
+SPDLOG_INLINE log_msg_buffer &log_msg_buffer::operator=(const log_msg_buffer &other)
37
+{
38
+    log_msg::operator=(other);
39
+    buffer.clear();
40
+    buffer.append(other.buffer.data(), other.buffer.data() + other.buffer.size());
41
+    update_string_views();
42
+    return *this;
43
+}
44
+
45
+SPDLOG_INLINE log_msg_buffer &log_msg_buffer::operator=(log_msg_buffer &&other)
46
+{
47
+    log_msg::operator=(std::move(other));
48
+    buffer = std::move(other.buffer);
49
+    update_string_views();
50
+    return *this;
51
+}
52
+
53
+SPDLOG_INLINE void log_msg_buffer::update_string_views()
54
+{
55
+    logger_name = string_view_t{buffer.data(), logger_name.size()};
56
+    payload = string_view_t{buffer.data() + logger_name.size(), payload.size()};
57
+}
58
+
59
+} // namespace details
60
+} // namespace spdlog

+ 33
- 0
incl/spdlog/details/log_msg_buffer.h View File

@@ -0,0 +1,33 @@
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
+#include "spdlog/details/log_msg.h"
7
+
8
+namespace spdlog {
9
+namespace details {
10
+
11
+// Extend log_msg with internal buffer to store its payload.
12
+// THis is needed since log_msg holds string_views that points to stack data.
13
+
14
+class log_msg_buffer : public log_msg
15
+{
16
+    memory_buf_t buffer;
17
+    void update_string_views();
18
+
19
+public:
20
+    log_msg_buffer() = default;
21
+    explicit log_msg_buffer(const log_msg &orig_msg);
22
+    log_msg_buffer(const log_msg_buffer &other);
23
+    log_msg_buffer(log_msg_buffer &&other);
24
+    log_msg_buffer &operator=(const log_msg_buffer &other);
25
+    log_msg_buffer &operator=(log_msg_buffer &&other);
26
+};
27
+
28
+} // namespace details
29
+} // namespace spdlog
30
+
31
+#ifdef SPDLOG_HEADER_ONLY
32
+#include "log_msg_buffer-inl.h"
33
+#endif

+ 120
- 0
incl/spdlog/details/mpmc_blocking_q.h View File

@@ -0,0 +1,120 @@
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
+// multi producer-multi consumer blocking queue.
7
+// enqueue(..) - will block until room found to put the new message.
8
+// enqueue_nowait(..) - will return immediately with false if no room left in
9
+// the queue.
10
+// dequeue_for(..) - will block until the queue is not empty or timeout have
11
+// passed.
12
+
13
+#include "spdlog/details/circular_q.h"
14
+
15
+#include <condition_variable>
16
+#include <mutex>
17
+
18
+namespace spdlog {
19
+namespace details {
20
+
21
+template<typename T>
22
+class mpmc_blocking_queue
23
+{
24
+public:
25
+    using item_type = T;
26
+    explicit mpmc_blocking_queue(size_t max_items)
27
+        : q_(max_items)
28
+    {}
29
+
30
+#ifndef __MINGW32__
31
+    // try to enqueue and block if no room left
32
+    void enqueue(T &&item)
33
+    {
34
+        {
35
+            std::unique_lock<std::mutex> lock(queue_mutex_);
36
+            pop_cv_.wait(lock, [this] { return !this->q_.full(); });
37
+            q_.push_back(std::move(item));
38
+        }
39
+        push_cv_.notify_one();
40
+    }
41
+
42
+    // enqueue immediately. overrun oldest message in the queue if no room left.
43
+    void enqueue_nowait(T &&item)
44
+    {
45
+        {
46
+            std::unique_lock<std::mutex> lock(queue_mutex_);
47
+            q_.push_back(std::move(item));
48
+        }
49
+        push_cv_.notify_one();
50
+    }
51
+
52
+    // try to dequeue item. if no item found. wait upto timeout and try again
53
+    // Return true, if succeeded dequeue item, false otherwise
54
+    bool dequeue_for(T &popped_item, std::chrono::milliseconds wait_duration)
55
+    {
56
+        {
57
+            std::unique_lock<std::mutex> lock(queue_mutex_);
58
+            if (!push_cv_.wait_for(lock, wait_duration, [this] { return !this->q_.empty(); }))
59
+            {
60
+                return false;
61
+            }
62
+            popped_item = std::move(q_.front());
63
+            q_.pop_front();
64
+        }
65
+        pop_cv_.notify_one();
66
+        return true;
67
+    }
68
+
69
+#else
70
+    // apparently mingw deadlocks if the mutex is released before cv.notify_one(),
71
+    // so release the mutex at the very end each function.
72
+
73
+    // try to enqueue and block if no room left
74
+    void enqueue(T &&item)
75
+    {
76
+        std::unique_lock<std::mutex> lock(queue_mutex_);
77
+        pop_cv_.wait(lock, [this] { return !this->q_.full(); });
78
+        q_.push_back(std::move(item));
79
+        push_cv_.notify_one();
80
+    }
81
+
82
+    // enqueue immediately. overrun oldest message in the queue if no room left.
83
+    void enqueue_nowait(T &&item)
84
+    {
85
+        std::unique_lock<std::mutex> lock(queue_mutex_);
86
+        q_.push_back(std::move(item));
87
+        push_cv_.notify_one();
88
+    }
89
+
90
+    // try to dequeue item. if no item found. wait upto timeout and try again
91
+    // Return true, if succeeded dequeue item, false otherwise
92
+    bool dequeue_for(T &popped_item, std::chrono::milliseconds wait_duration)
93
+    {
94
+        std::unique_lock<std::mutex> lock(queue_mutex_);
95
+        if (!push_cv_.wait_for(lock, wait_duration, [this] { return !this->q_.empty(); }))
96
+        {
97
+            return false;
98
+        }
99
+        popped_item = std::move(q_.front());
100
+        q_.pop_front();
101
+        pop_cv_.notify_one();
102
+        return true;
103
+    }
104
+
105
+#endif
106
+
107
+    size_t overrun_counter()
108
+    {
109
+        std::unique_lock<std::mutex> lock(queue_mutex_);
110
+        return q_.overrun_counter();
111
+    }
112
+
113
+private:
114
+    std::mutex queue_mutex_;
115
+    std::condition_variable push_cv_;
116
+    std::condition_variable pop_cv_;
117
+    spdlog::details::circular_q<T> q_;
118
+};
119
+} // namespace details
120
+} // namespace spdlog

+ 49
- 0
incl/spdlog/details/null_mutex.h View File

@@ -0,0 +1,49 @@
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
+#include <atomic>
7
+#include <utility>
8
+// null, no cost dummy "mutex" and dummy "atomic" int
9
+
10
+namespace spdlog {
11
+namespace details {
12
+struct null_mutex
13
+{
14
+    void lock() const {}
15
+    void unlock() const {}
16
+    bool try_lock() const
17
+    {
18
+        return true;
19
+    }
20
+};
21
+
22
+struct null_atomic_int
23
+{
24
+    int value;
25
+    null_atomic_int() = default;
26
+
27
+    explicit null_atomic_int(int new_value)
28
+        : value(new_value)
29
+    {}
30
+
31
+    int load(std::memory_order = std::memory_order_relaxed) const
32
+    {
33
+        return value;
34
+    }
35
+
36
+    void store(int new_value, std::memory_order = std::memory_order_relaxed)
37
+    {
38
+        value = new_value;
39
+    }
40
+
41
+    int exchange(int new_value, std::memory_order = std::memory_order_relaxed)
42
+    {
43
+        std::swap(new_value, value);
44
+        return new_value; // return value before the call
45
+    }
46
+};
47
+
48
+} // namespace details
49
+} // namespace spdlog

+ 465
- 0
incl/spdlog/details/os-inl.h View File

@@ -0,0 +1,465 @@
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
+#ifndef SPDLOG_HEADER_ONLY
7
+#include "spdlog/details/os.h"
8
+#endif
9
+
10
+#include "spdlog/common.h"
11
+
12
+#include <algorithm>
13
+#include <chrono>
14
+#include <cstdio>
15
+#include <cstdlib>
16
+#include <cstring>
17
+#include <ctime>
18
+#include <string>
19
+#include <thread>
20
+#include <array>
21
+#include <sys/stat.h>
22
+#include <sys/types.h>
23
+
24
+#ifdef _WIN32
25
+
26
+#ifndef NOMINMAX
27
+#define NOMINMAX // prevent windows redefining min/max
28
+#endif
29
+
30
+#ifndef WIN32_LEAN_AND_MEAN
31
+#define WIN32_LEAN_AND_MEAN
32
+#endif
33
+#include <io.h>      // _get_osfhandle and _isatty support
34
+#include <process.h> //  _get_pid support
35
+#include <windows.h>
36
+
37
+#ifdef __MINGW32__
38
+#include <share.h>
39
+#endif
40
+
41
+#if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)
42
+#include <limits>
43
+#endif
44
+
45
+#else // unix
46
+
47
+#include <fcntl.h>
48
+#include <unistd.h>
49
+
50
+#ifdef __linux__
51
+#include <sys/syscall.h> //Use gettid() syscall under linux to get thread id
52
+
53
+#elif defined(_AIX)
54
+#include <pthread.h> // for pthread_getthreadid_np
55
+
56
+#elif defined(__DragonFly__) || defined(__FreeBSD__)
57
+#include <pthread_np.h> // for pthread_getthreadid_np
58
+
59
+#elif defined(__NetBSD__)
60
+#include <lwp.h> // for _lwp_self
61
+
62
+#elif defined(__sun)
63
+#include <thread.h> // for thr_self
64
+#endif
65
+
66
+#endif // unix
67
+
68
+#ifndef __has_feature      // Clang - feature checking macros.
69
+#define __has_feature(x) 0 // Compatibility with non-clang compilers.
70
+#endif
71
+
72
+namespace spdlog {
73
+namespace details {
74
+namespace os {
75
+
76
+SPDLOG_INLINE spdlog::log_clock::time_point now() SPDLOG_NOEXCEPT
77
+{
78
+
79
+#if defined __linux__ && defined SPDLOG_CLOCK_COARSE
80
+    timespec ts;
81
+    ::clock_gettime(CLOCK_REALTIME_COARSE, &ts);
82
+    return std::chrono::time_point<log_clock, typename log_clock::duration>(
83
+        std::chrono::duration_cast<typename log_clock::duration>(std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec)));
84
+
85
+#else
86
+    return log_clock::now();
87
+#endif
88
+}
89
+SPDLOG_INLINE std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT
90
+{
91
+
92
+#ifdef _WIN32
93
+    std::tm tm;
94
+    localtime_s(&tm, &time_tt);
95
+#else
96
+    std::tm tm;
97
+    localtime_r(&time_tt, &tm);
98
+#endif
99
+    return tm;
100
+}
101
+
102
+SPDLOG_INLINE std::tm localtime() SPDLOG_NOEXCEPT
103
+{
104
+    std::time_t now_t = time(nullptr);
105
+    return localtime(now_t);
106
+}
107
+
108
+SPDLOG_INLINE std::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT
109
+{
110
+
111
+#ifdef _WIN32
112
+    std::tm tm;
113
+    gmtime_s(&tm, &time_tt);
114
+#else
115
+    std::tm tm;
116
+    gmtime_r(&time_tt, &tm);
117
+#endif
118
+    return tm;
119
+}
120
+
121
+SPDLOG_INLINE std::tm gmtime() SPDLOG_NOEXCEPT
122
+{
123
+    std::time_t now_t = time(nullptr);
124
+    return gmtime(now_t);
125
+}
126
+
127
+SPDLOG_INLINE void prevent_child_fd(FILE *f)
128
+{
129
+
130
+#ifdef _WIN32
131
+#if !defined(__cplusplus_winrt)
132
+    auto file_handle = reinterpret_cast<HANDLE>(_get_osfhandle(_fileno(f)));
133
+    if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0))
134
+        SPDLOG_THROW(spdlog_ex("SetHandleInformation failed", errno));
135
+#endif
136
+#else
137
+    auto fd = fileno(f);
138
+    if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
139
+    {
140
+        SPDLOG_THROW(spdlog_ex("fcntl with FD_CLOEXEC failed", errno));
141
+    }
142
+#endif
143
+}
144
+
145
+// fopen_s on non windows for writing
146
+SPDLOG_INLINE bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode)
147
+{
148
+#ifdef _WIN32
149
+#ifdef SPDLOG_WCHAR_FILENAMES
150
+    *fp = _wfsopen((filename.c_str()), mode.c_str(), _SH_DENYNO);
151
+#else
152
+    *fp = _fsopen((filename.c_str()), mode.c_str(), _SH_DENYNO);
153
+#endif
154
+#else // unix
155
+    *fp = fopen((filename.c_str()), mode.c_str());
156
+#endif
157
+
158
+#ifdef SPDLOG_PREVENT_CHILD_FD
159
+    if (*fp != nullptr)
160
+    {
161
+        prevent_child_fd(*fp);
162
+    }
163
+#endif
164
+    return *fp == nullptr;
165
+}
166
+
167
+SPDLOG_INLINE int remove(const filename_t &filename) SPDLOG_NOEXCEPT
168
+{
169
+#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
170
+    return _wremove(filename.c_str());
171
+#else
172
+    return std::remove(filename.c_str());
173
+#endif
174
+}
175
+
176
+SPDLOG_INLINE int remove_if_exists(const filename_t &filename) SPDLOG_NOEXCEPT
177
+{
178
+    return file_exists(filename) ? remove(filename) : 0;
179
+}
180
+
181
+SPDLOG_INLINE int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT
182
+{
183
+#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
184
+    return _wrename(filename1.c_str(), filename2.c_str());
185
+#else
186
+    return std::rename(filename1.c_str(), filename2.c_str());
187
+#endif
188
+}
189
+
190
+// Return true if file exists
191
+SPDLOG_INLINE bool file_exists(const filename_t &filename) SPDLOG_NOEXCEPT
192
+{
193
+#ifdef _WIN32
194
+#ifdef SPDLOG_WCHAR_FILENAMES
195
+    auto attribs = GetFileAttributesW(filename.c_str());
196
+#else
197
+    auto attribs = GetFileAttributesA(filename.c_str());
198
+#endif
199
+    return (attribs != INVALID_FILE_ATTRIBUTES && !(attribs & FILE_ATTRIBUTE_DIRECTORY));
200
+#else // common linux/unix all have the stat system call
201
+    struct stat buffer;
202
+    return (::stat(filename.c_str(), &buffer) == 0);
203
+#endif
204
+}
205
+
206
+// Return file size according to open FILE* object
207
+SPDLOG_INLINE size_t filesize(FILE *f)
208
+{
209
+    if (f == nullptr)
210
+    {
211
+        SPDLOG_THROW(spdlog_ex("Failed getting file size. fd is null"));
212
+    }
213
+#if defined(_WIN32) && !defined(__CYGWIN__)
214
+    int fd = _fileno(f);
215
+#if _WIN64 // 64 bits
216
+    __int64 ret = _filelengthi64(fd);
217
+    if (ret >= 0)
218
+    {
219
+        return static_cast<size_t>(ret);
220
+    }
221
+
222
+#else // windows 32 bits
223
+    long ret = _filelength(fd);
224
+    if (ret >= 0)
225
+    {
226
+        return static_cast<size_t>(ret);
227
+    }
228
+#endif
229
+
230
+#else // unix
231
+    int fd = fileno(f);
232
+// 64 bits(but not in osx or cygwin, where fstat64 is deprecated)
233
+#if (defined(__linux__) || defined(__sun) || defined(_AIX)) && (defined(__LP64__) || defined(_LP64))
234
+    struct stat64 st;
235
+    if (::fstat64(fd, &st) == 0)
236
+    {
237
+        return static_cast<size_t>(st.st_size);
238
+    }
239
+#else // unix 32 bits or cygwin
240
+    struct stat st;
241
+
242
+    if (::fstat(fd, &st) == 0)
243
+    {
244
+        return static_cast<size_t>(st.st_size);
245
+    }
246
+#endif
247
+#endif
248
+    SPDLOG_THROW(spdlog_ex("Failed getting file size from fd", errno));
249
+}
250
+
251
+// Return utc offset in minutes or throw spdlog_ex on failure
252
+SPDLOG_INLINE int utc_minutes_offset(const std::tm &tm)
253
+{
254
+
255
+#ifdef _WIN32
256
+#if _WIN32_WINNT < _WIN32_WINNT_WS08
257
+    TIME_ZONE_INFORMATION tzinfo;
258
+    auto rv = GetTimeZoneInformation(&tzinfo);
259
+#else
260
+    DYNAMIC_TIME_ZONE_INFORMATION tzinfo;
261
+    auto rv = GetDynamicTimeZoneInformation(&tzinfo);
262
+#endif
263
+    if (rv == TIME_ZONE_ID_INVALID)
264
+        SPDLOG_THROW(spdlog::spdlog_ex("Failed getting timezone info. ", errno));
265
+
266
+    int offset = -tzinfo.Bias;
267
+    if (tm.tm_isdst)
268
+    {
269
+        offset -= tzinfo.DaylightBias;
270
+    }
271
+    else
272
+    {
273
+        offset -= tzinfo.StandardBias;
274
+    }
275
+    return offset;
276
+#else
277
+
278
+#if defined(sun) || defined(__sun) || defined(_AIX)
279
+    // 'tm_gmtoff' field is BSD extension and it's missing on SunOS/Solaris
280
+    struct helper
281
+    {
282
+        static long int calculate_gmt_offset(const std::tm &localtm = details::os::localtime(), const std::tm &gmtm = details::os::gmtime())
283
+        {
284
+            int local_year = localtm.tm_year + (1900 - 1);
285
+            int gmt_year = gmtm.tm_year + (1900 - 1);
286
+
287
+            long int days = (
288
+                // difference in day of year
289
+                localtm.tm_yday -
290
+                gmtm.tm_yday
291
+
292
+                // + intervening leap days
293
+                + ((local_year >> 2) - (gmt_year >> 2)) - (local_year / 100 - gmt_year / 100) +
294
+                ((local_year / 100 >> 2) - (gmt_year / 100 >> 2))
295
+
296
+                // + difference in years * 365 */
297
+                + (long int)(local_year - gmt_year) * 365);
298
+
299
+            long int hours = (24 * days) + (localtm.tm_hour - gmtm.tm_hour);
300
+            long int mins = (60 * hours) + (localtm.tm_min - gmtm.tm_min);
301
+            long int secs = (60 * mins) + (localtm.tm_sec - gmtm.tm_sec);
302
+
303
+            return secs;
304
+        }
305
+    };
306
+
307
+    auto offset_seconds = helper::calculate_gmt_offset(tm);
308
+#else
309
+    auto offset_seconds = tm.tm_gmtoff;
310
+#endif
311
+
312
+    return static_cast<int>(offset_seconds / 60);
313
+#endif
314
+}
315
+
316
+// Return current thread id as size_t
317
+// It exists because the std::this_thread::get_id() is much slower(especially
318
+// under VS 2013)
319
+SPDLOG_INLINE size_t _thread_id() SPDLOG_NOEXCEPT
320
+{
321
+#ifdef _WIN32
322
+    return static_cast<size_t>(::GetCurrentThreadId());
323
+#elif defined(__linux__)
324
+#if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21)
325
+#define SYS_gettid __NR_gettid
326
+#endif
327
+    return static_cast<size_t>(syscall(SYS_gettid));
328
+#elif defined(_AIX) || defined(__DragonFly__) || defined(__FreeBSD__)
329
+    return static_cast<size_t>(pthread_getthreadid_np());
330
+#elif defined(__NetBSD__)
331
+    return static_cast<size_t>(_lwp_self());
332
+#elif defined(__OpenBSD__)
333
+    return static_cast<size_t>(getthrid());
334
+#elif defined(__sun)
335
+    return static_cast<size_t>(thr_self());
336
+#elif __APPLE__
337
+    uint64_t tid;
338
+    pthread_threadid_np(nullptr, &tid);
339
+    return static_cast<size_t>(tid);
340
+#else // Default to standard C++11 (other Unix)
341
+    return static_cast<size_t>(std::hash<std::thread::id>()(std::this_thread::get_id()));
342
+#endif
343
+}
344
+
345
+// Return current thread id as size_t (from thread local storage)
346
+SPDLOG_INLINE size_t thread_id() SPDLOG_NOEXCEPT
347
+{
348
+#if defined(SPDLOG_NO_TLS)
349
+    return _thread_id();
350
+#else // cache thread id in tls
351
+    static thread_local const size_t tid = _thread_id();
352
+    return tid;
353
+#endif
354
+}
355
+
356
+// This is avoid msvc issue in sleep_for that happens if the clock changes.
357
+// See https://github.com/gabime/spdlog/issues/609
358
+SPDLOG_INLINE void sleep_for_millis(int milliseconds) SPDLOG_NOEXCEPT
359
+{
360
+#if defined(_WIN32)
361
+    ::Sleep(milliseconds);
362
+#else
363
+    std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
364
+#endif
365
+}
366
+
367
+// wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined)
368
+#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
369
+SPDLOG_INLINE std::string filename_to_str(const filename_t &filename)
370
+{
371
+    memory_buf_t buf;
372
+    wstr_to_utf8buf(filename, buf);
373
+    return fmt::to_string(buf);
374
+}
375
+#else
376
+SPDLOG_INLINE std::string filename_to_str(const filename_t &filename)
377
+{
378
+    return filename;
379
+}
380
+#endif
381
+
382
+SPDLOG_INLINE int pid() SPDLOG_NOEXCEPT
383
+{
384
+
385
+#ifdef _WIN32
386
+    return static_cast<int>(::GetCurrentProcessId());
387
+#else
388
+    return static_cast<int>(::getpid());
389
+#endif
390
+}
391
+
392
+// Determine if the terminal supports colors
393
+// Source: https://github.com/agauniyal/rang/
394
+SPDLOG_INLINE bool is_color_terminal() SPDLOG_NOEXCEPT
395
+{
396
+#ifdef _WIN32
397
+    return true;
398
+#else
399
+    static constexpr std::array<const char *, 14> Terms = {
400
+        {"ansi", "color", "console", "cygwin", "gnome", "konsole", "kterm", "linux", "msys", "putty", "rxvt", "screen", "vt100", "xterm"}};
401
+
402
+    const char *env_p = std::getenv("TERM");
403
+    if (env_p == nullptr)
404
+    {
405
+        return false;
406
+    }
407
+
408
+    static const bool result =
409
+        std::any_of(std::begin(Terms), std::end(Terms), [&](const char *term) { return std::strstr(env_p, term) != nullptr; });
410
+    return result;
411
+#endif
412
+}
413
+
414
+// Detrmine if the terminal attached
415
+// Source: https://github.com/agauniyal/rang/
416
+SPDLOG_INLINE bool in_terminal(FILE *file) SPDLOG_NOEXCEPT
417
+{
418
+
419
+#ifdef _WIN32
420
+    return _isatty(_fileno(file)) != 0;
421
+#else
422
+    return isatty(fileno(file)) != 0;
423
+#endif
424
+}
425
+
426
+#if (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32)
427
+SPDLOG_INLINE void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target)
428
+{
429
+    if (wstr.size() > static_cast<size_t>(std::numeric_limits<int>::max()))
430
+    {
431
+        SPDLOG_THROW(spdlog::spdlog_ex("UTF-16 string is too big to be converted to UTF-8"));
432
+    }
433
+
434
+    int wstr_size = static_cast<int>(wstr.size());
435
+    if (wstr_size == 0)
436
+    {
437
+        target.resize(0);
438
+        return;
439
+    }
440
+
441
+    int result_size = static_cast<int>(target.capacity());
442
+    if ((wstr_size + 1) * 2 > result_size)
443
+    {
444
+        result_size = ::WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr_size, NULL, 0, NULL, NULL);
445
+    }
446
+
447
+    if (result_size > 0)
448
+    {
449
+        target.resize(result_size);
450
+        result_size = ::WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr_size, target.data(), result_size, NULL, NULL);
451
+
452
+        if (result_size > 0)
453
+        {
454
+            target.resize(result_size);
455
+            return;
456
+        }
457
+    }
458
+
459
+    SPDLOG_THROW(spdlog::spdlog_ex(fmt::format("WideCharToMultiByte failed. Last error: {}", ::GetLastError())));
460
+}
461
+#endif // (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32)
462
+
463
+} // namespace os
464
+} // namespace details
465
+} // namespace spdlog

+ 98
- 0
incl/spdlog/details/os.h View File

@@ -0,0 +1,98 @@
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
+#include "spdlog/common.h"
7
+#include <ctime> // std::time_t
8
+
9
+namespace spdlog {
10
+namespace details {
11
+namespace os {
12
+
13
+spdlog::log_clock::time_point now() SPDLOG_NOEXCEPT;
14
+
15
+std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT;
16
+
17
+std::tm localtime() SPDLOG_NOEXCEPT;
18
+
19
+std::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT;
20
+
21
+std::tm gmtime() SPDLOG_NOEXCEPT;
22
+
23
+// eol definition
24
+#if !defined(SPDLOG_EOL)
25
+#ifdef _WIN32
26
+#define SPDLOG_EOL "\r\n"
27
+#else
28
+#define SPDLOG_EOL "\n"
29
+#endif
30
+#endif
31
+
32
+SPDLOG_CONSTEXPR static const char *default_eol = SPDLOG_EOL;
33
+
34
+// folder separator
35
+#ifdef _WIN32
36
+const char folder_sep = '\\';
37
+#else
38
+SPDLOG_CONSTEXPR static const char folder_sep = '/';
39
+#endif
40
+
41
+void prevent_child_fd(FILE *f);
42
+
43
+// fopen_s on non windows for writing
44
+bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode);
45
+
46
+// Remove filename. return 0 on success
47
+int remove(const filename_t &filename) SPDLOG_NOEXCEPT;
48
+
49
+// Remove file if exists. return 0 on success
50
+// Note: Non atomic (might return failure to delete if concurrently deleted by other process/thread)
51
+int remove_if_exists(const filename_t &filename) SPDLOG_NOEXCEPT;
52
+
53
+int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT;
54
+
55
+// Return if file exists.
56
+bool file_exists(const filename_t &filename) SPDLOG_NOEXCEPT;
57
+
58
+// Return file size according to open FILE* object
59
+size_t filesize(FILE *f);
60
+
61
+// Return utc offset in minutes or throw spdlog_ex on failure
62
+int utc_minutes_offset(const std::tm &tm = details::os::localtime());
63
+
64
+// Return current thread id as size_t
65
+// It exists because the std::this_thread::get_id() is much slower(especially
66
+// under VS 2013)
67
+size_t _thread_id() SPDLOG_NOEXCEPT;
68
+
69
+// Return current thread id as size_t (from thread local storage)
70
+size_t thread_id() SPDLOG_NOEXCEPT;
71
+
72
+// This is avoid msvc issue in sleep_for that happens if the clock changes.
73
+// See https://github.com/gabime/spdlog/issues/609
74
+void sleep_for_millis(int milliseconds) SPDLOG_NOEXCEPT;
75
+
76
+std::string filename_to_str(const filename_t &filename);
77
+
78
+int pid() SPDLOG_NOEXCEPT;
79
+
80
+// Determine if the terminal supports colors
81
+// Source: https://github.com/agauniyal/rang/
82
+bool is_color_terminal() SPDLOG_NOEXCEPT;
83
+
84
+// Detrmine if the terminal attached
85
+// Source: https://github.com/agauniyal/rang/
86
+bool in_terminal(FILE *file) SPDLOG_NOEXCEPT;
87
+
88
+#if (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32)
89
+void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target);
90
+#endif
91
+
92
+} // namespace os
93
+} // namespace details
94
+} // namespace spdlog
95
+
96
+#ifdef SPDLOG_HEADER_ONLY
97
+#include "os-inl.h"
98
+#endif

+ 1317
- 0
incl/spdlog/details/pattern_formatter-inl.h
File diff suppressed because it is too large
View File


+ 99
- 0
incl/spdlog/details/pattern_formatter.h View File

@@ -0,0 +1,99 @@
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
+#include "spdlog/common.h"
7
+#include "spdlog/details/log_msg.h"
8
+#include "spdlog/details/os.h"
9
+#include "spdlog/formatter.h"
10
+
11
+#include <chrono>
12
+#include <ctime>
13
+#include <memory>
14
+
15
+#include <string>
16
+#include <vector>
17
+
18
+namespace spdlog {
19
+namespace details {
20
+
21
+// padding information.
22
+struct padding_info
23
+{
24
+    enum pad_side
25
+    {
26
+        left,
27
+        right,
28
+        center
29
+    };
30
+
31
+    padding_info() = default;
32
+    padding_info(size_t width, padding_info::pad_side side)
33
+        : width_(width)
34
+        , side_(side)
35
+    {}
36
+
37
+    bool enabled() const
38
+    {
39
+        return width_ != 0;
40
+    }
41
+    const size_t width_ = 0;
42
+    const pad_side side_ = left;
43
+};
44
+
45
+class flag_formatter
46
+{
47
+public:
48
+    explicit flag_formatter(padding_info padinfo)
49
+        : padinfo_(padinfo)
50
+    {}
51
+    flag_formatter() = default;
52
+    virtual ~flag_formatter() = default;
53
+    virtual void format(const details::log_msg &msg, const std::tm &tm_time, memory_buf_t &dest) = 0;
54
+
55
+protected:
56
+    padding_info padinfo_;
57
+};
58
+
59
+} // namespace details
60
+
61
+class pattern_formatter final : public formatter
62
+{
63
+public:
64
+    explicit pattern_formatter(
65
+        std::string pattern, pattern_time_type time_type = pattern_time_type::local, std::string eol = spdlog::details::os::default_eol);
66
+
67
+    // use default pattern is not given
68
+    explicit pattern_formatter(pattern_time_type time_type = pattern_time_type::local, std::string eol = spdlog::details::os::default_eol);
69
+
70
+    pattern_formatter(const pattern_formatter &other) = delete;
71
+    pattern_formatter &operator=(const pattern_formatter &other) = delete;
72
+
73
+    std::unique_ptr<formatter> clone() const override;
74
+    void format(const details::log_msg &msg, memory_buf_t &dest) override;
75
+
76
+private:
77
+    std::string pattern_;
78
+    std::string eol_;
79
+    pattern_time_type pattern_time_type_;
80
+    std::tm cached_tm_;
81
+    std::chrono::seconds last_log_secs_;
82
+    std::vector<std::unique_ptr<details::flag_formatter>> formatters_;
83
+
84
+    std::tm get_time_(const details::log_msg &msg);
85
+    template<typename Padder>
86
+    void handle_flag_(char flag, details::padding_info padding);
87
+
88
+    // Extract given pad spec (e.g. %8X)
89
+    // Advance the given it pass the end of the padding spec found (if any)
90
+    // Return padding.
91
+    details::padding_info handle_padspec_(std::string::const_iterator &it, std::string::const_iterator end);
92
+
93
+    void compile_pattern_(const std::string &pattern);
94
+};
95
+} // namespace spdlog
96
+
97
+#ifdef SPDLOG_HEADER_ONLY
98
+#include "pattern_formatter-inl.h"
99
+#endif

+ 49
- 0
incl/spdlog/details/periodic_worker-inl.h View File

@@ -0,0 +1,49 @@
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
+#ifndef SPDLOG_HEADER_ONLY
7
+#include "spdlog/details/periodic_worker.h"
8
+#endif
9
+
10
+namespace spdlog {
11
+namespace details {
12
+
13
+SPDLOG_INLINE periodic_worker::periodic_worker(const std::function<void()> &callback_fun, std::chrono::seconds interval)
14
+{
15
+    active_ = (interval > std::chrono::seconds::zero());
16
+    if (!active_)
17
+    {
18
+        return;
19
+    }
20
+
21
+    worker_thread_ = std::thread([this, callback_fun, interval]() {
22
+        for (;;)
23
+        {
24
+            std::unique_lock<std::mutex> lock(this->mutex_);
25
+            if (this->cv_.wait_for(lock, interval, [this] { return !this->active_; }))
26
+            {
27
+                return; // active_ == false, so exit this thread
28
+            }
29
+            callback_fun();
30
+        }
31
+    });
32
+}
33
+
34
+// stop the worker thread and join it
35
+SPDLOG_INLINE periodic_worker::~periodic_worker()
36
+{
37
+    if (worker_thread_.joinable())
38
+    {
39
+        {
40
+            std::lock_guard<std::mutex> lock(mutex_);
41
+            active_ = false;
42
+        }
43
+        cv_.notify_one();
44
+        worker_thread_.join();
45
+    }
46
+}
47
+
48
+} // namespace details
49
+} // namespace spdlog

+ 40
- 0
incl/spdlog/details/periodic_worker.h View File

@@ -0,0 +1,40 @@
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
+// periodic worker thread - periodically executes the given callback function.
7
+//
8
+// RAII over the owned thread:
9
+//    creates the thread on construction.
10
+//    stops and joins the thread on destruction (if the thread is executing a callback, wait for it to finish first).
11
+
12
+#include <chrono>
13
+#include <condition_variable>
14
+#include <functional>
15
+#include <mutex>
16
+#include <thread>
17
+namespace spdlog {
18
+namespace details {
19
+
20
+class periodic_worker
21
+{
22
+public:
23
+    periodic_worker(const std::function<void()> &callback_fun, std::chrono::seconds interval);
24
+    periodic_worker(const periodic_worker &) = delete;
25
+    periodic_worker &operator=(const periodic_worker &) = delete;
26
+    // stop the worker thread and join it
27
+    ~periodic_worker();
28
+
29
+private:
30
+    bool active_;
31
+    std::thread worker_thread_;
32
+    std::mutex mutex_;
33
+    std::condition_variable cv_;
34
+};
35
+} // namespace details
36
+} // namespace spdlog
37
+
38
+#ifdef SPDLOG_HEADER_ONLY
39
+#include "periodic_worker-inl.h"
40
+#endif

+ 284
- 0
incl/spdlog/details/registry-inl.h View File

@@ -0,0 +1,284 @@
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
+#ifndef SPDLOG_HEADER_ONLY
7
+#include "spdlog/details/registry.h"
8
+#endif
9
+
10
+#include "spdlog/common.h"
11
+#include "spdlog/details/periodic_worker.h"
12
+#include "spdlog/logger.h"
13
+#include "spdlog/details/pattern_formatter.h"
14
+
15
+#ifndef SPDLOG_DISABLE_DEFAULT_LOGGER
16
+// support for the default stdout color logger
17
+#ifdef _WIN32
18
+#include "spdlog/sinks/wincolor_sink.h"
19
+#else
20
+#include "spdlog/sinks/ansicolor_sink.h"
21
+#endif
22
+#endif // SPDLOG_DISABLE_DEFAULT_LOGGER
23
+
24
+#include <chrono>
25
+#include <functional>
26
+#include <memory>
27
+#include <string>
28
+#include <unordered_map>
29
+
30
+namespace spdlog {
31
+namespace details {
32
+
33
+SPDLOG_INLINE registry::registry()
34
+    : formatter_(new pattern_formatter())
35
+{
36
+
37
+#ifndef SPDLOG_DISABLE_DEFAULT_LOGGER
38
+    // create default logger (ansicolor_stdout_sink_mt or wincolor_stdout_sink_mt in windows).
39
+#ifdef _WIN32
40
+    auto color_sink = std::make_shared<sinks::wincolor_stdout_sink_mt>();
41
+#else
42
+    auto color_sink = std::make_shared<sinks::ansicolor_stdout_sink_mt>();
43
+#endif
44
+
45
+    const char *default_logger_name = "";
46
+    default_logger_ = std::make_shared<spdlog::logger>(default_logger_name, std::move(color_sink));
47
+    loggers_[default_logger_name] = default_logger_;
48
+
49
+#endif // SPDLOG_DISABLE_DEFAULT_LOGGER
50
+}
51
+SPDLOG_INLINE void registry::register_logger(std::shared_ptr<logger> new_logger)
52
+{
53
+    std::lock_guard<std::mutex> lock(logger_map_mutex_);
54
+    register_logger_(std::move(new_logger));
55
+}
56
+
57
+SPDLOG_INLINE void registry::initialize_logger(std::shared_ptr<logger> new_logger)
58
+{
59
+    std::lock_guard<std::mutex> lock(logger_map_mutex_);
60
+    new_logger->set_formatter(formatter_->clone());
61
+
62
+    if (err_handler_)
63
+    {
64
+        new_logger->set_error_handler(err_handler_);
65
+    }
66
+
67
+    new_logger->set_level(level_);
68
+    new_logger->flush_on(flush_level_);
69
+
70
+    if (backtrace_n_messages_ > 0)
71
+    {
72
+        new_logger->enable_backtrace(backtrace_n_messages_);
73
+    }
74
+
75
+    if (automatic_registration_)
76
+    {
77
+        register_logger_(std::move(new_logger));
78
+    }
79
+}
80
+
81
+SPDLOG_INLINE std::shared_ptr<logger> registry::get(const std::string &logger_name)
82
+{
83
+    std::lock_guard<std::mutex> lock(logger_map_mutex_);
84
+    auto found = loggers_.find(logger_name);
85
+    return found == loggers_.end() ? nullptr : found->second;
86
+}
87
+
88
+SPDLOG_INLINE std::shared_ptr<logger> registry::default_logger()
89
+{
90
+    std::lock_guard<std::mutex> lock(logger_map_mutex_);
91
+    return default_logger_;
92
+}
93
+
94
+// Return raw ptr to the default logger.
95
+// To be used directly by the spdlog default api (e.g. spdlog::info)
96
+// This make the default API faster, but cannot be used concurrently with set_default_logger().
97
+// e.g do not call set_default_logger() from one thread while calling spdlog::info() from another.
98
+SPDLOG_INLINE logger *registry::get_default_raw()
99
+{
100
+    return default_logger_.get();
101
+}
102
+
103
+// set default logger.
104
+// default logger is stored in default_logger_ (for faster retrieval) and in the loggers_ map.
105
+SPDLOG_INLINE void registry::set_default_logger(std::shared_ptr<logger> new_default_logger)
106
+{
107
+    std::lock_guard<std::mutex> lock(logger_map_mutex_);
108
+    // remove previous default logger from the map
109
+    if (default_logger_ != nullptr)
110
+    {
111
+        loggers_.erase(default_logger_->name());
112
+    }
113
+    if (new_default_logger != nullptr)
114
+    {
115
+        loggers_[new_default_logger->name()] = new_default_logger;
116
+    }
117
+    default_logger_ = std::move(new_default_logger);
118
+}
119
+
120
+SPDLOG_INLINE void registry::set_tp(std::shared_ptr<thread_pool> tp)
121
+{
122
+    std::lock_guard<std::recursive_mutex> lock(tp_mutex_);
123
+    tp_ = std::move(tp);
124
+}
125
+
126
+SPDLOG_INLINE std::shared_ptr<thread_pool> registry::get_tp()
127
+{
128
+    std::lock_guard<std::recursive_mutex> lock(tp_mutex_);
129
+    return tp_;
130
+}
131
+
132
+// Set global formatter. Each sink in each logger will get a clone of this object
133
+SPDLOG_INLINE void registry::set_formatter(std::unique_ptr<formatter> formatter)
134
+{
135
+    std::lock_guard<std::mutex> lock(logger_map_mutex_);
136
+    formatter_ = std::move(formatter);
137
+    for (auto &l : loggers_)
138
+    {
139
+        l.second->set_formatter(formatter_->clone());
140
+    }
141
+}
142
+
143
+SPDLOG_INLINE void registry::enable_backtrace(size_t n_messages)
144
+{
145
+    std::lock_guard<std::mutex> lock(logger_map_mutex_);
146
+    backtrace_n_messages_ = n_messages;
147
+
148
+    for (auto &l : loggers_)
149
+    {
150
+        l.second->enable_backtrace(n_messages);
151
+    }
152
+}
153
+
154
+SPDLOG_INLINE void registry::disable_backtrace()
155
+{
156
+    std::lock_guard<std::mutex> lock(logger_map_mutex_);
157
+    backtrace_n_messages_ = 0;
158
+    for (auto &l : loggers_)
159
+    {
160
+        l.second->disable_backtrace();
161
+    }
162
+}
163
+
164
+SPDLOG_INLINE void registry::set_level(level::level_enum log_level)
165
+{
166
+    std::lock_guard<std::mutex> lock(logger_map_mutex_);
167
+    for (auto &l : loggers_)
168
+    {
169
+        l.second->set_level(log_level);
170
+    }
171
+    level_ = log_level;
172
+}
173
+
174
+SPDLOG_INLINE void registry::flush_on(level::level_enum log_level)
175
+{
176
+    std::lock_guard<std::mutex> lock(logger_map_mutex_);
177
+    for (auto &l : loggers_)
178
+    {
179
+        l.second->flush_on(log_level);
180
+    }
181
+    flush_level_ = log_level;
182
+}
183
+
184
+SPDLOG_INLINE void registry::flush_every(std::chrono::seconds interval)
185
+{
186
+    std::lock_guard<std::mutex> lock(flusher_mutex_);
187
+    std::function<void()> clbk = std::bind(&registry::flush_all, this);
188
+    periodic_flusher_ = details::make_unique<periodic_worker>(clbk, interval);
189
+}
190
+
191
+SPDLOG_INLINE void registry::set_error_handler(void (*handler)(const std::string &msg))
192
+{
193
+    std::lock_guard<std::mutex> lock(logger_map_mutex_);
194
+    for (auto &l : loggers_)
195
+    {
196
+        l.second->set_error_handler(handler);
197
+    }
198
+    err_handler_ = handler;
199
+}
200
+
201
+SPDLOG_INLINE void registry::apply_all(const std::function<void(const std::shared_ptr<logger>)> &fun)
202
+{
203
+    std::lock_guard<std::mutex> lock(logger_map_mutex_);
204
+    for (auto &l : loggers_)
205
+    {
206
+        fun(l.second);
207
+    }
208
+}
209
+
210
+SPDLOG_INLINE void registry::flush_all()
211
+{
212
+    std::lock_guard<std::mutex> lock(logger_map_mutex_);
213
+    for (auto &l : loggers_)
214
+    {
215
+        l.second->flush();
216
+    }
217
+}
218
+
219
+SPDLOG_INLINE void registry::drop(const std::string &logger_name)
220
+{
221
+    std::lock_guard<std::mutex> lock(logger_map_mutex_);
222
+    loggers_.erase(logger_name);
223
+    if (default_logger_ && default_logger_->name() == logger_name)
224
+    {
225
+        default_logger_.reset();
226
+    }
227
+}
228
+
229
+SPDLOG_INLINE void registry::drop_all()
230
+{
231
+    std::lock_guard<std::mutex> lock(logger_map_mutex_);
232
+    loggers_.clear();
233
+    default_logger_.reset();
234
+}
235
+
236
+// clean all resources and threads started by the registry
237
+SPDLOG_INLINE void registry::shutdown()
238
+{
239
+    {
240
+        std::lock_guard<std::mutex> lock(flusher_mutex_);
241
+        periodic_flusher_.reset();
242
+    }
243
+
244
+    drop_all();
245
+
246
+    {
247
+        std::lock_guard<std::recursive_mutex> lock(tp_mutex_);
248
+        tp_.reset();
249
+    }
250
+}
251
+
252
+SPDLOG_INLINE std::recursive_mutex &registry::tp_mutex()
253
+{
254
+    return tp_mutex_;
255
+}
256
+
257
+SPDLOG_INLINE void registry::set_automatic_registration(bool automatic_regsistration)
258
+{
259
+    std::lock_guard<std::mutex> lock(logger_map_mutex_);
260
+    automatic_registration_ = automatic_regsistration;
261
+}
262
+
263
+SPDLOG_INLINE registry &registry::instance()
264
+{
265
+    static registry s_instance;
266
+    return s_instance;
267
+}
268
+
269
+SPDLOG_INLINE void registry::throw_if_exists_(const std::string &logger_name)
270
+{
271
+    if (loggers_.find(logger_name) != loggers_.end())
272
+    {
273
+        SPDLOG_THROW(spdlog_ex("logger with name '" + logger_name + "' already exists"));
274
+    }
275
+}
276
+
277
+SPDLOG_INLINE void registry::register_logger_(std::shared_ptr<logger> new_logger)
278
+{
279
+    auto logger_name = new_logger->name();
280
+    throw_if_exists_(logger_name);
281
+    loggers_[logger_name] = std::move(new_logger);
282
+}
283
+} // namespace details
284
+} // namespace spdlog

+ 109
- 0
incl/spdlog/details/registry.h View File

@@ -0,0 +1,109 @@
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
+// Loggers registry of unique name->logger pointer
7
+// An attempt to create a logger with an already existing name will result with spdlog_ex exception.
8
+// If user requests a non existing logger, nullptr will be returned
9
+// This class is thread safe
10
+
11
+#include "spdlog/common.h"
12
+
13
+#include <chrono>
14
+#include <functional>
15
+#include <memory>
16
+#include <string>
17
+#include <unordered_map>
18
+#include <mutex>
19
+
20
+namespace spdlog {
21
+class logger;
22
+
23
+namespace details {
24
+class thread_pool;
25
+class periodic_worker;
26
+
27
+class registry
28
+{
29
+public:
30
+    registry(const registry &) = delete;
31
+    registry &operator=(const registry &) = delete;
32
+
33
+    void register_logger(std::shared_ptr<logger> new_logger);
34
+    void initialize_logger(std::shared_ptr<logger> new_logger);
35
+    std::shared_ptr<logger> get(const std::string &logger_name);
36
+    std::shared_ptr<logger> default_logger();
37
+
38
+    // Return raw ptr to the default logger.
39
+    // To be used directly by the spdlog default api (e.g. spdlog::info)
40
+    // This make the default API faster,