diff --git a/src/logging.h b/src/logging.h index acfb00fa76096447ba92fce8b07196633a31cf94..eea75fcc522654ab8d302634c432e267249be632 100644 --- a/src/logging.h +++ b/src/logging.h @@ -19,6 +19,9 @@ namespace wolf { namespace internal { +namespace do_not_enter_where_the_wolf_lives { + +#define __INTERNAL_WOLF_MAIN_LOGGER_NAME_ "wolf_main_console" static const auto repeated_brace = std::make_tuple("{}", "{}{}", @@ -44,49 +47,51 @@ static const auto repeated_brace = std::make_tuple("{}", "{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}", "{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}", "{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}", - "{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}"); // up to 25 args. - -class Logger : public Singleton<Logger> + "{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}"); // up to 25 args. Should be fine +class Logger { - friend class Singleton<Logger>; +public: -protected: + Logger(const std::string& name); - Logger(); - ~Logger(); + Logger(std::string&& name); -// It is counter intuitive to have those functions -// public but that for the sake of the macros below -public: + ~Logger(); - Logger(Logger&) = delete; - void operator=(Logger&) = delete; + // Not copyable/movable + Logger(Logger&) = delete; + void operator=(Logger&) = delete; + Logger(Logger&&) = delete; + void operator=(Logger&&) = delete; template<typename... Args> - void info(Args&&... args); + void info(Args&&... args) const; template<typename... Args> - void warn(Args&&... args); + void warn(Args&&... args) const; template<typename... Args> - void error(Args&&... args); + void error(Args&&... args) const; template<typename... Args> - void debug(Args&&... args); + void debug(Args&&... args) const; template<typename... Args> - void trace(Args&&... args); + void trace(Args&&... args) const; bool set_async_queue(const std::size_t q_size); + void set_pattern(const std::string& p); + protected: - const std::string log_name_ = "wolf_main_console"; + const std::string log_name_; std::shared_ptr<spdlog::logger> console_; }; -inline Logger::Logger() +inline Logger::Logger(const std::string& name) : + log_name_(name) { // Create main logger console_ = spdlog::stdout_color_mt(log_name_); @@ -99,9 +104,46 @@ inline Logger::Logger() // Queue size must be a power of 2 spdlog::set_async_mode(4096); - // Logging pattern is : - // [thread num][hour:minutes:seconds.nanoseconds][log type] #log-content - console_->set_pattern("[%t][%H:%M:%S.%F][%l] %v"); + if (log_name_ == __INTERNAL_WOLF_MAIN_LOGGER_NAME_) + // Logging pattern is : + // [thread num][hour:minutes:seconds.nanoseconds][log type] #log-content + //set_pattern("[%t][%H:%M:%S.%F][%l] %v"); + // [log type][MM/DD/YY - hour:minutes:seconds.nanoseconds] #log-content + set_pattern("[%l][%x - %H:%M:%S.%F] %v"); + else + // Logging pattern is : + // [logger name][thread num][hour:minutes:seconds.nanoseconds][log type] #log-content + //set_pattern("[" + log_name_ + "]" +"[%t][%H:%M:%S.%F][%l] %v"); + // [log type][MM/DD/YY - hour:minutes:seconds.nanoseconds][logger name] #log-content + set_pattern("[%l][%x - %H:%M:%S.%F][" + log_name_ + "] %v"); +} + +inline Logger::Logger(std::string&& name) : + log_name_(std::forward<std::string>(name)) +{ + // Create main logger + console_ = spdlog::stdout_color_mt(log_name_); + +#ifdef _WOLF_TRACE + console_->set_level(spdlog::level::trace); +#endif + + // Enable asynchronous logging + // Queue size must be a power of 2 + spdlog::set_async_mode(4096); + + if (log_name_ == __INTERNAL_WOLF_MAIN_LOGGER_NAME_) + // Logging pattern is : + // [thread num][hour:minutes:seconds.nanoseconds][log type] #log-content + //set_pattern("[%t][%H:%M:%S.%F][%l] %v"); + // [log type][MM/DD/YY - hour:minutes:seconds.nanoseconds] #log-content + set_pattern("[%l][%x - %H:%M:%S.%F] %v"); + else + // Logging pattern is : + // [logger name][thread num][hour:minutes:seconds.nanoseconds][log type] #log-content + //set_pattern("[" + log_name_ + "]" +"[%t][%H:%M:%S.%F][%l] %v"); + // [log type][MM/DD/YY - hour:minutes:seconds.nanoseconds][logger name] #log-content + set_pattern("[%l][%x - %H:%M:%S.%F][" + log_name_ + "] %v"); } inline Logger::~Logger() @@ -110,31 +152,31 @@ inline Logger::~Logger() } template<typename... Args> -void Logger::info(Args&&... args) +void Logger::info(Args&&... args) const { console_->info(std::get<sizeof...(args)-1>(repeated_brace), std::forward<Args>(args)...); } template<typename... Args> -void Logger::warn(Args&&... args) +void Logger::warn(Args&&... args) const { console_->warn(std::get<sizeof...(args)-1>(repeated_brace), std::forward<Args>(args)...); } template<typename... Args> -void Logger::error(Args&&... args) +void Logger::error(Args&&... args) const { console_->error(std::get<sizeof...(args)-1>(repeated_brace), std::forward<Args>(args)...); } template<typename... Args> -void Logger::debug(Args&&... args) +void Logger::debug(Args&&... args) const { console_->debug(std::get<sizeof...(args)-1>(repeated_brace), std::forward<Args>(args)...); } template<typename... Args> -void Logger::trace(Args&&... args) +void Logger::trace(Args&&... args) const { console_->trace(std::get<sizeof...(args)-1>(repeated_brace), std::forward<Args>(args)...); } @@ -148,38 +190,140 @@ inline bool Logger::set_async_queue(const std::size_t q_size) return q_size; } +inline void Logger::set_pattern(const std::string& p) +{ + console_->set_pattern(p); +} + +using LoggerPtr = std::unique_ptr<Logger>; + +/// dummy namespace to avoid colision with c++14 +/// @todo use std version once we move to cxx14 +namespace not_std { +template <typename T, typename... Args> +std::unique_ptr<T> make_unique(Args&&... args) +{ + return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); +} +} /* namespace not_std */ + +class LoggerManager +{ +public: + + LoggerManager() = default; + ~LoggerManager() = default; + + bool exists(const std::string& name) const + { + std::lock_guard<std::mutex> lock(mut_); + return existsImpl(name); + } + + const Logger& getLogger(const std::string& name) /*const*/ + { + std::lock_guard<std::mutex> lock(mut_); + + if (!existsImpl(name)) addLogger(name); + + return *(logger_map_.at(name)); + } + +protected: + + mutable std::mutex mut_; + + std::map<const std::string, const LoggerPtr> logger_map_; + + bool addLogger(const std::string& name) + { + /// @note would be easier with cpp17 map.try_emplace... + const bool created = existsImpl(name) ? + false : + logger_map_.emplace(name, not_std::make_unique<Logger>(name)).second; + return created; + } + + bool existsImpl(const std::string& name) const + { + return (logger_map_.find(name) != logger_map_.end()); + //return (spdlog::get(name) != nullptr); + } +}; + +} /* namespace do_not_enter_where_the_wolf_lives */ + +using WolfLogger = Singleton<do_not_enter_where_the_wolf_lives::Logger>; +using WolfLoggerManager = Singleton<do_not_enter_where_the_wolf_lives::LoggerManager>; + +} /* namespace internal */ +} /* namespace wolf */ + #define WOLF_STRINGIFY(x) #x #define WOLF_STR_HELPER(x) WOLF_STRINGIFY(x) -#define WOLF_INFO(...) \ - wolf::internal::Logger::get().info(__VA_ARGS__); +/// @brief NAMED LOGGING + +#define WOLF_ASYNC_QUEUE_LOG_NAMED(name, ...) wolf::internal::WolfLoggerManager::get().getLogger(name).set_async_queue(x); -#define WOLF_WARN(...) \ - wolf::internal::Logger::get().warn(__VA_ARGS__); +#define WOLF_INFO_NAMED(name, ...) wolf::internal::WolfLoggerManager::get().getLogger(name).info(__VA_ARGS__); +#define WOLF_INFO_NAMED_COND(name, cond, ...) if (cond) WOLF_INFO_NAMED(name, __VA_ARGS__); -#define WOLF_ERROR(...) \ - wolf::internal::Logger::get().error(__VA_ARGS__); +#define WOLF_WARN_NAMED(name, ...) wolf::internal::WolfLoggerManager::get().getLogger(name).warn(__VA_ARGS__); +#define WOLF_WARN_NAMED_COND(name, cond, ...) if (cond) WOLF_WARN_NAMED(name, __VA_ARGS__); + +#define WOLF_ERROR_NAMED(name, ...) wolf::internal::WolfLoggerManager::get().getLogger(name).error(__VA_ARGS__); +#define WOLF_ERROR_NAMED_COND(name, cond, ...) if (cond) WOLF_ERROR_NAMED(name, __VA_ARGS__); #ifdef _WOLF_DEBUG - #define WOLF_DEBUG(...) \ - wolf::internal::Logger::get().debug(__VA_ARGS__); + #define WOLF_DEBUG_NAMED(name, ...) wolf::internal::WolfLoggerManager::get().getLogger(name).debug(__VA_ARGS__); + #define WOLF_DEBUG_NAMED_COND(name, cond, ...) if (cond) WOLF_DEBUG_NAMED(name, __VA_ARGS__); #else - #define WOLF_DEBUG(...) + #define WOLF_DEBUG_NAMED(name, ...) + #define WOLF_DEBUG_NAMED_COND(cond, name, ...) #endif -#define WOLF_ASYNC_QUEUE_LOG(x) \ - wolf::internal::Logger::get().set_async_queue(x); +#ifdef _WOLF_TRACE + #define WOLF_TRACE_NAMED(name, ...) \ + {char this_file[] = __FILE__;\ + wolf::internal::WolfLoggerManager::get().getLogger(name).trace("[", basename(this_file), " L", __LINE__, \ + " : ", __FUNCTION__, "] ", __VA_ARGS__);} + #define WOLF_TRACE_NAMED_COND(name, cond, ...) if (cond) WOLF_TRACE_NAMED_COND(name, __VA_ARGS__); +#else + #define WOLF_TRACE_NAMED(...) + #define WOLF_TRACE_NAMED_cond(name, cond, ...) +#endif + +/// @brief MAIN LOGGING + +#define WOLF_ASYNC_QUEUE_LOG(x) wolf::internal::WolfLogger::get(__INTERNAL_WOLF_MAIN_LOGGER_NAME_).set_async_queue(x); + +#define WOLF_INFO(...) wolf::internal::WolfLogger::get(__INTERNAL_WOLF_MAIN_LOGGER_NAME_).info(__VA_ARGS__); +#define WOLF_INFO_COND(cond, ...) if (cond) WOLF_INFO(__VA_ARGS__); + +#define WOLF_WARN(...) wolf::internal::WolfLogger::get(__INTERNAL_WOLF_MAIN_LOGGER_NAME_).warn(__VA_ARGS__); +#define WOLF_WARN_COND(cond, ...) if (cond) WOLF_WARN(__VA_ARGS__); + +#define WOLF_ERROR(...) wolf::internal::WolfLogger::get(__INTERNAL_WOLF_MAIN_LOGGER_NAME_).error(__VA_ARGS__); +#define WOLF_ERROR_COND(cond, ...) if (cond) WOLF_ERROR(__VA_ARGS__); + +#ifdef _WOLF_DEBUG + #define WOLF_DEBUG(...) wolf::internal::WolfLogger::get(__INTERNAL_WOLF_MAIN_LOGGER_NAME_).debug(__VA_ARGS__); + #define WOLF_DEBUG_COND(cond, ...) if (cond) WOLF_DEBUG(__VA_ARGS__); +#else + #define WOLF_DEBUG(...) + #define WOLF_DEBUG_COND(cond, ...) +#endif #ifdef _WOLF_TRACE #define WOLF_TRACE(...) \ {char this_file[] = __FILE__;\ - wolf::internal::Logger::get().trace("[", basename(this_file), " L", __LINE__, \ + wolf::internal::WolfLogger::get(__INTERNAL_WOLF_MAIN_LOGGER_NAME_).trace("[", basename(this_file), " L", __LINE__, \ " : ", __FUNCTION__, "] ", __VA_ARGS__);} + #define WOLF_TRACE_COND(cond, ...) if (cond) WOLF_TRACE(__VA_ARGS__); #else #define WOLF_TRACE(...) + #define WOLF_TRACE_COND(cond, ...) #endif -} // namespace internal -} // namespace wolf - #endif /* WOLF_LOGGING_H_ */ diff --git a/src/processor_logging.h b/src/processor_logging.h new file mode 100644 index 0000000000000000000000000000000000000000..167beb892bb2dfe777426d14d535daf7e28cd1ac --- /dev/null +++ b/src/processor_logging.h @@ -0,0 +1,31 @@ +/** + * \file processor_logging.h + * + * Created on: Oct 5, 2017 + * \author: Jeremie Deray + */ + +#ifndef _WOLF_PROCESSOR_LOGGING_H_ +#define _WOLF_PROCESSOR_LOGGING_H_ + +/// @brief un-comment for IDE highlights. +//#include "logging.h" + +#define __INTERNAL_WOLF_ASSERT_PROCESSOR \ + static_assert(std::is_base_of<ProcessorBase, \ + typename std::remove_pointer<decltype(this)>::type>::value, \ + "This macro can be used only within the body of a " \ + "non-static " \ + "ProcessorBase (and derived) function !"); + +#define WOLF_PROCESSOR_INFO(...) __INTERNAL_WOLF_ASSERT_PROCESSOR WOLF_INFO_NAMED(getType(), __VA_ARGS__); +#define WOLF_PROCESSOR_WARN(...) __INTERNAL_WOLF_ASSERT_PROCESSOR WOLF_WARN_NAMED(getType(), __VA_ARGS__); +#define WOLF_PROCESSOR_ERROR(...) __INTERNAL_WOLF_ASSERT_PROCESSOR WOLF_ERROR_NAMED(getType(), __VA_ARGS__); +#define WOLF_PROCESSOR_DEBUG(...) __INTERNAL_WOLF_ASSERT_PROCESSOR WOLF_DEBUG_NAMED(getType(), __VA_ARGS__); + +#define WOLF_PROCESSOR_INFO_COND(cond, ...) __INTERNAL_WOLF_ASSERT_PROCESSOR WOLF_INFO_NAMED_COND(getType(), cond, __VA_ARGS__); +#define WOLF_PROCESSOR_WARN_COND(cond, ...) __INTERNAL_WOLF_ASSERT_PROCESSOR WOLF_WARN_NAMED_COND(getType(), cond, __VA_ARGS__); +#define WOLF_PROCESSOR_ERROR_COND(cond, ...) __INTERNAL_WOLF_ASSERT_PROCESSOR WOLF_ERROR_NAMED_COND(getType(), cond, __VA_ARGS__); +#define WOLF_PROCESSOR_DEBUG_COND(cond, ...) __INTERNAL_WOLF_ASSERT_PROCESSOR WOLF_DEBUG_NAMED_COND(getType(), cond, __VA_ARGS__); + +#endif /* _WOLF_PROCESSOR_LOGGING_H_ */ diff --git a/src/singleton.h b/src/singleton.h index 56450acaf4a738890eb3c98a9aca5d7c0e5dddb5..c50a8da39306e521c11caa3d098a524184b63a75 100644 --- a/src/singleton.h +++ b/src/singleton.h @@ -14,49 +14,34 @@ namespace wolf { namespace internal { /** - * \brief A thread-safer Singleton implementation with + * \brief A thread-safer (?) Singleton implementation with * argument forwarding. **/ template <class T> class Singleton { - /** - * \brief Custom deleter to by-pass private destructor issue. - **/ - struct Deleter; - - using SingletonOPtr = std::unique_ptr<T, Deleter>; + using SingletonOPtr = std::unique_ptr<T>; public: template <typename... Args> static T& get(Args&&... args) { - static SingletonOPtr instance_(new T(args...)); + static SingletonOPtr instance_(new T(std::forward<Args>(args)...)); return *instance_; } - constexpr Singleton(const Singleton&) = delete; - //constexpr Singleton(const Singleton&&) = delete; + constexpr Singleton(const Singleton&) = delete; + constexpr Singleton(const Singleton&&) = delete; constexpr Singleton& operator=(const Singleton&) const = delete; - //constexpr Singleton& operator=(const Singleton&&) = delete; + constexpr Singleton& operator=(const Singleton&&) = delete; protected: - Singleton() = default; - - virtual ~Singleton() = default; -}; - -template <class T> -struct Singleton<T>::Deleter -{ - void operator()( const T* const p ) - { - delete p; - } + constexpr Singleton() = default; + virtual ~Singleton() = default; }; } // namespace internal