1 //
2 // Copyright(c) 2015 Gabi Melman.
3 // Distributed under the MIT License (http://opensource.org/licenses/MIT)
4 //
5 
6 #pragma once
7 
8 // Loggers registy of unique name->logger pointer
9 // An attempt to create a logger with an already existing name will be ignored
10 // If user requests a non existing logger, nullptr will be returned
11 // This class is thread safe
12 
13 #include "spdlog/details/null_mutex.h"
14 #include "spdlog/logger.h"
15 #include "spdlog/async_logger.h"
16 #include "spdlog/common.h"
17 
18 #include <chrono>
19 #include <functional>
20 #include <memory>
21 #include <mutex>
22 #include <string>
23 #include <unordered_map>
24 
25 namespace spdlog
26 {
27 namespace details
28 {
29 template <class Mutex> class registry_t
30 {
31 public:
32 
register_logger(std::shared_ptr<logger> logger)33     void register_logger(std::shared_ptr<logger> logger)
34     {
35         std::lock_guard<Mutex> lock(_mutex);
36         auto logger_name = logger->name();
37         throw_if_exists(logger_name);
38         _loggers[logger_name] = logger;
39     }
40 
41 
get(const std::string& logger_name)42     std::shared_ptr<logger> get(const std::string& logger_name)
43     {
44         std::lock_guard<Mutex> lock(_mutex);
45         auto found = _loggers.find(logger_name);
46         return found == _loggers.end() ? nullptr : found->second;
47     }
48 
49     template<class It>
create(const std::string& logger_name, const It& sinks_begin, const It& sinks_end)50     std::shared_ptr<logger> create(const std::string& logger_name, const It& sinks_begin, const It& sinks_end)
51     {
52         std::lock_guard<Mutex> lock(_mutex);
53         throw_if_exists(logger_name);
54         std::shared_ptr<logger> new_logger;
55         if (_async_mode)
56             new_logger = std::make_shared<async_logger>(logger_name, sinks_begin, sinks_end, _async_q_size, _overflow_policy, _worker_warmup_cb, _flush_interval_ms, _worker_teardown_cb);
57         else
58             new_logger = std::make_shared<logger>(logger_name, sinks_begin, sinks_end);
59 
60         if (_formatter)
61             new_logger->set_formatter(_formatter);
62 
63         if (_err_handler)
64             new_logger->set_error_handler(_err_handler);
65 
66         new_logger->set_level(_level);
67 
68 
69         //Add to registry
70         _loggers[logger_name] = new_logger;
71         return new_logger;
72     }
73 
74     template<class It>
create_async(const std::string& logger_name, size_t queue_size, const async_overflow_policy overflow_policy, const std::function<void()>& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms, const std::function<void()>& worker_teardown_cb, const It& sinks_begin, const It& sinks_end)75     std::shared_ptr<async_logger> create_async(const std::string& logger_name, size_t queue_size, const async_overflow_policy overflow_policy, const std::function<void()>& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms, const std::function<void()>& worker_teardown_cb, const It& sinks_begin, const It& sinks_end)
76     {
77         std::lock_guard<Mutex> lock(_mutex);
78         throw_if_exists(logger_name);
79         auto new_logger = std::make_shared<async_logger>(logger_name, sinks_begin, sinks_end, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb);
80 
81         if (_formatter)
82             new_logger->set_formatter(_formatter);
83 
84         if (_err_handler)
85             new_logger->set_error_handler(_err_handler);
86 
87         new_logger->set_level(_level);
88 
89         //Add to registry
90         _loggers[logger_name] = new_logger;
91         return new_logger;
92     }
93 
apply_all(std::function<void(std::shared_ptr<logger>)> fun)94     void apply_all(std::function<void(std::shared_ptr<logger>)> fun)
95     {
96         std::lock_guard<Mutex> lock(_mutex);
97         for (auto &l : _loggers)
98             fun(l.second);
99     }
100 
drop(const std::string& logger_name)101     void drop(const std::string& logger_name)
102     {
103         std::lock_guard<Mutex> lock(_mutex);
104         _loggers.erase(logger_name);
105     }
106 
drop_all()107     void drop_all()
108     {
109         std::lock_guard<Mutex> lock(_mutex);
110         _loggers.clear();
111     }
create(const std::string& logger_name, sinks_init_list sinks)112     std::shared_ptr<logger> create(const std::string& logger_name, sinks_init_list sinks)
113     {
114         return create(logger_name, sinks.begin(), sinks.end());
115     }
116 
create(const std::string& logger_name, sink_ptr sink)117     std::shared_ptr<logger> create(const std::string& logger_name, sink_ptr sink)
118     {
119         return create(logger_name, { sink });
120     }
121 
create_async(const std::string& logger_name, size_t queue_size, const async_overflow_policy overflow_policy, const std::function<void()>& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms, const std::function<void()>& worker_teardown_cb, sinks_init_list sinks)122     std::shared_ptr<async_logger> create_async(const std::string& logger_name, size_t queue_size, const async_overflow_policy overflow_policy, const std::function<void()>& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms, const std::function<void()>& worker_teardown_cb, sinks_init_list sinks)
123     {
124         return create_async(logger_name, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb, sinks.begin(), sinks.end());
125     }
126 
create_async(const std::string& logger_name, size_t queue_size, const async_overflow_policy overflow_policy, const std::function<void()>& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms, const std::function<void()>& worker_teardown_cb, sink_ptr sink)127     std::shared_ptr<async_logger> create_async(const std::string& logger_name, size_t queue_size, const async_overflow_policy overflow_policy, const std::function<void()>& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms, const std::function<void()>& worker_teardown_cb, sink_ptr sink)
128     {
129         return create_async(logger_name, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb, { sink });
130     }
131 
formatter(formatter_ptr f)132     void formatter(formatter_ptr f)
133     {
134         std::lock_guard<Mutex> lock(_mutex);
135         _formatter = f;
136         for (auto& l : _loggers)
137             l.second->set_formatter(_formatter);
138     }
139 
set_pattern(const std::string& pattern)140     void set_pattern(const std::string& pattern)
141     {
142         std::lock_guard<Mutex> lock(_mutex);
143         _formatter = std::make_shared<pattern_formatter>(pattern);
144         for (auto& l : _loggers)
145             l.second->set_formatter(_formatter);
146     }
147 
set_level(level::level_enum log_level)148     void set_level(level::level_enum log_level)
149     {
150         std::lock_guard<Mutex> lock(_mutex);
151         for (auto& l : _loggers)
152             l.second->set_level(log_level);
153         _level = log_level;
154     }
155 
set_error_handler(log_err_handler handler)156     void set_error_handler(log_err_handler handler)
157     {
158         for (auto& l : _loggers)
159             l.second->set_error_handler(handler);
160         _err_handler = handler;
161     }
162 
set_async_mode(size_t q_size, const async_overflow_policy overflow_policy, const std::function<void()>& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms, const std::function<void()>& worker_teardown_cb)163     void set_async_mode(size_t q_size, const async_overflow_policy overflow_policy, const std::function<void()>& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms, const std::function<void()>& worker_teardown_cb)
164     {
165         std::lock_guard<Mutex> lock(_mutex);
166         _async_mode = true;
167         _async_q_size = q_size;
168         _overflow_policy = overflow_policy;
169         _worker_warmup_cb = worker_warmup_cb;
170         _flush_interval_ms = flush_interval_ms;
171         _worker_teardown_cb = worker_teardown_cb;
172     }
173 
set_sync_mode()174     void set_sync_mode()
175     {
176         std::lock_guard<Mutex> lock(_mutex);
177         _async_mode = false;
178     }
179 
instance()180     static registry_t<Mutex>& instance()
181     {
182         static registry_t<Mutex> s_instance;
183         return s_instance;
184     }
185 
186 private:
registry_t()187     registry_t<Mutex>() {}
188     registry_t<Mutex>(const registry_t<Mutex>&) = delete;
189     registry_t<Mutex>& operator=(const registry_t<Mutex>&) = delete;
190 
throw_if_exists(const std::string &logger_name)191     void throw_if_exists(const std::string &logger_name)
192     {
193         if (_loggers.find(logger_name) != _loggers.end())
194             throw spdlog_ex("logger with name '" + logger_name + "' already exists");
195     }
196     Mutex _mutex;
197     std::unordered_map <std::string, std::shared_ptr<logger>> _loggers;
198     formatter_ptr _formatter;
199     level::level_enum _level = level::info;
200     log_err_handler _err_handler;
201     bool _async_mode = false;
202     size_t _async_q_size = 0;
203     async_overflow_policy _overflow_policy = async_overflow_policy::block_retry;
204     std::function<void()> _worker_warmup_cb = nullptr;
205     std::chrono::milliseconds _flush_interval_ms;
206     std::function<void()> _worker_teardown_cb = nullptr;
207 };
208 #ifdef SPDLOG_NO_REGISTRY_MUTEX
209 typedef registry_t<spdlog::details::null_mutex> registry;
210 #else
211 typedef registry_t<std::mutex> registry;
212 #endif
213 }
214 }
215