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/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 | |
52 | SPDLOG_INLINE registry::~registry() = default; |
53 | |
54 | SPDLOG_INLINE void registry::register_logger(std::shared_ptr<logger> new_logger) |
55 | { |
56 | std::lock_guard<std::mutex> lock(logger_map_mutex_); |
57 | register_logger_(std::move(new_logger)); |
58 | } |
59 | |
60 | SPDLOG_INLINE void registry::initialize_logger(std::shared_ptr<logger> new_logger) |
61 | { |
62 | std::lock_guard<std::mutex> lock(logger_map_mutex_); |
63 | new_logger->set_formatter(formatter_->clone()); |
64 | |
65 | if (err_handler_) |
66 | { |
67 | new_logger->set_error_handler(err_handler_); |
68 | } |
69 | |
70 | // set new level according to previously configured level or default level |
71 | auto it = log_levels_.find(new_logger->name()); |
72 | auto new_level = it != log_levels_.end() ? it->second : global_log_level_; |
73 | new_logger->set_level(new_level); |
74 | |
75 | new_logger->flush_on(flush_level_); |
76 | |
77 | if (backtrace_n_messages_ > 0) |
78 | { |
79 | new_logger->enable_backtrace(backtrace_n_messages_); |
80 | } |
81 | |
82 | if (automatic_registration_) |
83 | { |
84 | register_logger_(std::move(new_logger)); |
85 | } |
86 | } |
87 | |
88 | SPDLOG_INLINE std::shared_ptr<logger> registry::get(const std::string &logger_name) |
89 | { |
90 | std::lock_guard<std::mutex> lock(logger_map_mutex_); |
91 | auto found = loggers_.find(logger_name); |
92 | return found == loggers_.end() ? nullptr : found->second; |
93 | } |
94 | |
95 | SPDLOG_INLINE std::shared_ptr<logger> registry::default_logger() |
96 | { |
97 | std::lock_guard<std::mutex> lock(logger_map_mutex_); |
98 | return default_logger_; |
99 | } |
100 | |
101 | // Return raw ptr to the default logger. |
102 | // To be used directly by the spdlog default api (e.g. spdlog::info) |
103 | // This make the default API faster, but cannot be used concurrently with set_default_logger(). |
104 | // e.g do not call set_default_logger() from one thread while calling spdlog::info() from another. |
105 | SPDLOG_INLINE logger *registry::get_default_raw() |
106 | { |
107 | return default_logger_.get(); |
108 | } |
109 | |
110 | // set default logger. |
111 | // default logger is stored in default_logger_ (for faster retrieval) and in the loggers_ map. |
112 | SPDLOG_INLINE void registry::set_default_logger(std::shared_ptr<logger> new_default_logger) |
113 | { |
114 | std::lock_guard<std::mutex> lock(logger_map_mutex_); |
115 | // remove previous default logger from the map |
116 | if (default_logger_ != nullptr) |
117 | { |
118 | loggers_.erase(default_logger_->name()); |
119 | } |
120 | if (new_default_logger != nullptr) |
121 | { |
122 | loggers_[new_default_logger->name()] = new_default_logger; |
123 | } |
124 | default_logger_ = std::move(new_default_logger); |
125 | } |
126 | |
127 | SPDLOG_INLINE void registry::set_tp(std::shared_ptr<thread_pool> tp) |
128 | { |
129 | std::lock_guard<std::recursive_mutex> lock(tp_mutex_); |
130 | tp_ = std::move(tp); |
131 | } |
132 | |
133 | SPDLOG_INLINE std::shared_ptr<thread_pool> registry::get_tp() |
134 | { |
135 | std::lock_guard<std::recursive_mutex> lock(tp_mutex_); |
136 | return tp_; |
137 | } |
138 | |
139 | // Set global formatter. Each sink in each logger will get a clone of this object |
140 | SPDLOG_INLINE void registry::set_formatter(std::unique_ptr<formatter> formatter) |
141 | { |
142 | std::lock_guard<std::mutex> lock(logger_map_mutex_); |
143 | formatter_ = std::move(formatter); |
144 | for (auto &l : loggers_) |
145 | { |
146 | l.second->set_formatter(formatter_->clone()); |
147 | } |
148 | } |
149 | |
150 | SPDLOG_INLINE void registry::enable_backtrace(size_t n_messages) |
151 | { |
152 | std::lock_guard<std::mutex> lock(logger_map_mutex_); |
153 | backtrace_n_messages_ = n_messages; |
154 | |
155 | for (auto &l : loggers_) |
156 | { |
157 | l.second->enable_backtrace(n_messages); |
158 | } |
159 | } |
160 | |
161 | SPDLOG_INLINE void registry::disable_backtrace() |
162 | { |
163 | std::lock_guard<std::mutex> lock(logger_map_mutex_); |
164 | backtrace_n_messages_ = 0; |
165 | for (auto &l : loggers_) |
166 | { |
167 | l.second->disable_backtrace(); |
168 | } |
169 | } |
170 | |
171 | SPDLOG_INLINE void registry::set_level(level::level_enum log_level) |
172 | { |
173 | std::lock_guard<std::mutex> lock(logger_map_mutex_); |
174 | for (auto &l : loggers_) |
175 | { |
176 | l.second->set_level(log_level); |
177 | } |
178 | global_log_level_ = log_level; |
179 | } |
180 | |
181 | SPDLOG_INLINE void registry::flush_on(level::level_enum log_level) |
182 | { |
183 | std::lock_guard<std::mutex> lock(logger_map_mutex_); |
184 | for (auto &l : loggers_) |
185 | { |
186 | l.second->flush_on(log_level); |
187 | } |
188 | flush_level_ = log_level; |
189 | } |
190 | |
191 | SPDLOG_INLINE void registry::set_error_handler(err_handler handler) |
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_ = std::move(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 ®istry::tp_mutex() |
253 | { |
254 | return tp_mutex_; |
255 | } |
256 | |
257 | SPDLOG_INLINE void registry::set_automatic_registration(bool automatic_registration) |
258 | { |
259 | std::lock_guard<std::mutex> lock(logger_map_mutex_); |
260 | automatic_registration_ = automatic_registration; |
261 | } |
262 | |
263 | SPDLOG_INLINE void registry::set_levels(log_levels levels, level::level_enum *global_level) |
264 | { |
265 | std::lock_guard<std::mutex> lock(logger_map_mutex_); |
266 | log_levels_ = std::move(levels); |
267 | auto global_level_requested = global_level != nullptr; |
268 | global_log_level_ = global_level_requested ? *global_level : global_log_level_; |
269 | |
270 | for (auto &logger : loggers_) |
271 | { |
272 | auto logger_entry = log_levels_.find(logger.first); |
273 | if (logger_entry != log_levels_.end()) |
274 | { |
275 | logger.second->set_level(logger_entry->second); |
276 | } |
277 | else if (global_level_requested) |
278 | { |
279 | logger.second->set_level(*global_level); |
280 | } |
281 | } |
282 | } |
283 | |
284 | SPDLOG_INLINE registry ®istry::instance() |
285 | { |
286 | static registry s_instance; |
287 | return s_instance; |
288 | } |
289 | |
290 | SPDLOG_INLINE void registry::throw_if_exists_(const std::string &logger_name) |
291 | { |
292 | if (loggers_.find(logger_name) != loggers_.end()) |
293 | { |
294 | throw_spdlog_ex("logger with name '" + logger_name + "' already exists" ); |
295 | } |
296 | } |
297 | |
298 | SPDLOG_INLINE void registry::register_logger_(std::shared_ptr<logger> new_logger) |
299 | { |
300 | auto logger_name = new_logger->name(); |
301 | throw_if_exists_(logger_name); |
302 | loggers_[logger_name] = std::move(new_logger); |
303 | } |
304 | |
305 | } // namespace details |
306 | } // namespace spdlog |
307 | |