logger.h 10.3 KB
Newer Older
1
2
3
/*
 * Copyright 2015, 2019
 * LAAS-CNRS
4
 * Andrea Del Prete, François Bailly, Olivier Stasse
5
6
7
8
9
10
11
12
13
14
 *
 */

#ifndef __dynamic_graph_logger_H__
#define __dynamic_graph_logger_H__

/* --------------------------------------------------------------------- */
/* --- API ------------------------------------------------------------- */
/* --------------------------------------------------------------------- */

Bergé's avatar
Bergé committed
15
16
17
#if defined(WIN32)
#if defined(logger_EXPORTS)
#define LOGGER_EXPORT __declspec(dllexport)
18
#else
Bergé's avatar
Bergé committed
19
20
21
22
#define LOGGER_EXPORT __declspec(dllimport)
#endif
#else
#define LOGGER_EXPORT
23
24
#endif

25
26
namespace dynamicgraph {

Bergé's avatar
Bergé committed
27
28
29
/** Enum representing the different kind of messages.
 */
enum MsgType {
Joseph Mirabel's avatar
Joseph Mirabel committed
30
31
32
33
34
35
36
37
38
39
40
  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
Bergé's avatar
Bergé committed
41
};
42
} // namespace dynamicgraph
43
44
45
46
47

/* --------------------------------------------------------------------- */
/* --- INCLUDE --------------------------------------------------------- */
/* --------------------------------------------------------------------- */

48
49
50
51
52
53
#include <map>
/// \todo These 3 headers should be removed.
#include <fstream>
#include <iomanip> // std::setprecision
#include <sstream>

54
55
#include <boost/assign.hpp>
#include <boost/preprocessor/stringize.hpp>
56
57

#include <dynamic-graph/deprecated.hh>
58
#include <dynamic-graph/linear-algebra.h>
59
#include <dynamic-graph/real-time-logger-def.h>
60
61
62
63
64
65

namespace dynamicgraph {

//#define LOGGER_VERBOSITY_INFO_WARNING_ERROR
#define LOGGER_VERBOSITY_ALL

66
67
#define SEND_MSG(msg, type)                                                    \
  sendMsg(msg, type, __FILE__ ":" BOOST_PP_STRINGIZE(__LINE__))
Bergé's avatar
Bergé committed
68
69
70
71
72
73

#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)

74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#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)


Olivier Stasse's avatar
Olivier Stasse committed
96
97
98
template <typename T>
std::string toString(const T &v, const int precision = 3,
                     const int width = -1) {
Bergé's avatar
Bergé committed
99
  std::stringstream ss;
Olivier Stasse's avatar
Olivier Stasse committed
100
101
  if (width > precision)
    ss << std::fixed << std::setw(width) << std::setprecision(precision) << v;
Bergé's avatar
Bergé committed
102
  else
Olivier Stasse's avatar
Olivier Stasse committed
103
    ss << std::fixed << std::setprecision(precision) << v;
Bergé's avatar
Bergé committed
104
  return ss.str();
105
}
Bergé's avatar
Bergé committed
106
107

template <typename T>
108
109
std::string toString(const std::vector<T> &v, const int precision = 3,
                     const int width = -1, const std::string separator = ", ") {
Bergé's avatar
Bergé committed
110
111
  std::stringstream ss;
  if (width > precision) {
112
    for (unsigned int i = 0; i < v.size() - 1; i++)
113
      ss << std::fixed << std::setw(width) << std::setprecision(precision)
114
         << v[i] << separator;
115
116
    ss << std::fixed << std::setw(width) << std::setprecision(precision)
       << v[v.size() - 1];
Bergé's avatar
Bergé committed
117
  } else {
118
    for (unsigned int i = 0; i < v.size() - 1; i++)
119
      ss << std::fixed << std::setprecision(precision) << v[i] << separator;
Bergé's avatar
Bergé committed
120
    ss << std::fixed << std::setprecision(precision) << v[v.size() - 1];
121
122
  }

Bergé's avatar
Bergé committed
123
124
125
126
  return ss.str();
}

template <typename T>
127
128
std::string toString(const Eigen::MatrixBase<T> &v, const int precision = 3,
                     const int width = -1, const std::string separator = ", ") {
Bergé's avatar
Bergé committed
129
130
  std::stringstream ss;
  if (width > precision) {
131
    for (unsigned int i = 0; i < v.size() - 1; i++)
132
133
134
135
      ss << std::fixed << std::setw(width) << std::setprecision(precision)
         << v[i] << separator;
    ss << std::fixed << std::setw(width) << std::setprecision(precision)
       << v[v.size() - 1];
Bergé's avatar
Bergé committed
136
  } else {
137
    for (unsigned int i = 0; i < v.size() - 1; i++)
138
      ss << std::fixed << std::setprecision(precision) << v[i] << separator;
Bergé's avatar
Bergé committed
139
140
141
142
143
144
145
    ss << std::setprecision(precision) << v[v.size() - 1];
  }

  return ss.str();
}

enum LoggerVerbosity {
146
147
148
149
150
  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
Bergé's avatar
Bergé committed
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
};

/// \ingroup debug
///
/// \brief Class for logging messages
///
/// 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) {
///   std::ofstream of;
///   of.open("/tmp/dg-LOGS.txt",std::ofstream::out|std::ofstream::app);
///   dgADD_OSTREAM_TO_RTLOG (of);
/// }
///
/// // Somewhere in your library
170
171
/// dynamicgraph::LoggerVerbosity aLoggerVerbosityLevel =
///   VERBOSITY_WARNING_ERROR;
Bergé's avatar
Bergé committed
172
173
/// entity.setLoggerVerbosityLevel(aLoggerVerbosityLevel);
/// ...
174
175
176
177
178
179
180
181
/// // using macros
/// DYNAMIC_GRAPH_ENTITY_WARNING(entity) << "your message\n";
///
/// // 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';
Bergé's avatar
Bergé committed
182
183
184
///
/// \endcode
///
Joseph Mirabel's avatar
Joseph Mirabel committed
185
186
187
/// \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.
Bergé's avatar
Bergé committed
188
class Logger {
189
public:
Bergé's avatar
Bergé committed
190
191
192
193
194
195
196
197
198
199
  /** Constructor */
  Logger(double timeSample = 0.001, double streamPrintPeriod = 1.0);

  /** Destructor */
  ~Logger();

  /** Method to be called at every control iteration
   * to decrement the internal Logger's counter. */
  void countdown();

Joseph Mirabel's avatar
Joseph Mirabel committed
200
  /** Get an output stream independently of the debug level.
201
202
   */
  RTLoggerStream stream() {
Joseph Mirabel's avatar
Joseph Mirabel committed
203
    return ::dynamicgraph::RealTimeLogger::instance().front();
204
205
  }

Bergé's avatar
Bergé committed
206
  /** Print the specified message on standard output if the verbosity level
207
208
209
210
   * 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__)
Bergé's avatar
Bergé committed
211
   */
212
213
214
215
216
217
218
219
220
221
222
223
224
  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 std::string& lineId = "");
Bergé's avatar
Bergé committed
225

226
227
228
229
230
231
232
233
  /** \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;

Bergé's avatar
Bergé committed
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
  /** Set the sampling time at which the method countdown()
   * is going to be called. */
  bool setTimeSample(double t);

  /** Get the sampling time at which the method countdown()
   * is going to be called. */
  double getTimeSample();

  /** Set the time period for printing of streaming messages. */
  bool setStreamPrintPeriod(double s);

  /** Get the time period for printing of streaming messages. */
  double getStreamPrintPeriod();

  /** Set the verbosity level of the logger. */
  void setVerbosity(LoggerVerbosity lv);

  /** Get the verbosity level of the logger. */
  LoggerVerbosity getVerbosity();

254
255
protected:
  LoggerVerbosity m_lv; /// verbosity of the logger
256
257
  double m_timeSample;
  /// specify the period of call of the countdown method
258
  double m_streamPrintPeriod; /// specify the time period of the stream prints
259
260
  double m_printCountdown;
  /// every time this is < 0 (i.e. every _streamPrintPeriod sec) print stuff
Bergé's avatar
Bergé committed
261

262
  typedef std::map<std::string, double> StreamCounterMap_t;
263
  /** Pointer to the dynamic structure which holds
264
      the collection of streaming messages */
265
  StreamCounterMap_t m_stream_msg_counters;
Bergé's avatar
Bergé committed
266

267
268
  inline bool isStreamMsg(MsgType m) {
    return (m & MSG_TYPE_STREAM_BIT);
269
270
  }

Joseph Mirabel's avatar
Joseph Mirabel committed
271
272
273
274
275
  /** 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) {
Joseph Mirabel's avatar
Joseph Mirabel committed
276
277
    // If more verbose than the current verbosity level
    if ((m & MSG_TYPE_TYPE_BITS) > m_lv)
Joseph Mirabel's avatar
Joseph Mirabel committed
278
      return false;
Bergé's avatar
Bergé committed
279

Joseph Mirabel's avatar
Joseph Mirabel committed
280
281
282
    // if print is allowed by current verbosity level
    if (isStreamMsg(m)) return checkStreamPeriod(lineId);
    return true;
283
  }
284

Joseph Mirabel's avatar
Joseph Mirabel committed
285
286
287
  /** Check whether a message from \c lineId should be accepted.
   *  \note The internal counter associated to \c lineId is updated.
   */
288
  bool checkStreamPeriod (const std::string& lineId);
Bergé's avatar
Bergé committed
289
290
};

291
} // namespace dynamicgraph
Bergé's avatar
Bergé committed
292

293
#endif // #ifndef __sot_torque_control_logger_H__