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

template <typename T>
107
108
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
109
110
  std::stringstream ss;
  if (width > precision) {
111
    for (unsigned int i = 0; i < v.size() - 1; i++)
112
      ss << std::fixed << std::setw(width) << std::setprecision(precision)
113
         << v[i] << separator;
114
115
    ss << std::fixed << std::setw(width) << std::setprecision(precision)
       << v[v.size() - 1];
Bergé's avatar
Bergé committed
116
  } else {
117
    for (unsigned int i = 0; i < v.size() - 1; i++)
118
      ss << std::fixed << std::setprecision(precision) << v[i] << separator;
Bergé's avatar
Bergé committed
119
    ss << std::fixed << std::setprecision(precision) << v[v.size() - 1];
120
121
  }

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

template <typename T>
126
127
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
128
129
  std::stringstream ss;
  if (width > precision) {
130
    for (unsigned int i = 0; i < v.size() - 1; i++)
131
132
133
134
      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
135
  } else {
136
    for (unsigned int i = 0; i < v.size() - 1; i++)
137
      ss << std::fixed << std::setprecision(precision) << v[i] << separator;
Bergé's avatar
Bergé committed
138
139
140
141
142
143
144
    ss << std::setprecision(precision) << v[v.size() - 1];
  }

  return ss.str();
}

enum LoggerVerbosity {
Olivier Stasse's avatar
Olivier Stasse committed
145
  VERBOSITY_ALL = MSG_TYPE_DEBUG,
146
  VERBOSITY_INFO_WARNING_ERROR = MSG_TYPE_INFO,
Olivier Stasse's avatar
Olivier Stasse committed
147
148
149
  VERBOSITY_WARNING_ERROR = MSG_TYPE_WARNING,
  VERBOSITY_ERROR = MSG_TYPE_ERROR,
  VERBOSITY_NONE = 0
Bergé's avatar
Bergé committed
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
};

/// \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
169
170
/// dynamicgraph::LoggerVerbosity aLoggerVerbosityLevel =
///   VERBOSITY_WARNING_ERROR;
Bergé's avatar
Bergé committed
171
172
/// entity.setLoggerVerbosityLevel(aLoggerVerbosityLevel);
/// ...
173
174
175
176
177
178
179
180
/// // 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
181
182
183
///
/// \endcode
///
Joseph Mirabel's avatar
Joseph Mirabel committed
184
185
186
/// \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
187
class Logger {
188
public:
Bergé's avatar
Bergé committed
189
190
191
192
193
194
195
196
197
198
  /** 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
199
  /** Get an output stream independently of the debug level.
200
201
   */
  RTLoggerStream stream() {
Joseph Mirabel's avatar
Joseph Mirabel committed
202
    return ::dynamicgraph::RealTimeLogger::instance().front();
203
204
  }

Bergé's avatar
Bergé committed
205
  /** Print the specified message on standard output if the verbosity level
206
207
208
   * allows it. The lineId is used to identify the point where sendMsg is
   * called so that streaming messages are printed only every streamPrintPeriod
   * iterations.
209
   * \param type specifies the verbosity level, for instance MSG_TYPE_DEBUG
210
   * \param lineId typically __FILE__ ":" BOOST_PP_STRINGIZE(__LINE__)
Bergé's avatar
Bergé committed
211
   */
Olivier Stasse's avatar
Olivier Stasse committed
212
  RTLoggerStream stream(MsgType type, const std::string &lineId = "") {
213
214
215
216
217
218
219
220
221
222
223
    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
   */
Olivier Stasse's avatar
Olivier Stasse committed
224
  void sendMsg(std::string msg, MsgType type, const std::string &lineId = "");
Bergé's avatar
Bergé committed
225

226
227
228
229
230
  /** \deprecated instead, use
   *  \code
   *    stream(type, lineId) << msg << '\n';
   *  \endcode
   */
Olivier Stasse's avatar
Olivier Stasse committed
231
232
  void sendMsg(std::string msg, MsgType type, const std::string &file,
               int line) DYNAMIC_GRAPH_DEPRECATED;
233

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

Olivier Stasse's avatar
Olivier Stasse committed
267
  inline bool isStreamMsg(MsgType m) { return (m & MSG_TYPE_STREAM_BIT); }
268

Guilhem Saurel's avatar
format    
Guilhem Saurel committed
269
270
271
  /** Check whether a message of type \p m and from \p c lineId should be
   * accepted. \note If \p m is a stream type, the internal counter associated
   * to \p lineId is updated.
Joseph Mirabel's avatar
Joseph Mirabel committed
272
   */
Olivier Stasse's avatar
Olivier Stasse committed
273
  bool acceptMsg(MsgType m, const std::string &lineId) {
Joseph Mirabel's avatar
Joseph Mirabel committed
274
275
    // If more verbose than the current verbosity level
    if ((m & MSG_TYPE_TYPE_BITS) > m_lv)
Joseph Mirabel's avatar
Joseph Mirabel committed
276
      return false;
Bergé's avatar
Bergé committed
277

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

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

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

292
#endif // #ifndef __sot_torque_control_logger_H__