Skip to content
Snippets Groups Projects
Commit 26b7e6db authored by Joan Solà Ortega's avatar Joan Solà Ortega
Browse files

Merge branch 'enhance_logging' into 'master'

Enhance logging

See merge request mobile_robotics/wolf!137
parents 305ee3b1 776186a6
No related branches found
No related tags found
1 merge request!137Enhance logging
...@@ -19,6 +19,9 @@ ...@@ -19,6 +19,9 @@
namespace wolf { namespace wolf {
namespace internal { 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("{}", static const auto repeated_brace = std::make_tuple("{}",
"{}{}", "{}{}",
...@@ -44,49 +47,51 @@ static const auto repeated_brace = std::make_tuple("{}", ...@@ -44,49 +47,51 @@ static const auto repeated_brace = std::make_tuple("{}",
"{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}", "{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}",
"{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}", "{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}",
"{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}", "{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}",
"{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}"); // up to 25 args. "{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}"); // up to 25 args. Should be fine
class Logger
class Logger : public Singleton<Logger>
{ {
friend class Singleton<Logger>; public:
protected: Logger(const std::string& name);
Logger(); Logger(std::string&& name);
~Logger();
// It is counter intuitive to have those functions ~Logger();
// public but that for the sake of the macros below
public:
Logger(Logger&) = delete; // Not copyable/movable
void operator=(Logger&) = delete; Logger(Logger&) = delete;
void operator=(Logger&) = delete;
Logger(Logger&&) = delete;
void operator=(Logger&&) = delete;
template<typename... Args> template<typename... Args>
void info(Args&&... args); void info(Args&&... args) const;
template<typename... Args> template<typename... Args>
void warn(Args&&... args); void warn(Args&&... args) const;
template<typename... Args> template<typename... Args>
void error(Args&&... args); void error(Args&&... args) const;
template<typename... Args> template<typename... Args>
void debug(Args&&... args); void debug(Args&&... args) const;
template<typename... Args> template<typename... Args>
void trace(Args&&... args); void trace(Args&&... args) const;
bool set_async_queue(const std::size_t q_size); bool set_async_queue(const std::size_t q_size);
void set_pattern(const std::string& p);
protected: protected:
const std::string log_name_ = "wolf_main_console"; const std::string log_name_;
std::shared_ptr<spdlog::logger> console_; std::shared_ptr<spdlog::logger> console_;
}; };
inline Logger::Logger() inline Logger::Logger(const std::string& name) :
log_name_(name)
{ {
// Create main logger // Create main logger
console_ = spdlog::stdout_color_mt(log_name_); console_ = spdlog::stdout_color_mt(log_name_);
...@@ -99,9 +104,46 @@ inline Logger::Logger() ...@@ -99,9 +104,46 @@ inline Logger::Logger()
// Queue size must be a power of 2 // Queue size must be a power of 2
spdlog::set_async_mode(4096); spdlog::set_async_mode(4096);
// Logging pattern is : if (log_name_ == __INTERNAL_WOLF_MAIN_LOGGER_NAME_)
// [thread num][hour:minutes:seconds.nanoseconds][log type] #log-content // Logging pattern is :
console_->set_pattern("[%t][%H:%M:%S.%F][%l] %v"); // [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() inline Logger::~Logger()
...@@ -110,31 +152,31 @@ inline Logger::~Logger() ...@@ -110,31 +152,31 @@ inline Logger::~Logger()
} }
template<typename... Args> 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)...); console_->info(std::get<sizeof...(args)-1>(repeated_brace), std::forward<Args>(args)...);
} }
template<typename... 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)...); console_->warn(std::get<sizeof...(args)-1>(repeated_brace), std::forward<Args>(args)...);
} }
template<typename... 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)...); console_->error(std::get<sizeof...(args)-1>(repeated_brace), std::forward<Args>(args)...);
} }
template<typename... 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)...); console_->debug(std::get<sizeof...(args)-1>(repeated_brace), std::forward<Args>(args)...);
} }
template<typename... 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)...); 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) ...@@ -148,38 +190,140 @@ inline bool Logger::set_async_queue(const std::size_t q_size)
return 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_STRINGIFY(x) #x
#define WOLF_STR_HELPER(x) WOLF_STRINGIFY(x) #define WOLF_STR_HELPER(x) WOLF_STRINGIFY(x)
#define WOLF_INFO(...) \ /// @brief NAMED LOGGING
wolf::internal::Logger::get().info(__VA_ARGS__);
#define WOLF_ASYNC_QUEUE_LOG_NAMED(name, ...) wolf::internal::WolfLoggerManager::get().getLogger(name).set_async_queue(x);
#define WOLF_WARN(...) \ #define WOLF_INFO_NAMED(name, ...) wolf::internal::WolfLoggerManager::get().getLogger(name).info(__VA_ARGS__);
wolf::internal::Logger::get().warn(__VA_ARGS__); #define WOLF_INFO_NAMED_COND(name, cond, ...) if (cond) WOLF_INFO_NAMED(name, __VA_ARGS__);
#define WOLF_ERROR(...) \ #define WOLF_WARN_NAMED(name, ...) wolf::internal::WolfLoggerManager::get().getLogger(name).warn(__VA_ARGS__);
wolf::internal::Logger::get().error(__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 #ifdef _WOLF_DEBUG
#define WOLF_DEBUG(...) \ #define WOLF_DEBUG_NAMED(name, ...) wolf::internal::WolfLoggerManager::get().getLogger(name).debug(__VA_ARGS__);
wolf::internal::Logger::get().debug(__VA_ARGS__); #define WOLF_DEBUG_NAMED_COND(name, cond, ...) if (cond) WOLF_DEBUG_NAMED(name, __VA_ARGS__);
#else #else
#define WOLF_DEBUG(...) #define WOLF_DEBUG_NAMED(name, ...)
#define WOLF_DEBUG_NAMED_COND(cond, name, ...)
#endif #endif
#define WOLF_ASYNC_QUEUE_LOG(x) \ #ifdef _WOLF_TRACE
wolf::internal::Logger::get().set_async_queue(x); #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 #ifdef _WOLF_TRACE
#define WOLF_TRACE(...) \ #define WOLF_TRACE(...) \
{char this_file[] = __FILE__;\ {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__);} " : ", __FUNCTION__, "] ", __VA_ARGS__);}
#define WOLF_TRACE_COND(cond, ...) if (cond) WOLF_TRACE(__VA_ARGS__);
#else #else
#define WOLF_TRACE(...) #define WOLF_TRACE(...)
#define WOLF_TRACE_COND(cond, ...)
#endif #endif
} // namespace internal
} // namespace wolf
#endif /* WOLF_LOGGING_H_ */ #endif /* WOLF_LOGGING_H_ */
/**
* \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_ */
...@@ -14,49 +14,34 @@ namespace wolf { ...@@ -14,49 +14,34 @@ namespace wolf {
namespace internal { namespace internal {
/** /**
* \brief A thread-safer Singleton implementation with * \brief A thread-safer (?) Singleton implementation with
* argument forwarding. * argument forwarding.
**/ **/
template <class T> template <class T>
class Singleton class Singleton
{ {
/** using SingletonOPtr = std::unique_ptr<T>;
* \brief Custom deleter to by-pass private destructor issue.
**/
struct Deleter;
using SingletonOPtr = std::unique_ptr<T, Deleter>;
public: public:
template <typename... Args> template <typename... Args>
static T& get(Args&&... args) static T& get(Args&&... args)
{ {
static SingletonOPtr instance_(new T(args...)); static SingletonOPtr instance_(new T(std::forward<Args>(args)...));
return *instance_; 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&) const = delete;
//constexpr Singleton& operator=(const Singleton&&) = delete; constexpr Singleton& operator=(const Singleton&&) = delete;
protected: protected:
Singleton() = default; constexpr Singleton() = default;
virtual ~Singleton() = default;
virtual ~Singleton() = default;
};
template <class T>
struct Singleton<T>::Deleter
{
void operator()( const T* const p )
{
delete p;
}
}; };
} // namespace internal } // namespace internal
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment