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 registry()33SPDLOG_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 register_logger(std::shared_ptr<logger> new_logger)54SPDLOG_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 initialize_logger(std::shared_ptr<logger> new_logger)60SPDLOG_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 get(const std::string & logger_name)88SPDLOG_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 default_logger()95SPDLOG_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. get_default_raw()105SPDLOG_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. set_default_logger(std::shared_ptr<logger> new_default_logger)112SPDLOG_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 set_tp(std::shared_ptr<thread_pool> tp)127SPDLOG_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 get_tp()133SPDLOG_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 set_formatter(std::unique_ptr<formatter> formatter)140SPDLOG_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 enable_backtrace(size_t n_messages)150SPDLOG_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 disable_backtrace()161SPDLOG_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 set_level(level::level_enum log_level)171SPDLOG_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 flush_on(level::level_enum log_level)181SPDLOG_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 flush_every(std::chrono::seconds interval)191SPDLOG_INLINE void registry::flush_every(std::chrono::seconds interval) 192 { 193 std::lock_guard<std::mutex> lock(flusher_mutex_); 194 auto clbk = [this]() { this->flush_all(); }; 195 periodic_flusher_ = details::make_unique<periodic_worker>(clbk, interval); 196 } 197 set_error_handler(void (* handler)(const std::string & msg))198SPDLOG_INLINE void registry::set_error_handler(void (*handler)(const std::string &msg)) 199 { 200 std::lock_guard<std::mutex> lock(logger_map_mutex_); 201 for (auto &l : loggers_) 202 { 203 l.second->set_error_handler(handler); 204 } 205 err_handler_ = handler; 206 } 207 apply_all(const std::function<void (const std::shared_ptr<logger>)> & fun)208SPDLOG_INLINE void registry::apply_all(const std::function<void(const std::shared_ptr<logger>)> &fun) 209 { 210 std::lock_guard<std::mutex> lock(logger_map_mutex_); 211 for (auto &l : loggers_) 212 { 213 fun(l.second); 214 } 215 } 216 flush_all()217SPDLOG_INLINE void registry::flush_all() 218 { 219 std::lock_guard<std::mutex> lock(logger_map_mutex_); 220 for (auto &l : loggers_) 221 { 222 l.second->flush(); 223 } 224 } 225 drop(const std::string & logger_name)226SPDLOG_INLINE void registry::drop(const std::string &logger_name) 227 { 228 std::lock_guard<std::mutex> lock(logger_map_mutex_); 229 loggers_.erase(logger_name); 230 if (default_logger_ && default_logger_->name() == logger_name) 231 { 232 default_logger_.reset(); 233 } 234 } 235 drop_all()236SPDLOG_INLINE void registry::drop_all() 237 { 238 std::lock_guard<std::mutex> lock(logger_map_mutex_); 239 loggers_.clear(); 240 default_logger_.reset(); 241 } 242 243 // clean all resources and threads started by the registry shutdown()244SPDLOG_INLINE void registry::shutdown() 245 { 246 { 247 std::lock_guard<std::mutex> lock(flusher_mutex_); 248 periodic_flusher_.reset(); 249 } 250 251 drop_all(); 252 253 { 254 std::lock_guard<std::recursive_mutex> lock(tp_mutex_); 255 tp_.reset(); 256 } 257 } 258 tp_mutex()259SPDLOG_INLINE std::recursive_mutex ®istry::tp_mutex() 260 { 261 return tp_mutex_; 262 } 263 set_automatic_registration(bool automatic_registration)264SPDLOG_INLINE void registry::set_automatic_registration(bool automatic_registration) 265 { 266 std::lock_guard<std::mutex> lock(logger_map_mutex_); 267 automatic_registration_ = automatic_registration; 268 } 269 set_levels(log_levels levels,level::level_enum * global_level)270SPDLOG_INLINE void registry::set_levels(log_levels levels, level::level_enum *global_level) 271 { 272 std::lock_guard<std::mutex> lock(logger_map_mutex_); 273 log_levels_ = std::move(levels); 274 auto global_level_requested = global_level != nullptr; 275 global_log_level_ = global_level_requested ? *global_level : global_log_level_; 276 277 for (auto &logger : loggers_) 278 { 279 auto logger_entry = log_levels_.find(logger.first); 280 if (logger_entry != log_levels_.end()) 281 { 282 logger.second->set_level(logger_entry->second); 283 } 284 else if (global_level_requested) 285 { 286 logger.second->set_level(*global_level); 287 } 288 } 289 } 290 instance()291SPDLOG_INLINE registry ®istry::instance() 292 { 293 static registry s_instance; 294 return s_instance; 295 } 296 throw_if_exists_(const std::string & logger_name)297SPDLOG_INLINE void registry::throw_if_exists_(const std::string &logger_name) 298 { 299 if (loggers_.find(logger_name) != loggers_.end()) 300 { 301 throw_spdlog_ex("logger with name '" + logger_name + "' already exists"); 302 } 303 } 304 register_logger_(std::shared_ptr<logger> new_logger)305SPDLOG_INLINE void registry::register_logger_(std::shared_ptr<logger> new_logger) 306 { 307 auto logger_name = new_logger->name(); 308 throw_if_exists_(logger_name); 309 loggers_[logger_name] = std::move(new_logger); 310 } 311 312 } // namespace details 313 } // namespace spdlog 314