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 @@
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_ */
/**
* \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 {
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
......
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