diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f0bc0edec..a7fe491cdd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to this project are documented in this file. - Implement `AdvanceableRunner::isRunning()` method (https://github.com/dic-iit/bipedal-locomotion-framework/pull/395) - Implement `ContactPhaseList::getPresentPhase()` method (https://github.com/dic-iit/bipedal-locomotion-framework/pull/396) - Add a synchronization mechanism for the `AdvanceableRunner` class (https://github.com/dic-iit/bipedal-locomotion-framework/pull/403) +- Add the possibility to use spdlog with YARP (https://github.com/ami-iit/bipedal-locomotion-framework/pull/408) ### Changed diff --git a/src/TextLogging/CMakeLists.txt b/src/TextLogging/CMakeLists.txt index de3e7b2fca..0ee9445ac3 100644 --- a/src/TextLogging/CMakeLists.txt +++ b/src/TextLogging/CMakeLists.txt @@ -5,5 +5,8 @@ add_bipedal_locomotion_library( NAME TextLogging PUBLIC_HEADERS include/BipedalLocomotion/TextLogging/Logger.h - SOURCES src/Logger.cpp - PUBLIC_LINK_LIBRARIES spdlog::spdlog) + include/BipedalLocomotion/TextLogging/LoggerBuilder.h + include/BipedalLocomotion/TextLogging/DefaultLogger.h + SOURCES src/Logger.cpp src/LoggerBuilder.cpp src/DefaultLogger.cpp + PUBLIC_LINK_LIBRARIES spdlog::spdlog + SUBDIRECTORIES YarpImplementation) diff --git a/src/TextLogging/YarpImplementation/CMakeLists.txt b/src/TextLogging/YarpImplementation/CMakeLists.txt new file mode 100644 index 0000000000..23a94a0ef7 --- /dev/null +++ b/src/TextLogging/YarpImplementation/CMakeLists.txt @@ -0,0 +1,14 @@ +# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved. +# This software may be modified and distributed under the terms of the +# GNU Lesser General Public License v2.1 or any later version. + +if(FRAMEWORK_COMPILE_YarpImplementation) + + add_bipedal_locomotion_library( + NAME TextLoggingYarpImplementation + SOURCES src/YarpLogger.cpp + PUBLIC_HEADERS include/BipedalLocomotion/TextLogging/YarpLogger.h + PUBLIC_LINK_LIBRARIES BipedalLocomotion::TextLogging YARP::YARP_os + INSTALLATION_FOLDER TextLogging) + +endif() diff --git a/src/TextLogging/YarpImplementation/include/BipedalLocomotion/TextLogging/YarpLogger.h b/src/TextLogging/YarpImplementation/include/BipedalLocomotion/TextLogging/YarpLogger.h new file mode 100644 index 0000000000..b769cbb270 --- /dev/null +++ b/src/TextLogging/YarpImplementation/include/BipedalLocomotion/TextLogging/YarpLogger.h @@ -0,0 +1,101 @@ +/** + * @file YarpLogger.h + * @authors Giulio Romualdi + * @copyright 2021 Istituto Italiano di Tecnologia (IIT). This software may be modified and + * distributed under the terms of the GNU Lesser General Public License v2.1 or any later version. + */ + +#ifndef BIPEDAL_LOCOMOTION_TEXT_LOGGING_YARP_LOGGER_H +#define BIPEDAL_LOCOMOTION_TEXT_LOGGING_YARP_LOGGER_H + +#include +#include +#include + +#include +#include + +#include + +#include + +namespace BipedalLocomotion +{ +namespace TextLogging +{ + +namespace sinks +{ + +template class YarpSink : public spdlog::sinks::base_sink +{ +protected: + void sink_it_(const spdlog::details::log_msg& msg) override + { + + // log_msg is a struct containing the log entry info like level, timestamp, thread id etc. + // msg.raw contains pre formatted log + spdlog::memory_buf_t formatted; + + spdlog::sinks::base_sink::formatter_->format(msg, formatted); + + std::string formattedString(formatted.data(), formatted.size()); + + if (msg.level == spdlog::level::level_enum::trace) + { + yTrace() << formattedString; + } else if (msg.level == spdlog::level::level_enum::debug) + { + yDebug() << formattedString; + } else if (msg.level == spdlog::level::level_enum::info) + { + yInfo() << formattedString; + } else if (msg.level == spdlog::level::level_enum::warn) + { + yWarning() << formattedString; + } else if (msg.level == spdlog::level::level_enum::err) + { + yError() << formattedString; + } else + { + yFatal() << formattedString; + } + } + + void flush_() override + { + } +}; + +using YarpSink_mt = YarpSink; +} // namespace sinks + + +/** + * YarpLoggetFactory implements the factory you should use to enable the sink using yaro. + * The YARP logger can be easily used as follows + * \code{.cpp} + * #include + * #include + * #include + * + * // Change the logger + * BipedalLocomotion::TextLogging::LoggerBuilder::setFactory(std::make_shared())); + * + * BipedalLocomotion::log()->info("My info"); + * \endcode + */ +class YarpLoggerFactory final : public LoggerFactory +{ +public: + /** + * Create the YARPLogger as a singleton + * @return the pointer to TextLogging::Logger that streams the output using YARP + */ + TextLogging::Logger* const createLogger() final; +}; + +} // namespace TextLogging +} // namespace BipedalLocomotion + +#endif // BIPEDAL_LOCOMOTION_TEXT_LOGGING_YARP_LOGGER_H diff --git a/src/TextLogging/YarpImplementation/src/YarpLogger.cpp b/src/TextLogging/YarpImplementation/src/YarpLogger.cpp new file mode 100644 index 0000000000..3ae6c277e8 --- /dev/null +++ b/src/TextLogging/YarpImplementation/src/YarpLogger.cpp @@ -0,0 +1,56 @@ +/** + * @file YarpLogger.cpp + * @authors Giulio Romualdi + * @copyright 2021 Istituto Italiano di Tecnologia (IIT). This software may be modified and + * distributed under the terms of the GNU Lesser General Public License v2.1 or any later version. + */ + +#include + +#include + +namespace BipedalLocomotion +{ + +template +inline std::shared_ptr YarpSink_mt(const std::string& loggerName) +{ + return Factory::template create(loggerName); +} + +std::shared_ptr _createLogger() +{ + auto logger = spdlog::get("blf"); + + // if the logger called blf already exist. If it does not exist it is created. + if (logger == nullptr) + { + // spdlog already handle the logger as singleton create the logger called blf + auto console = YarpSink_mt("blf"); + + // get the logger + logger = spdlog::get("blf"); + + // if the project is compiled in debug the level of spdlog is set in debug +#ifdef NDEBUG + logger->set_level(spdlog::level::info); +#else + logger->set_level(spdlog::level::debug); +#endif // NDEBUG + + // set the custom pattern + logger->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [thread: %t] [%n] %v"); + } + return logger; +} + +TextLogging::Logger* const TextLogging::YarpLoggerFactory::createLogger() +{ + // Since the oobject is static the memory is not deallocated + static std::shared_ptr logger(_createLogger()); + + // the logger exist because loggerCreation is called. + return logger.get(); +} + +} // namespace BipedalLocomotion diff --git a/src/TextLogging/include/BipedalLocomotion/TextLogging/DefaultLogger.h b/src/TextLogging/include/BipedalLocomotion/TextLogging/DefaultLogger.h new file mode 100644 index 0000000000..4c2acdb16e --- /dev/null +++ b/src/TextLogging/include/BipedalLocomotion/TextLogging/DefaultLogger.h @@ -0,0 +1,31 @@ +/** + * @file DefaultLogger.h + * @authors Giulio Romualdi + * @copyright 2021 Istituto Italiano di Tecnologia (IIT). This software may be modified and + * distributed under the terms of the GNU Lesser General Public License v2.1 or any later version. + */ + +#ifndef BIPEDAL_LOCOMOTION_TEXT_LOGGING_DEFAULT_LOGGER_FACTORY_H +#define BIPEDAL_LOCOMOTION_TEXT_LOGGING_DEFAULT_LOGGER_FACTORY_H + +#include + +namespace BipedalLocomotion +{ +namespace TextLogging +{ + +class DefaultLoggerFactory final : public LoggerFactory +{ +public: + /** + * Create the std clock as a singleton + * @return the reference to a System::StdClock + */ + Logger* const createLogger() final; +}; + +} // namespace TextLogging +} // namespace BipedalLocomotion + +#endif // BIPEDAL_LOCOMOTION_TEXT_LOGGING_DEFAULT_LOGGER_FACTORY_H diff --git a/src/TextLogging/include/BipedalLocomotion/TextLogging/Logger.h b/src/TextLogging/include/BipedalLocomotion/TextLogging/Logger.h index fe0ba4bb8d..a15466d6aa 100644 --- a/src/TextLogging/include/BipedalLocomotion/TextLogging/Logger.h +++ b/src/TextLogging/include/BipedalLocomotion/TextLogging/Logger.h @@ -19,7 +19,22 @@ namespace TextLogging { using Logger = spdlog::logger; +} // namespace TextLogging +} // namespace BipedalLocomotion + +namespace BipedalLocomotion +{ +/** + * Get an the instance of the log + */ +TextLogging::Logger* const log(); +} // namespace BipedalLocomotion + +namespace BipedalLocomotion +{ +namespace TextLogging +{ enum class Verbosity { Trace, @@ -38,13 +53,25 @@ enum class Verbosity */ void setVerbosity(const TextLogging::Verbosity verbosity); -} // namespace TextLogging - /** - * Get an the instance of the log + * LoggerFactory is an interface that implements the factory paradigm. Please inherit from + * LoggerFactory class if you want to build your custom Logger. */ -TextLogging::Logger* const log(); +class LoggerFactory +{ +public: + /** + * Destructor + */ + virtual ~LoggerFactory() = default; + /** + * Create a Logger + */ + virtual Logger* const createLogger() = 0; +}; + +} // namespace TextLogging } // namespace BipedalLocomotion #endif // BIPEDAL_LOCOMOTION_TEXT_LOGGING_LOGGER_H diff --git a/src/TextLogging/include/BipedalLocomotion/TextLogging/LoggerBuilder.h b/src/TextLogging/include/BipedalLocomotion/TextLogging/LoggerBuilder.h new file mode 100644 index 0000000000..8e6eef584c --- /dev/null +++ b/src/TextLogging/include/BipedalLocomotion/TextLogging/LoggerBuilder.h @@ -0,0 +1,58 @@ +/** + * @file LoggerBuilder.h + * @authors Giulio Romualdi + * @copyright 2021 Istituto Italiano di Tecnologia (IIT). This software may be modified and + * distributed under the terms of the GNU Lesser General Public License v2.1 or any later version. + */ + +#ifndef BIPEDAL_LOCOMOTION_TEXT_LOGGING_LOGGER_BUILDER_H +#define BIPEDAL_LOCOMOTION_TEXT_LOGGING_LOGGER_BUILDER_H + +#include + +#include +#include + +namespace BipedalLocomotion +{ +namespace TextLogging +{ + +/** + * LoggerBuilder is a class that implements the Builder paradigm. You can use the LoggerBuilder at + * the beginning of your application to set a different sink for spdlog. For instance, you can use + * the following example to enable the TextLogging with YARP + * \code{.cpp} + * #include + * #include + * #include + * + * // Change the logger + * BipedalLocomotion::TextLogging::LoggerBuilder::setFactory(std::make_shared()); + * + * BipedalLocomotion::log()->info("My info"); + * \endcode + */ +class LoggerBuilder +{ + /** + * Pointer to factory used to build the clock + */ + inline static std::shared_ptr m_factory{ + std::make_shared()}; + +public: + /** + * Set a custom factory. + * @param factory. A pointer to an existing factory. + * @return True in case success, false otherwise. + */ + static bool setFactory(std::shared_ptr factory); + + friend Logger* const ::BipedalLocomotion::log(); +}; + +}; // namespace TextLogging +} // namespace BipedalLocomotion + +#endif // BIPEDAL_LOCOMOTION_TEXT_LOGGING_LOGGER_BUILDER_H diff --git a/src/TextLogging/src/DefaultLogger.cpp b/src/TextLogging/src/DefaultLogger.cpp new file mode 100644 index 0000000000..61accb77c7 --- /dev/null +++ b/src/TextLogging/src/DefaultLogger.cpp @@ -0,0 +1,50 @@ +/** + * @file DefaultLogger.cpp + * @authors Giulio Romualdi + * @copyright 2021 Istituto Italiano di Tecnologia (IIT). This software may be modified and + * distributed under the terms of the GNU Lesser General Public License v2.1 or any later version. + */ + +#include + +#include +#include + +namespace BipedalLocomotion +{ + +std::shared_ptr _createLogger() +{ + auto logger = spdlog::get("blf"); + + // if the logger called blf already exist. If it does not exist it is created. + if (logger == nullptr) + { + // spdlog already handle the logger as singleton create the logger called blf + auto console = spdlog::stdout_color_mt("blf"); + + // get the logger + logger = spdlog::get("blf"); + + // if the project is compiled in debug the level of spdlog is set in debug +#ifdef NDEBUG + logger->set_level(spdlog::level::info); +#else + logger->set_level(spdlog::level::debug); +#endif // NDEBUG + + // set the custom pattern + logger->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [thread: %t] [%n] %^[%l]%$ %v"); + } + return logger; +} + +TextLogging::Logger* const TextLogging::DefaultLoggerFactory::createLogger() +{ + // Since the oobject is static the memory is not deallocated + static std::shared_ptr logger(_createLogger()); + + // the logger exist because loggerCreation is called. + return logger.get(); +} +} // namespace BipedalLocomotion diff --git a/src/TextLogging/src/Logger.cpp b/src/TextLogging/src/Logger.cpp index b14135b32b..2a949dd007 100644 --- a/src/TextLogging/src/Logger.cpp +++ b/src/TextLogging/src/Logger.cpp @@ -5,46 +5,17 @@ * distributed under the terms of the GNU Lesser General Public License v2.1 or any later version. */ -#include - #include +#include namespace BipedalLocomotion { -std::shared_ptr loggerCreation() -{ - auto logger = spdlog::get("blf"); - - // if the logger called blf already exist. If it does not exist it is created. - if (logger == nullptr) - { - // spdlog already handle the logger as singleton create the logger called blf - auto console = spdlog::stdout_color_mt("blf"); - - // get the logger - logger = spdlog::get("blf"); - - // if the project is compiled in debug the level of spdlog is set in debug -#ifdef NDEBUG - logger->set_level(spdlog::level::info); -#else - logger->set_level(spdlog::level::debug); -#endif // NDEBUG - - // set the custom pattern - logger->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [thread: %t] [%n] %^[%l]%$ %v"); - } - return logger; -} - TextLogging::Logger* const log() { - // Since the oobject is static the memory is not deallocated - static std::shared_ptr logger(loggerCreation()); - - // the logger exist because loggerCreation is called. - return logger.get(); + // m_factory is always initialized. + assert(BipedalLocomotion::TextLogging::LoggerBuilder::m_factory); + return BipedalLocomotion::TextLogging::LoggerBuilder::m_factory->createLogger(); } void TextLogging::setVerbosity(const Verbosity verbosity) diff --git a/src/TextLogging/src/LoggerBuilder.cpp b/src/TextLogging/src/LoggerBuilder.cpp new file mode 100644 index 0000000000..7b0989e45e --- /dev/null +++ b/src/TextLogging/src/LoggerBuilder.cpp @@ -0,0 +1,26 @@ +/** + * @file LoggerBuilder.cpp + * @authors Giulio Romualdi + * @copyright 2021 Istituto Italiano di Tecnologia (IIT). This software may be modified and + * distributed under the terms of the GNU Lesser General Public License v2.1 or any later version. + */ + +#include + +#include + +using namespace BipedalLocomotion::TextLogging; + +bool LoggerBuilder::setFactory(std::shared_ptr factory) +{ + constexpr auto logPrefix = "[LoggerBuilder::setFactory]"; + if (factory == nullptr) + { + // logger cannot be used here + std::cerr << logPrefix << " The factory is not valid." << std::endl; + return false; + } + + m_factory = factory; + return true; +}