Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the possibility to use spdlog with YARP #408

Merged
merged 3 commits into from
Sep 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
7 changes: 5 additions & 2 deletions src/TextLogging/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
14 changes: 14 additions & 0 deletions src/TextLogging/YarpImplementation/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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()
Original file line number Diff line number Diff line change
@@ -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 <memory>
#include <mutex>
#include <string>

#include <spdlog/common.h>
#include <spdlog/sinks/base_sink.h>

#include <BipedalLocomotion/TextLogging/Logger.h>

#include <yarp/os/LogStream.h>

namespace BipedalLocomotion
{
namespace TextLogging
{

namespace sinks
{

template <typename Mutex> class YarpSink : public spdlog::sinks::base_sink<Mutex>
{
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<Mutex>::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<std::mutex>;
} // 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 <BipedalLocomotion/TextLogging/Logger.h>
* #include <BipedalLocomotion/TextLogging/YarpLogger.h>
* #include <BipedalLocomotion/TextLogging/LoggerBuilder.h>
*
* // Change the logger
* BipedalLocomotion::TextLogging::LoggerBuilder::setFactory(std::make_shared<BipedalLocomotion::TextLogging::YarpLoggerFactory>()));
*
* 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
56 changes: 56 additions & 0 deletions src/TextLogging/YarpImplementation/src/YarpLogger.cpp
Original file line number Diff line number Diff line change
@@ -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 <mutex>

#include <BipedalLocomotion/TextLogging/YarpLogger.h>

namespace BipedalLocomotion
{

template <typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<TextLogging::Logger> YarpSink_mt(const std::string& loggerName)
{
return Factory::template create<TextLogging::sinks::YarpSink_mt>(loggerName);
}

std::shared_ptr<TextLogging::Logger> _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<TextLogging::Logger> logger(_createLogger());

// the logger exist because loggerCreation is called.
return logger.get();
}

} // namespace BipedalLocomotion
Original file line number Diff line number Diff line change
@@ -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 <BipedalLocomotion/TextLogging/Logger.h>

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
35 changes: 31 additions & 4 deletions src/TextLogging/include/BipedalLocomotion/TextLogging/Logger.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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
Original file line number Diff line number Diff line change
@@ -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 <memory>

#include <BipedalLocomotion/TextLogging/DefaultLogger.h>
#include <BipedalLocomotion/TextLogging/Logger.h>

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 <BipedalLocomotion/TextLogging/Logger.h>
* #include <BipedalLocomotion/TextLogging/YarpLogger.h>
* #include <BipedalLocomotion/TextLogging/LoggerBuilder.h>
*
* // Change the logger
* BipedalLocomotion::TextLogging::LoggerBuilder::setFactory(std::make_shared<BipedalLocomotion::TextLogging::YarpLoggerFactory>());
*
* BipedalLocomotion::log()->info("My info");
* \endcode
*/
class LoggerBuilder
{
/**
* Pointer to factory used to build the clock
*/
inline static std::shared_ptr<LoggerFactory> m_factory{
std::make_shared<DefaultLoggerFactory>()};

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<LoggerFactory> factory);

friend Logger* const ::BipedalLocomotion::log();
};

}; // namespace TextLogging
} // namespace BipedalLocomotion

#endif // BIPEDAL_LOCOMOTION_TEXT_LOGGING_LOGGER_BUILDER_H
50 changes: 50 additions & 0 deletions src/TextLogging/src/DefaultLogger.cpp
Original file line number Diff line number Diff line change
@@ -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 <spdlog/sinks/stdout_color_sinks.h>

#include <BipedalLocomotion/TextLogging/DefaultLogger.h>
#include <BipedalLocomotion/TextLogging/Logger.h>

namespace BipedalLocomotion
{

std::shared_ptr<TextLogging::Logger> _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<TextLogging::Logger> logger(_createLogger());

// the logger exist because loggerCreation is called.
return logger.get();
}
} // namespace BipedalLocomotion
Loading