...
 
Commits (11)
......@@ -98,6 +98,7 @@ SET(${PROJECT_NAME}_HEADERS
include/dynamic-graph/fwd.hh
include/dynamic-graph/debug.h
include/dynamic-graph/real-time-logger.h
include/dynamic-graph/real-time-logger-def.h
include/dynamic-graph/dynamic-graph-api.h
......
......@@ -83,12 +83,16 @@ public:
SignalMap getSignalMap() const;
/** \name Logger related methods */
/** \{*/
/// \name Logger related methods
/// \{
Logger &logger() { return logger_; };
Logger const &logger() const { return logger_; };
/// \brief Send messages \c msg with level \c t.
/// Add string file and line to message.
void sendMsg(const std::string &msg, MsgType t = MSG_TYPE_INFO,
const char *file = "", int line = 0);
const std::string &lineId = "");
/// \brief Specify the verbosity level of the logger.
void setLoggerVerbosityLevel(LoggerVerbosity lv) { logger_.setVerbosity(lv); }
......@@ -110,6 +114,8 @@ public:
/// \brief Get the period of the stream period
double getStreamPrintPeriod() { return logger_.getStreamPrintPeriod(); }
/// \}
protected:
void addCommand(const std::string &name, command::Command *command);
......
......@@ -27,14 +27,17 @@ namespace dynamicgraph {
/** Enum representing the different kind of messages.
*/
enum MsgType {
MSG_TYPE_DEBUG = 0,
MSG_TYPE_INFO = 1,
MSG_TYPE_WARNING = 2,
MSG_TYPE_ERROR = 3,
MSG_TYPE_DEBUG_STREAM = 4,
MSG_TYPE_INFO_STREAM = 5,
MSG_TYPE_WARNING_STREAM = 6,
MSG_TYPE_ERROR_STREAM = 7
MSG_TYPE_TYPE_BITS = 1<<0 | 1<<1 | 1<<2 | 1<<3, // 15
MSG_TYPE_STREAM_BIT = 1<<4, // 16
MSG_TYPE_DEBUG = 1<<3, // 1
MSG_TYPE_INFO = 1<<2, // 2
MSG_TYPE_WARNING = 1<<1, // 4
MSG_TYPE_ERROR = 1<<0, // 8
MSG_TYPE_DEBUG_STREAM = MSG_TYPE_DEBUG | MSG_TYPE_STREAM_BIT, // 17
MSG_TYPE_INFO_STREAM = MSG_TYPE_INFO | MSG_TYPE_STREAM_BIT, // 18
MSG_TYPE_WARNING_STREAM = MSG_TYPE_WARNING | MSG_TYPE_STREAM_BIT, // 20
MSG_TYPE_ERROR_STREAM = MSG_TYPE_ERROR | MSG_TYPE_STREAM_BIT // 24
};
} // namespace dynamicgraph
......@@ -42,25 +45,54 @@ enum MsgType {
/* --- INCLUDE --------------------------------------------------------- */
/* --------------------------------------------------------------------- */
#include "boost/assign.hpp"
#include <dynamic-graph/linear-algebra.h>
#include <map>
/// \todo These 3 headers should be removed.
#include <fstream>
#include <iomanip> // std::setprecision
#include <map>
#include <sstream>
#include <boost/assign.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <dynamic-graph/deprecated.hh>
#include <dynamic-graph/linear-algebra.h>
#include <dynamic-graph/real-time-logger-def.h>
namespace dynamicgraph {
//#define LOGGER_VERBOSITY_INFO_WARNING_ERROR
#define LOGGER_VERBOSITY_ALL
#define SEND_MSG(msg, type) sendMsg(msg, type, __FILE__, __LINE__)
#define SEND_MSG(msg, type) \
sendMsg(msg, type, __FILE__ ":" BOOST_PP_STRINGIZE(__LINE__))
#define SEND_DEBUG_STREAM_MSG(msg) SEND_MSG(msg, MSG_TYPE_DEBUG_STREAM)
#define SEND_INFO_STREAM_MSG(msg) SEND_MSG(msg, MSG_TYPE_INFO_STREAM)
#define SEND_WARNING_STREAM_MSG(msg) SEND_MSG(msg, MSG_TYPE_WARNING_STREAM)
#define SEND_ERROR_STREAM_MSG(msg) SEND_MSG(msg, MSG_TYPE_ERROR_STREAM)
#define _DYNAMIC_GRAPH_ENTITY_MSG(entity, type) \
(entity).logger().stream(type, __FILE__ BOOST_PP_STRINGIZE(__LINE__))
#define DYNAMIC_GRAPH_ENTITY_DEBUG(entity) \
_DYNAMIC_GRAPH_ENTITY_MSG(entity, MSG_TYPE_DEBUG)
#define DYNAMIC_GRAPH_ENTITY_INFO(entity) \
_DYNAMIC_GRAPH_ENTITY_MSG(entity, MSG_TYPE_INFO)
#define DYNAMIC_GRAPH_ENTITY_WARNING(entity) \
_DYNAMIC_GRAPH_ENTITY_MSG(entity, MSG_TYPE_WARNING)
#define DYNAMIC_GRAPH_ENTITY_ERROR(entity) \
_DYNAMIC_GRAPH_ENTITY_MSG(entity, MSG_TYPE_ERROR)
#define DYNAMIC_GRAPH_ENTITY_DEBUG_STREAM(entity) \
_DYNAMIC_GRAPH_ENTITY_MSG(entity, MSG_TYPE_DEBUG_STREAM)
#define DYNAMIC_GRAPH_ENTITY_INFO_STREAM(entity) \
_DYNAMIC_GRAPH_ENTITY_MSG(entity, MSG_TYPE_INFO_STREAM)
#define DYNAMIC_GRAPH_ENTITY_WARNING_STREAM(entity) \
_DYNAMIC_GRAPH_ENTITY_MSG(entity, MSG_TYPE_WARNING_STREAM)
#define DYNAMIC_GRAPH_ENTITY_ERROR_STREAM(entity) \
_DYNAMIC_GRAPH_ENTITY_MSG(entity, MSG_TYPE_ERROR_STREAM)
template <typename T>
std::string toString(const T &v, const int precision = 3,
const int width = -1) {
......@@ -111,11 +143,11 @@ std::string toString(const Eigen::MatrixBase<T> &v, const int precision = 3,
}
enum LoggerVerbosity {
VERBOSITY_ALL,
VERBOSITY_INFO_WARNING_ERROR,
VERBOSITY_WARNING_ERROR,
VERBOSITY_ERROR,
VERBOSITY_NONE
VERBOSITY_ALL = MSG_TYPE_DEBUG,
VERBOSITY_INFO_WARNING_ERROR = MSG_TYPE_INFO,
VERBOSITY_WARNING_ERROR = MSG_TYPE_WARNING,
VERBOSITY_ERROR = MSG_TYPE_ERROR,
VERBOSITY_NONE = 0
};
/// \ingroup debug
......@@ -139,12 +171,20 @@ enum LoggerVerbosity {
/// VERBOSITY_WARNING_ERROR;
/// entity.setLoggerVerbosityLevel(aLoggerVerbosityLevel);
/// ...
/// std::string aMsg=aBaseMsg+" WARNING";
/// entity.sendMsg(aMsg,dynamicgraph::MSG_TYPE_WARNING, __FILE__,__LINE__);
/// // using macros
/// DYNAMIC_GRAPH_ENTITY_WARNING(entity) << "your message\n";
///
/// \endcode
/// // or the equivalent code without macros:
/// // Please use '\n' instead of std::endl and flushing will have no effect
/// entity.logger.stream(dynamicgraph::MSG_TYPE_WARNING,
/// __FILE__ BOOST_PP_STRINGIZE(__LINE__))
/// << your message << '\n';
///
/// \endcode
///
/// \todo remove m_timeSample and streamPrintPeriod to rather use a simple
/// integer counting the number of calls. This will achieve exactly the
/// same behaviour without rouding numerical errors.
class Logger {
public:
/** Constructor */
......@@ -157,13 +197,39 @@ public:
* to decrement the internal Logger's counter. */
void countdown();
/** Get an output stream independently of the debug level.
*/
RTLoggerStream stream() {
return ::dynamicgraph::RealTimeLogger::instance().front();
}
/** Print the specified message on standard output if the verbosity level
* allows it. The file name and the line number are used to identify
* the point where sendMsg is called so that streaming messages are
* printed only every streamPrintPeriod iterations.
* allows it. The lineId is used to identify the point where sendMsg is
* called so that streaming messages are printed only every streamPrintPeriod
* iterations.
* \param lineId typically __FILE__ ":" BOOST_PP_STRINGIZE(__LINE__)
*/
RTLoggerStream stream(MsgType type, const std::string& lineId = "") {
RealTimeLogger &rtlogger = ::dynamicgraph::RealTimeLogger::instance();
if (acceptMsg(type, lineId))
return rtlogger.front();
return rtlogger.emptyStream();
}
/** \deprecated instead, use
* \code
* stream(type, lineId) << msg << '\n';
* \endcode
*/
void sendMsg(std::string msg, MsgType type, const char *file = "",
int line = 0);
void sendMsg(std::string msg, MsgType type, const std::string& lineId = "");
/** \deprecated instead, use
* \code
* stream(type, lineId) << msg << '\n';
* \endcode
*/
void sendMsg(std::string msg, MsgType type, const std::string& file,
int line) DYNAMIC_GRAPH_DEPRECATED;
/** Set the sampling time at which the method countdown()
* is going to be called. */
......@@ -193,30 +259,33 @@ protected:
double m_printCountdown;
/// every time this is < 0 (i.e. every _streamPrintPeriod sec) print stuff
typedef std::map<std::string, double> StreamCounterMap_t;
/** Pointer to the dynamic structure which holds
the collection of streaming messages */
std::map<std::string, double> m_stream_msg_counters;
StreamCounterMap_t m_stream_msg_counters;
bool isStreamMsg(MsgType m) {
return m == MSG_TYPE_ERROR_STREAM || m == MSG_TYPE_DEBUG_STREAM ||
m == MSG_TYPE_INFO_STREAM || m == MSG_TYPE_WARNING_STREAM;
inline bool isStreamMsg(MsgType m) {
return (m & MSG_TYPE_STREAM_BIT);
}
bool isDebugMsg(MsgType m) {
return m == MSG_TYPE_DEBUG_STREAM || m == MSG_TYPE_DEBUG;
}
bool isInfoMsg(MsgType m) {
return m == MSG_TYPE_INFO_STREAM || m == MSG_TYPE_INFO;
}
bool isWarningMsg(MsgType m) {
return m == MSG_TYPE_WARNING_STREAM || m == MSG_TYPE_WARNING;
/** Check whether a message of type \m and from \c lineId should be accepted.
* \note If \c is a stream type, the internal counter associated to \c lineId
* is updated.
*/
bool acceptMsg (MsgType m, const std::string& lineId) {
// If more verbose than the current verbosity level
if ((m & MSG_TYPE_TYPE_BITS) > m_lv)
return false;
// if print is allowed by current verbosity level
if (isStreamMsg(m)) return checkStreamPeriod(lineId);
return true;
}
bool isErrorMsg(MsgType m) {
return m == MSG_TYPE_ERROR_STREAM || m == MSG_TYPE_ERROR;
}
/** Check whether a message from \c lineId should be accepted.
* \note The internal counter associated to \c lineId is updated.
*/
bool checkStreamPeriod (const std::string& lineId);
};
} // namespace dynamicgraph
......
// -*- mode: c++ -*-
// Copyright 2018, Joseph Mirabel LAAS-CNRS
//
#ifndef DYNAMIC_GRAPH_LOGGER_REAL_TIME_DEF_H
#define DYNAMIC_GRAPH_LOGGER_REAL_TIME_DEF_H
#include <sstream>
#include <vector>
#include <boost/shared_ptr.hpp>
#include <boost/thread/mutex.hpp>
#include <dynamic-graph/config.hh>
namespace dynamicgraph {
/// \ingroup debug
///
/// \brief Stream for the real-time logger.
///
/// You should inherit from this class in order to redirect the logs where you
/// want.
/// \sa LoggerIOStream
class LoggerStream {
public:
virtual void write(const char *c) = 0;
};
/// Write to an ostream object.
///
/// The easieast is to use the macro \ref dgADD_OSTREAM_TO_RTLOG(ostr) where
/// `ostr` can be `std::cout` or an std::ofstream...
class LoggerIOStream : public LoggerStream {
public:
LoggerIOStream(std::ostream &os) : os_(os) {}
virtual void write(const char *c) { os_ << c; }
private:
std::ostream &os_;
};
typedef boost::shared_ptr<LoggerStream> LoggerStreamPtr_t;
class RealTimeLogger;
/// \cond DEVEL
/// \brief write entries to intenal buffer.
///
/// The entry starts when an instance is created and ends when is is deleted.
/// This class is only used by RealTimeLogger.
class RTLoggerStream {
public:
inline RTLoggerStream(RealTimeLogger *logger, std::ostream &os)
: ok_(logger != NULL), logger_(logger), os_(os) {}
template <typename T> inline RTLoggerStream &operator<<(T t) {
if (ok_)
os_ << t;
return *this;
}
inline RTLoggerStream &operator<<(std::ostream &(*pf)(std::ostream &)) {
if (ok_)
os_ << pf;
return *this;
}
inline ~RTLoggerStream();
inline bool isNull() { return !ok_; }
private:
const bool ok_;
RealTimeLogger *logger_;
std::ostream &os_;
};
/// \endcond DEVEL
/// \ingroup debug
///
/// \brief Main class of the real-time logger.
///
/// It is intended to be used like this:
/// \code
/// #define ENABLE_RT_LOG
/// #include <dynamic-graph/real-time-logger.h>
///
/// // Somewhere in the main function of your executable
/// int main (int argc, char** argv) {
/// dgADD_OSTREAM_TO_RTLOG (std::cout);
/// }
///
/// // Somewhere in your library
/// dgRTLOG() << "your message. Prefer to use \n than std::endl."
/// \endcode
///
/// \note Thread safety. This class expects to have:
/// - only one reader: the one who take the log entries and write them
/// somewhere.
/// - one writer at a time. Writing to the logs is **never** a blocking
/// operation. If the resource is busy, the log entry is discarded.
class DYNAMIC_GRAPH_DLLAPI RealTimeLogger {
public:
static RealTimeLogger &instance();
static void destroy();
/// \todo add an argument to preallocate the internal string
/// to a given size.
RealTimeLogger(const std::size_t &bufferSize);
inline void clearOutputStreams() { outputs_.clear(); }
inline void addOutputStream(const LoggerStreamPtr_t &os) {
outputs_.push_back(os);
}
/// Write next message to output.
/// It does nothing if the buffer is empty.
/// \return true if it wrote something
bool spinOnce();
/// Return an object onto which a real-time thread can write.
/// The message is considered finished when the object is destroyed.
RTLoggerStream front();
/// Return an empty stream object.
RTLoggerStream emptyStream() { return RTLoggerStream(NULL, oss_); }
inline void frontReady() {
backIdx_ = (backIdx_ + 1) % buffer_.size();
wmutex.unlock();
}
inline bool empty() const { return frontIdx_ == backIdx_; }
inline bool full() const {
return ((backIdx_ + 1) % buffer_.size()) == frontIdx_;
}
inline std::size_t size() const {
if (frontIdx_ <= backIdx_)
return backIdx_ - frontIdx_;
else
return backIdx_ + buffer_.size() - frontIdx_;
}
inline std::size_t getBufferSize() { return buffer_.size(); }
~RealTimeLogger();
private:
struct Data {
std::stringbuf buf;
};
std::vector<LoggerStreamPtr_t> outputs_;
std::vector<Data *> buffer_;
/// Index of the next value to be read.
std::size_t frontIdx_;
/// Index of the slot where to write next value
/// (does not contain valid data).
std::size_t backIdx_;
std::ostream oss_;
/// The writer mutex.
boost::mutex wmutex;
std::size_t nbDiscarded_;
struct thread;
static RealTimeLogger *instance_;
static thread *thread_;
};
RTLoggerStream::~RTLoggerStream() {
if (ok_) {
os_ << std::ends;
logger_->frontReady();
}
}
} // end of namespace dynamicgraph
#endif //! DYNAMIC_GRAPH_LOGGER_REAL_TIME_DEF_H
......@@ -4,167 +4,6 @@
#ifndef DYNAMIC_GRAPH_LOGGER_REAL_TIME_H
#define DYNAMIC_GRAPH_LOGGER_REAL_TIME_H
#include <sstream>
#include <vector>
#include <boost/circular_buffer.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread/mutex.hpp>
#include <dynamic-graph/config.hh>
#include <dynamic-graph/debug.h>
namespace dynamicgraph {
/// \ingroup debug
///
/// \brief Stream for the real-time logger.
///
/// You should inherit from this class in order to redirect the logs where you
/// want.
/// \sa LoggerIOStream
class LoggerStream {
public:
virtual void write(const char *c) = 0;
};
/// Write to an ostream object.
///
/// The easieast is to use the macro \ref dgADD_OSTREAM_TO_RTLOG(ostr) where
/// `ostr` can be `std::cout` or an std::ofstream...
class LoggerIOStream : public LoggerStream {
public:
LoggerIOStream(std::ostream &os) : os_(os) {}
virtual void write(const char *c) { os_ << c; }
private:
std::ostream &os_;
};
typedef boost::shared_ptr<LoggerStream> LoggerStreamPtr_t;
class RealTimeLogger;
/// \cond DEVEL
/// \brief write entries to intenal buffer.
///
/// The entry starts when an instance is created and ends when is is deleted.
/// This class is only used by RealTimeLogger.
class RTLoggerStream {
public:
RTLoggerStream(RealTimeLogger *logger, std::ostream &os)
: logger_(logger), os_(os) {}
template <typename T> inline RTLoggerStream &operator<<(T t) {
if (logger_ != NULL)
os_ << t;
return *this;
}
inline RTLoggerStream &operator<<(std::ostream &(*pf)(std::ostream &)) {
if (logger_ != NULL)
os_ << pf;
return *this;
}
~RTLoggerStream();
private:
RealTimeLogger *logger_;
std::ostream &os_;
};
/// \endcond DEVEL
/// \ingroup debug
///
/// \brief Main class of the real-time logger.
///
/// It is intended to be used like this:
/// \code
/// #define ENABLE_RT_LOG
/// #include <dynamic-graph/real-time-logger.h>
///
/// // Somewhere in the main function of your executable
/// int main (int argc, char** argv) {
/// dgADD_OSTREAM_TO_RTLOG (std::cout);
/// }
///
/// // Somewhere in your library
/// dgRTLOG() << "your message. Prefer to use \n than std::endl."
/// \endcode
///
/// \note Thread safety. This class expects to have:
/// - only one reader: the one who take the log entries and write them
/// somewhere.
/// - one writer at a time. Writing to the logs is **never** a blocking
/// operation. If the resource is busy, the log entry is discarded.
class DYNAMIC_GRAPH_DLLAPI RealTimeLogger {
public:
static RealTimeLogger &instance();
static void destroy();
/// \todo add an argument to preallocate the internal string
/// to a given size.
RealTimeLogger(const std::size_t &bufferSize);
inline void clearOutputStreams() { outputs_.clear(); }
inline void addOutputStream(const LoggerStreamPtr_t &os) {
outputs_.push_back(os);
}
/// Write next message to output.
/// It does nothing if the buffer is empty.
/// \return true if it wrote something
bool spinOnce();
/// Return an object onto which a real-time thread can write.
/// The message is considered finished when the object is destroyed.
RTLoggerStream front();
inline void frontReady() {
backIdx_ = (backIdx_ + 1) % buffer_.size();
wmutex.unlock();
}
inline bool empty() const { return frontIdx_ == backIdx_; }
inline bool full() const {
return ((backIdx_ + 1) % buffer_.size()) == frontIdx_;
}
inline std::size_t size() const {
if (frontIdx_ <= backIdx_)
return backIdx_ - frontIdx_;
else
return backIdx_ + buffer_.size() - frontIdx_;
}
inline std::size_t getBufferSize() { return buffer_.size(); }
~RealTimeLogger();
private:
struct Data {
std::stringbuf buf;
};
std::vector<LoggerStreamPtr_t> outputs_;
std::vector<Data *> buffer_;
/// Index of the next value to be read.
std::size_t frontIdx_;
/// Index of the slot where to write next value
/// (does not contain valid data).
std::size_t backIdx_;
std::ostream oss_;
/// The writer mutex.
boost::mutex wmutex;
std::size_t nbDiscarded_;
struct thread;
static RealTimeLogger *instance_;
static thread *thread_;
};
} // end of namespace dynamicgraph
#ifdef ENABLE_RT_LOG
#define dgADD_OSTREAM_TO_RTLOG(ostr) \
......@@ -182,4 +21,6 @@ private:
__null_stream()
#endif
#include <dynamic-graph/real-time-logger-def.h>
#endif //! DYNAMIC_GRAPH_LOGGER_REAL_TIME_H
......@@ -12,10 +12,13 @@
#include <dynamic-graph/linear-algebra.h>
#include <string>
#include <typeinfo>
#include <vector>
namespace dynamicgraph {
namespace command {
class Value;
typedef std::vector<Value> Values;
class DYNAMIC_GRAPH_DLLAPI EitherType {
public:
EitherType(const Value &value);
......@@ -29,6 +32,7 @@ public:
operator Vector() const;
operator Eigen::MatrixXd() const;
operator Eigen::Matrix4d() const;
operator Values() const;
private:
const Value *value_;
......@@ -47,6 +51,7 @@ public:
VECTOR,
MATRIX,
MATRIX4D,
VALUES,
NB_TYPES
};
~Value();
......@@ -60,12 +65,15 @@ public:
explicit Value(const Vector &value);
explicit Value(const Eigen::MatrixXd &value);
explicit Value(const Eigen::Matrix4d &value);
explicit Value(const Values &value);
/// Copy constructor
Value(const Value &value);
// Construct an empty value (None)
explicit Value();
// operator assignement
Value operator=(const Value &value);
// Equality operator
bool operator==(const Value &other) const;
/// Return the type of the value
Type type() const;
......@@ -99,6 +107,8 @@ public:
Vector vectorValue() const;
Eigen::MatrixXd matrixXdValue() const;
Eigen::Matrix4d matrix4dValue() const;
Values valuesValue () const;
const Values &constValuesValue () const;
Type type_;
const void *const value_;
};
......
# Copyright 2010, Olivier Stasse, JRL, CNRS/AIST
#
####################################
### Main Library
####################################
SET(LIBRARY_NAME ${PROJECT_NAME})
# Verbosity level
IF (NOT (\"${CMAKE_VERBOSITY_LEVEL}\" STREQUAL \"\"))
ADD_DEFINITIONS(-DVP_DEBUG_MODE=${CMAKE_VERBOSITY_LEVEL} -DVP_DEBUG)
ENDIF (NOT (\"${CMAKE_VERBOSITY_LEVEL}\" STREQUAL \"\"))
# Declare boost include directories
#include_directories(${Boost_INCLUDE_DIRS})
#link_directories(${Boost_LIBRARY_DIRS})
ADD_LIBRARY(${LIBRARY_NAME}
SHARED
debug/debug.cpp
debug/real-time-logger.cpp
debug/logger.cpp
dgraph/entity.cpp
dgraph/factory.cpp
dgraph/pool.cpp
exception/exception-abstract.cpp
exception/exception-factory.cpp
exception/exception-signal.cpp
exception/exception-traces.cpp
mt/process-list.cpp
signal/signal-array.cpp
signal/signal-caster.cpp
signal/signal-cast-helper.cpp
command/value.cpp
command/command.cpp
)
# INSTALL(TARGETS ${PROJECT_NAME}
# EXPORT ${TARGETS_EXPORT_NAME}
# PUBLIC_HEADER
# INCLUDES DESTINATION include/${PROJECT_NAME}
# )
target_include_directories(${PROJECT_NAME}
PUBLIC
$<INSTALL_INTERFACE:include>
)
SET_TARGET_PROPERTIES(${LIBRARY_NAME} PROPERTIES SOVERSION ${PROJECT_VERSION})
IF (UNIX)
TARGET_LINK_LIBRARIES(${LIBRARY_NAME} ${CMAKE_DL_LIBS} pthread)
ENDIF (UNIX)
TARGET_LINK_LIBRARIES(${LIBRARY_NAME} ${Boost_LIBRARIES})
TARGET_LINK_LIBRARIES(${LIBRARY_NAME} Eigen3::Eigen)
#IF (UNIX AND NOT APPLE)
# TARGET_LINK_LIBRARIES(${LIBRARY_NAME} ${JRL_MAL_LDFLAGS_OTHER})
#ENDIF (UNIX AND NOT APPLE)
INSTALL(TARGETS ${LIBRARY_NAME}
EXPORT ${TARGETS_EXPORT_NAME}
DESTINATION ${CMAKE_INSTALL_LIBDIR})
####################################
### Plugins
####################################
SET(plugins_list
traces/tracer
traces/tracer-real-time
)
SET(tracer-real-time_dependency tracer)
FOREACH(plugin_file ${plugins_list})
GET_FILENAME_COMPONENT(plugin ${plugin_file} NAME)
ADD_LIBRARY(${plugin} SHARED "${plugin_file}.cpp")
TARGET_LINK_LIBRARIES(${plugin}
${PROJECT_NAME} ${${plugin}_dependency}
${Boost_LIBRARIES})
SET_TARGET_PROPERTIES(${plugin}
PROPERTIES
PREFIX ""
)
INSTALL(TARGETS ${plugin} EXPORT ${TARGET_NAME} DESTINATION ${PLUGINDIR})
ENDFOREACH(plugin_file)
......@@ -29,6 +29,7 @@ EitherType::operator Vector() const { return value_->vectorValue(); }
EitherType::operator Eigen::MatrixXd() const { return value_->matrixXdValue(); }
EitherType::operator Eigen::Matrix4d() const { return value_->matrix4dValue(); }
EitherType::operator Values() const { return value_->valuesValue(); }
void Value::deleteValue() {
switch (type_) {
......@@ -59,6 +60,9 @@ void Value::deleteValue() {
case MATRIX4D:
delete (const Eigen::Matrix4d *)value_;
break;
case VALUES:
delete (const Values *)value_;
break;
default:;
}
}
......@@ -78,6 +82,8 @@ Value::Value(const Eigen::MatrixXd &value)
: type_(MATRIX), value_(new Eigen::MatrixXd(value)) {}
Value::Value(const Eigen::Matrix4d &value)
: type_(MATRIX4D), value_(new Eigen::Matrix4d(value)) {}
Value::Value(const Values &value)
: type_(VALUES), value_(new Values(value)) {}
Value::Value(const Value &value)
: type_(value.type_), value_(copyValue(value)) {}
......@@ -116,6 +122,9 @@ void *copyValue(const Value &value) {
case Value::MATRIX4D:
copy = new Eigen::Matrix4d(value.matrix4dValue());
break;
case Value::VALUES:
copy = new Values(value.valuesValue());
break;
default:
abort();
}
......@@ -135,6 +144,25 @@ Value Value::operator=(const Value &value) {
return *this;
}
bool Value::operator==(const Value &other) const {
if (type_ != other.type_) return false;
switch (type_) {
case Value::BOOL: return boolValue() == other.boolValue();
case Value::UNSIGNED: return unsignedValue() == other.unsignedValue();
case Value::INT: return intValue() == other.intValue();
case Value::DOUBLE: return doubleValue() == other.doubleValue();
case Value::FLOAT: return floatValue() == other.floatValue();
case Value::STRING: return stringValue() == other.stringValue();
case Value::VECTOR: return vectorValue() == other.vectorValue();
case Value::MATRIX: return matrixXdValue() == other.matrixXdValue();
case Value::MATRIX4D: return matrix4dValue() == other.matrix4dValue();
case Value::VALUES: return constValuesValue() == other.constValuesValue();
case Value::NONE: break;
default: break;
}
return false;
}
const EitherType Value::value() const { return EitherType(*this); }
Value::Type Value::type() const { return type_; }
......@@ -200,6 +228,20 @@ Eigen::Matrix4d Value::matrix4dValue() const {
"value is not a Eigen matrix4d");
}
Values Value::valuesValue() const {
if (type_ == VALUES)
return *((const Values *)value_);
throw ExceptionAbstract(ExceptionAbstract::TOOLS,
"value is not a vector of Value");
}
const Values &Value::constValuesValue() const {
if (type_ == VALUES)
return *((const Values *)value_);
throw ExceptionAbstract(ExceptionAbstract::TOOLS,
"value is not a vector of Value");
}
std::string Value::typeName(Type type) {
switch (type) {
case BOOL:
......@@ -220,6 +262,8 @@ std::string Value::typeName(Type type) {
return std::string("matrixXd");
case MATRIX4D:
return std::string("matrix4d");
case VALUES:
return std::string("values");
default:
return std::string("unknown");
}
......@@ -255,6 +299,15 @@ std::ostream &operator<<(std::ostream &os, const Value &value) {
case Value::MATRIX4D:
os << value.matrix4dValue();
break;
case Value::VALUES:
{
const std::vector<Value>& vals = value.constValuesValue();
os << "[ ";
for (std::size_t i = 0; i < vals.size(); ++i)
os << "Value(" << vals[i] << "), ";
os << "]";
}
break;
default:
return os;
}
......@@ -272,6 +325,7 @@ template <>
const Value::Type ValueHelper<Eigen::MatrixXd>::TypeID = Value::MATRIX;
template <>
const Value::Type ValueHelper<Eigen::Matrix4d>::TypeID = Value::MATRIX4D;
template <> const Value::Type ValueHelper<Values>::TypeID = Value::VALUES;
} // namespace command
} // namespace dynamicgraph
......@@ -22,8 +22,6 @@
namespace dynamicgraph {
using namespace std;
Logger::Logger(double timeSample, double streamPrintPeriod)
: m_timeSample(timeSample), m_streamPrintPeriod(streamPrintPeriod),
m_printCountdown(0.0) {
......@@ -41,38 +39,15 @@ void Logger::countdown() {
m_printCountdown -= m_timeSample;
}
void Logger::sendMsg(string msg, MsgType type, const char *file, int line) {
if (m_lv == VERBOSITY_NONE ||
(m_lv == VERBOSITY_ERROR && !isErrorMsg(type)) ||
(m_lv == VERBOSITY_WARNING_ERROR &&
!(isWarningMsg(type) || isErrorMsg(type))) ||
(m_lv == VERBOSITY_INFO_WARNING_ERROR && isDebugMsg(type)))
return;
// if print is allowed by current verbosity level
if (isStreamMsg(type)) {
// check whether counter already exists
std::ostringstream oss;
oss << file << line;
std::string id(oss.str());
map<string, double>::iterator it = m_stream_msg_counters.find(id);
if (it == m_stream_msg_counters.end()) {
// if counter doesn't exist then add one
m_stream_msg_counters.insert(make_pair(id, 0.0));
it = m_stream_msg_counters.find(id);
}
// if counter is greater than 0 then decrement it and do not print
if (it->second > 0.0) {
it->second -= m_timeSample;
if (it->second <= 0.0)
it->second = m_streamPrintPeriod;
else
return;
} else // otherwise reset counter and print
it->second = m_streamPrintPeriod;
}
dgRTLOG() << msg.c_str() << "\n";
void Logger::sendMsg(std::string msg, MsgType type, const std::string &lineId) {
stream(type, lineId) << msg << '\n';
}
void Logger::sendMsg(std::string msg, MsgType type, const std::string &file,
int line) {
std::ostringstream oss;
oss << file << line;
stream(type, oss.str()) << msg << '\n';
}
bool Logger::setTimeSample(double t) {
......@@ -92,4 +67,21 @@ bool Logger::setStreamPrintPeriod(double s) {
double Logger::getTimeSample() { return m_timeSample; }
double Logger::getStreamPrintPeriod() { return m_streamPrintPeriod; }
bool Logger::checkStreamPeriod(const std::string &lineId) {
// insert element with value 0 if it does not exist.
// otherwise, return a counter to the existing one.
std::pair<StreamCounterMap_t::iterator, bool> result =
m_stream_msg_counters.insert(std::make_pair(lineId, 0.));
// if counter is greater than 0 then decrement it and do not print
double &counter = result.first->second;
counter -= m_timeSample;
if (counter > 0.0) {
return false;
} else // otherwise reset counter and print
counter = m_streamPrintPeriod;
return true;
}
} // namespace dynamicgraph
......@@ -59,12 +59,6 @@ RTLoggerStream RealTimeLogger::front() {
return RTLoggerStream(this, oss_);
}
RTLoggerStream::~RTLoggerStream() {
os_ << std::ends;
if (logger_ != NULL)
logger_->frontReady();
}
struct RealTimeLogger::thread {
bool requestShutdown_;
int threadPolicy_;
......
......@@ -207,7 +207,7 @@ Command *Entity::getNewStyleCommand(const std::string &commandName) {
return commandMap[commandName];
}
void Entity::sendMsg(const std::string &msg, MsgType t, const char *file,
int line) {
logger_.sendMsg("[" + name + "]" + msg, t, file, line);
void Entity::sendMsg(const std::string &msg, MsgType t,
const std::string &lineId) {
logger_.sendMsg("[" + name + "]" + msg, t, lineId);
}
......@@ -31,38 +31,86 @@ public:
explicit CustomEntity(const std::string &n) : Entity(n) {
logger_.setTimeSample(0.001);
logger_.setStreamPrintPeriod(0.005);
logger_.setVerbosity(VERBOSITY_NONE);
BOOST_CHECK_EQUAL(logger_.getVerbosity(), VERBOSITY_NONE);
BOOST_CHECK( logger_.stream(MSG_TYPE_DEBUG ).isNull());
BOOST_CHECK( logger_.stream(MSG_TYPE_INFO ).isNull());
BOOST_CHECK( logger_.stream(MSG_TYPE_WARNING).isNull());
BOOST_CHECK( logger_.stream(MSG_TYPE_ERROR ).isNull());
logger_.setVerbosity(VERBOSITY_ERROR);
BOOST_CHECK_EQUAL(logger_.getVerbosity(), VERBOSITY_ERROR);
BOOST_CHECK( logger_.stream(MSG_TYPE_DEBUG ).isNull());
BOOST_CHECK( logger_.stream(MSG_TYPE_INFO ).isNull());
BOOST_CHECK( logger_.stream(MSG_TYPE_WARNING).isNull());
BOOST_CHECK(!logger_.stream(MSG_TYPE_ERROR ).isNull());
logger_.setVerbosity(VERBOSITY_WARNING_ERROR);
BOOST_CHECK_EQUAL(logger_.getVerbosity(), VERBOSITY_WARNING_ERROR);
BOOST_CHECK( logger_.stream(MSG_TYPE_DEBUG ).isNull());
BOOST_CHECK( logger_.stream(MSG_TYPE_INFO ).isNull());
BOOST_CHECK(!logger_.stream(MSG_TYPE_WARNING).isNull());
BOOST_CHECK(!logger_.stream(MSG_TYPE_ERROR ).isNull());
logger_.setVerbosity(VERBOSITY_INFO_WARNING_ERROR);
BOOST_CHECK_EQUAL(logger_.getVerbosity(), VERBOSITY_INFO_WARNING_ERROR);
BOOST_CHECK( logger_.stream(MSG_TYPE_DEBUG ).isNull());
BOOST_CHECK(!logger_.stream(MSG_TYPE_INFO ).isNull());
BOOST_CHECK(!logger_.stream(MSG_TYPE_WARNING).isNull());
BOOST_CHECK(!logger_.stream(MSG_TYPE_ERROR ).isNull());
logger_.setVerbosity(VERBOSITY_ALL);
LoggerVerbosity alv = logger_.getVerbosity();
BOOST_CHECK(alv == VERBOSITY_ALL);
BOOST_CHECK_EQUAL(logger_.getVerbosity(), VERBOSITY_ALL);
BOOST_CHECK(!logger_.stream(MSG_TYPE_DEBUG ).isNull());
BOOST_CHECK(!logger_.stream(MSG_TYPE_INFO ).isNull());
BOOST_CHECK(!logger_.stream(MSG_TYPE_WARNING).isNull());
BOOST_CHECK(!logger_.stream(MSG_TYPE_ERROR ).isNull());
}
~CustomEntity() {}
void testDebugTrace() {
sendMsg("This is a message of level MSG_TYPE_DEBUG", MSG_TYPE_DEBUG);
sendMsg("This is a message of level MSG_TYPE_INFO", MSG_TYPE_INFO);
sendMsg("This is a message of level MSG_TYPE_WARNING", MSG_TYPE_WARNING);
sendMsg("This is a message of level MSG_TYPE_ERROR", MSG_TYPE_ERROR);
sendMsg("This is a message of level MSG_TYPE_DEBUG_STREAM",
MSG_TYPE_DEBUG_STREAM);
sendMsg("This is a message of level MSG_TYPE_INFO_STREAM",
MSG_TYPE_INFO_STREAM);
sendMsg("This is a message of level MSG_TYPE_WARNING_STREAM",
MSG_TYPE_WARNING_STREAM);
sendMsg("This is a message of level MSG_TYPE_ERROR_STREAM",
MSG_TYPE_ERROR_STREAM);
logger_.stream(MSG_TYPE_DEBUG)
<< "This is a message of level MSG_TYPE_DEBUG\n";
dynamicgraph::RealTimeLogger::instance().spinOnce();
logger_.stream(MSG_TYPE_INFO)
<< "This is a message of level MSG_TYPE_INFO\n";
dynamicgraph::RealTimeLogger::instance().spinOnce();
logger_.stream(MSG_TYPE_WARNING)
<< "This is a message of level MSG_TYPE_WARNING\n";
dynamicgraph::RealTimeLogger::instance().spinOnce();
logger_.stream(MSG_TYPE_ERROR)
<< "This is a message of level MSG_TYPE_ERROR\n";
dynamicgraph::RealTimeLogger::instance().spinOnce();
logger_.stream(MSG_TYPE_DEBUG_STREAM)
<< "This is a message of level MSG_TYPE_DEBUG_STREAM\n";
dynamicgraph::RealTimeLogger::instance().spinOnce();
logger_.stream(MSG_TYPE_INFO_STREAM)
<< "This is a message of level MSG_TYPE_INFO_STREAM\n";
dynamicgraph::RealTimeLogger::instance().spinOnce();
logger_.stream(MSG_TYPE_WARNING_STREAM)
<< "This is a message of level MSG_TYPE_WARNING_STREAM\n";
dynamicgraph::RealTimeLogger::instance().spinOnce();
logger_.stream(MSG_TYPE_ERROR_STREAM)
<< "This is a message of level MSG_TYPE_ERROR_STREAM\n";
/* Add test toString */
dynamicgraph::RealTimeLogger::instance().spinOnce();
double q = 1.0;
sendMsg("Value to display: " + toString(q));
logger_.stream() << "Value to display: " + toString(q) << '\n';
dynamicgraph::RealTimeLogger::instance().spinOnce();
std::vector<double> vq;
vq.resize(3);
vq[0] = 1.0;
vq[1] = 2.0;
vq[2] = 3.0;
sendMsg("Value to display: " + toString(vq));
sendMsg("Value to display: " + toString(vq, 3, 10));
logger_.stream(MSG_TYPE_INFO) << "Value to display: " << toString(vq) << '\n';
dynamicgraph::RealTimeLogger::instance().spinOnce();
logger_.stream(MSG_TYPE_INFO) << "Value to display: " << toString(vq, 3, 10) << '\n';
dynamicgraph::RealTimeLogger::instance().spinOnce();
Eigen::Matrix<double, 3, 3> an_eig_m;
an_eig_m.Ones();
sendMsg("Value to display: " + toString(an_eig_m));
an_eig_m.setOnes();
logger_.stream(MSG_TYPE_INFO) << "Value to display: " << toString(an_eig_m) << '\n';
dynamicgraph::RealTimeLogger::instance().spinOnce();
logger_.countdown();
}
};
......@@ -84,8 +132,8 @@ BOOST_AUTO_TEST_CASE(debug_logger) {
entity.setTimeSample(0.002);
BOOST_CHECK_EQUAL(entity.getTimeSample(), 0.002);
entity.setStreamPrintPeriod(0.004);
BOOST_CHECK_EQUAL(entity.getStreamPrintPeriod(), 0.004);
entity.setStreamPrintPeriod(0.002);
BOOST_CHECK_EQUAL(entity.getStreamPrintPeriod(), 0.002);
for (unsigned int i = 0; i < 10000; i++) {
entity.testDebugTrace();
......
......@@ -216,15 +216,16 @@ BOOST_AUTO_TEST_CASE(sendMsg) {
if (entity.getLoggerVerbosityLevel() != aLoggerVerbosityLevel)
output << "Mismatch output";
std::string aBaseMsg = "Auto Test Case";
std::string aMsg = aBaseMsg + " DEBUG";
entity.sendMsg(aMsg, dynamicgraph::MSG_TYPE_DEBUG, __FILE__, __LINE__);
aMsg = aBaseMsg + " INFO";
entity.sendMsg(aMsg, dynamicgraph::MSG_TYPE_INFO, __FILE__, __LINE__);
aMsg = aBaseMsg + " WARNING";
entity.sendMsg(aMsg, dynamicgraph::MSG_TYPE_WARNING, __FILE__, __LINE__);
aMsg = aBaseMsg + " DEBUG";
entity.sendMsg(aMsg, dynamicgraph::MSG_TYPE_ERROR, __FILE__, __LINE__);
#define __FILELINE__ __FILE__ BOOST_PP_STRINGIZE(__LINE__)
entity.logger().stream(dynamicgraph::MSG_TYPE_DEBUG, __FILELINE__)
<< "Auto Test Case" << " DEBUG" << '\n';
entity.logger().stream(dynamicgraph::MSG_TYPE_INFO, __FILELINE__)
<< "Auto Test Case" << " INFO" << '\n';
entity.logger().stream(dynamicgraph::MSG_TYPE_WARNING, __FILELINE__)
<< "Auto Test Case" << " WARNING" << '\n';
entity.logger().stream(dynamicgraph::MSG_TYPE_ERROR, __FILELINE__)
<< "Auto Test Case" << " ERROR" << '\n';
#undef __FILELINE__
};
};
......
......@@ -19,6 +19,10 @@ BOOST_AUTO_TEST_CASE(value_none) {
Value value1;
Value value(value1);
// Similar to NaN != NaN
BOOST_CHECK(!(value1 == value));
{
output_test_stream output;
output << value1;
......@@ -33,6 +37,8 @@ BOOST_AUTO_TEST_CASE(value_bool) {
Value value1(abool1);
Value value = value1;
BOOST_CHECK(value1 == value);
{
output_test_stream output;
output << value1;
......@@ -166,6 +172,8 @@ BOOST_AUTO_TEST_CASE(value_unsigned_int) {
Value value1(aint1);
Value value = value1;
BOOST_CHECK(value1 == value);
{
output_test_stream output;
output << value1;
......@@ -186,6 +194,8 @@ BOOST_AUTO_TEST_CASE(value_int) {
Value value1(aint1);
Value value = value1;
BOOST_CHECK(value1 == value);
{
output_test_stream output;
output << value1;
......@@ -206,6 +216,8 @@ BOOST_AUTO_TEST_CASE(value_float) {
Value value1(afloat1);
Value value = value1;
BOOST_CHECK(value1 == value);
{
output_test_stream output;
output << value1;
......@@ -226,6 +238,8 @@ BOOST_AUTO_TEST_CASE(value_double) {
Value value1(adouble1);
Value value = value1;
BOOST_CHECK(value1 == value);
{
output_test_stream output;
output << value1;
......@@ -249,6 +263,8 @@ BOOST_AUTO_TEST_CASE(value_vector) {
Value value1(avector1);
Value value = value1;
BOOST_CHECK(value1 == value);
{
output_test_stream output;
output << value1;
......@@ -269,6 +285,8 @@ BOOST_AUTO_TEST_CASE(value_string) {
Value value1(str1);
Value value = value1;
BOOST_CHECK(value1 == value);
{
output_test_stream output;
output << value1;
......@@ -310,6 +328,8 @@ BOOST_AUTO_TEST_CASE(value_matrixXd) {
Value value1(avector1);
Value value = value1;
BOOST_CHECK(value1 == value);
{
output_test_stream output;
output << value1;
......@@ -335,6 +355,8 @@ BOOST_AUTO_TEST_CASE(value_matrix4d) {
Value value1(avector1);
Value value = value1;
BOOST_CHECK(value1 == value);
{
output_test_stream output;
output << value1;
......@@ -351,3 +373,46 @@ BOOST_AUTO_TEST_CASE(value_matrix4d) {
" 0 0 0 0"));
}
}
BOOST_AUTO_TEST_CASE(value_values) {
using namespace dynamicgraph::command;
std::string s1("value #1");
double d1 = 0.3;
Value vs1(s1);
Value vd1(d1);
Values values;
values.push_back (vs1);
values.push_back (vd1);
Value vvalues (values);
BOOST_CHECK_EQUAL(vvalues.type(), Value::VALUES);
{ // Const ref
const Values& vs = vvalues.constValuesValue();
BOOST_CHECK_EQUAL(vs.size(), values.size());
BOOST_CHECK(vs == values);
}
{ // Cast does not work.
//dg::command::EitherType eitherType (vvalues);
//Values vs = static_cast<Values>(eitherType);
//BOOST_CHECK_EQUAL(vs.size(), values.size());
//BOOST_CHECK(vs == values);
}
{ // Constructor
Value vvs (vvalues);
BOOST_CHECK(vvs == vvalues);
}
{
output_test_stream output;
output << vvalues;
BOOST_CHECK(output.is_equal("Type=values, value=[ "
"Value(Type=string, value=value #1), "
"Value(Type=double, value=0.3), "
"]"));
}
}