ErrorReporting.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <atomic>
4 #include <condition_variable>
5 #include <filesystem>
6 #include <fstream>
7 #include <map>
8 #include <memory>
9 #include <mutex>
10 #include <optional>
11 #include <thread>
12 
15 
16 #include "SlaveIdentifier.h"
17 
18 /**
19  * @defgroup Namespace-error error
20  * @ingroup Library-ethercat
21  * A description of the namespace error.
22  */
24 {
25  /**
26  * @enum Type
27  * @ingroup Namespace-error
28  *
29  * @brief The Type enum
30  */
31  enum class Type
32  {
33  Bus, //!< Bussdfnödf
34  Slave, //!< sdfluieb,dj
35  Device,
36  General
37  };
38 
39  std::ostream& operator<<(std::ostream& stream, const Type& rhs);
40 
41  /**
42  * @enum Severity
43  * @ingroup Namespace-error
44  *
45  * @brief The Severity enum
46  */
47  enum class Severity
48  {
49  Debug,
50  Info,
51  Warning,
52  Error,
53  Fatal
54  };
55 
56  std::ostream& operator<<(std::ostream& stream, const Severity& rhs);
57 
58  class Reporter;
59  class Reporting;
60 
61  /**
62  * @class Entry
63  * @ingroup Namespace-error
64  * @brief Brief description of class Entry.
65  *
66  * Detailed description of class Entry.
67  */
68  class Entry
69  {
70  static constexpr std::uint16_t DEVICE_NAME_BUFFER_SIZE = 64;
71 
72  static constexpr std::uint16_t MESSAGE_BUFFER_SIZE = 1024;
73  static constexpr char OVERFLOW_MESSAGE[] = {"[ERROR MESSAGE TOO LONG]"};
74  static_assert(MESSAGE_BUFFER_SIZE > sizeof(OVERFLOW_MESSAGE) + 1);
75 
76  static constexpr std::uint16_t FILE_STRING_BUFFER_SIZE = 256;
77  static constexpr std::uint16_t FUNCTION_STRING_BUFFER_SIZE = 256;
78 
79  friend Reporter;
80  friend Reporting;
81 
82  char m_message[MESSAGE_BUFFER_SIZE];
83  std::size_t m_message_size = 0;
84  Type m_type;
85  SlaveIdentifier m_sid;
86  char m_device_name[DEVICE_NAME_BUFFER_SIZE];
87  Severity m_severity;
88  IceUtil::Time m_timestamp;
89  std::uint64_t m_bus_iteration_number = 0;
90  float m_deactivate_spam_seconds = 0;
91 
92  struct MetaInfo
93  {
94  char file[FILE_STRING_BUFFER_SIZE];
95  int line;
96  char function[FUNCTION_STRING_BUFFER_SIZE];
97  };
98 
99  MetaInfo m_metaInfo;
100 
101  public:
102  Entry() = default;
103  ~Entry() = default;
104 
105  template <typename... T>
106  Entry&
107  message(const char* fmt, T... args)
108  {
109 #pragma GCC diagnostic ignored "-Wformat-security"
110  int sz = std::snprintf(m_message, sizeof(m_message), fmt, args...);
111  if (sz >= static_cast<int>(sizeof(m_message)))
112  {
113  std::snprintf(m_message + MESSAGE_BUFFER_SIZE - sizeof(OVERFLOW_MESSAGE),
114  sizeof(OVERFLOW_MESSAGE),
115  OVERFLOW_MESSAGE);
116  m_message_size = MESSAGE_BUFFER_SIZE;
117  }
118  else
119  {
120  m_message_size = static_cast<std::size_t>(sz);
121  }
122 #pragma GCC diagnostic pop
123  return *this;
124  }
125 
127  Entry& errorType(Type type);
128  Entry& metaInfo(const char* file, int line, const char* function);
129  Entry& deviceName(const char* deviceName);
130  Entry& busIterationNumber(std::uint64_t iteration);
131 
132  std::string toString() const;
133  };
134 
135  /**
136  * @class Reporter
137  * @ingroup Namespace-error
138  * @brief Brief description of class Reporter.
139  *
140  * Detailed description of class Reporter.
141  */
142  class Reporter
143  {
144  friend Reporting;
145 
146  class ReportWrapper
147  {
148  public:
149  ReportWrapper(Entry& error, Reporter* reporter);
150  ~ReportWrapper();
151  ReportWrapper(const ReportWrapper&) = delete; // Copying not allowed
152  ReportWrapper& operator=(const ReportWrapper&) = delete; // Assignment not allowed
153 
154  ReportWrapper& deactivateSpam(float seconds);
155 
156  private:
157  Entry& m_error;
158  Reporter* m_reporter;
159  };
160 
161  public:
162  ReportWrapper reportDebug(Entry& error);
163  ReportWrapper reportInfo(Entry& error);
164  ReportWrapper reportWarning(Entry& error);
165  ReportWrapper reportError(Entry& error);
166  [[noreturn]] void reportErrorAndThrow(Entry& error);
167  bool hasErrors() const;
168 
169  private:
170  Reporter() = delete;
171  Reporter(Reporting* errorReporting);
172  Reporting* m_errorReporting;
173  unsigned int m_errorCount = 0;
174  };
175 
176  /**
177  * @class Reporting
178  * @ingroup Namespace-error
179  * @brief Brief description of class Reporting.
180  *
181  * Detailed description of class Reporting.
182  */
183  class Reporting : virtual public Logging
184  {
185  public:
186  static Reporting& getErrorReporting();
187 
190  void report(Entry&& error);
191 
192  void setMaxErrorHistorySize(std::size_t maxErrorHistorySize);
193 
194  std::optional<std::filesystem::path> dumpToFile(std::filesystem::path file,
195  std::uint64_t lastNSeconds = 1000000);
196 
197  private:
198  Reporting(std::size_t maxErrorHistorySize = 1000);
199  ~Reporting() override;
200 
201  std::vector<Entry> m_errors;
202 
203  struct QueueImpl;
205 
206  struct ErrorTimestamp
207  {
208  std::int64_t timestamp;
209  std::uint16_t subid;
210 
211  bool
212  operator<(const ErrorTimestamp& x) const
213  {
214  return std::tie(this->timestamp, this->subid) < std::tie(x.timestamp, x.subid);
215  }
216  };
217 
218  std::map<ErrorTimestamp, Entry> m_errorHistory;
219  std::size_t m_maxErrorHistorySize;
220 
221  std::thread m_errorProcessingThread;
222  std::atomic_bool m_errorProcessingRunning{true};
223  void errorProcessingLoop();
224  std::condition_variable m_errorProcessingCondition;
225  std::mutex m_errorProcessingConditionMutex;
226 
227  IceUtil::Time m_timestampReportingStart;
228  };
229 
230 } // namespace armarx::control::ethercat::reporting
231 
233 {
237 
238 
239 ////////////////////////////////////////////////////////////////////////////////////////////////////
240 #define _detail_GENERAL_REPORT_CONSTRUCTION(...) \
241  armarx::control::ethercat::ReportingEntry() \
242  .errorType(armarx::control::ethercat::ReportingType::General) \
243  .metaInfo(__FILE__, __LINE__, ARMARX_FUNCTION) \
244  .message(__VA_ARGS__)
245 
246 #define GENERAL_DEBUG(...) \
247  armarx::control::ethercat::Reporting::getGlobalErrorReporter().reportDebug( \
248  _detail_GENERAL_REPORT_CONSTRUCTION(__VA_ARGS__))
249 #define GENERAL_INFO(...) \
250  armarx::control::ethercat::Reporting::getGlobalErrorReporter().reportInfo( \
251  _detail_GENERAL_REPORT_CONSTRUCTION(__VA_ARGS__))
252 #define GENERAL_WARNING(...) \
253  armarx::control::ethercat::Reporting::getGlobalErrorReporter().reportWarning( \
254  _detail_GENERAL_REPORT_CONSTRUCTION(__VA_ARGS__))
255 #define GENERAL_ERROR(...) \
256  armarx::control::ethercat::Reporting::getGlobalErrorReporter().reportError( \
257  _detail_GENERAL_REPORT_CONSTRUCTION(__VA_ARGS__))
258 
259 
260 ////////////////////////////////////////////////////////////////////////////////////////////////////
261 #define _detail_BUS_REPORT_CONSTRUCTION(bin, ...) \
262  armarx::control::ethercat::ReportingEntry() \
263  .errorType(armarx::control::ethercat::ReportingType::Bus) \
264  .metaInfo(__FILE__, __LINE__, ARMARX_FUNCTION) \
265  .message(__VA_ARGS__) \
266  .busIterationNumber(bin)
267 
268 #define BUS_DEBUG(bin, ...) \
269  armarx::control::ethercat::Reporting::getGlobalErrorReporter().reportDebug( \
270  _detail_BUS_REPORT_CONSTRUCTION(bin, __VA_ARGS__))
271 #define BUS_INFO(bin, ...) \
272  armarx::control::ethercat::Reporting::getGlobalErrorReporter().reportInfo( \
273  _detail_BUS_REPORT_CONSTRUCTION(bin, __VA_ARGS__))
274 #define BUS_WARNING(bin, ...) \
275  armarx::control::ethercat::reporting::Reporting::getGlobalErrorReporter().reportWarning( \
276  _detail_BUS_REPORT_CONSTRUCTION(bin, __VA_ARGS__))
277 #define BUS_ERROR(bin, ...) \
278  armarx::control::ethercat::reporting::Reporting::getGlobalErrorReporter().reportError( \
279  _detail_BUS_REPORT_CONSTRUCTION(bin, __VA_ARGS__))
280 #define BUS_FATAL_AND_THROW(bin, ...) \
281  armarx::control::ethercat::reporting::Reporting::getGlobalErrorReporter().reportErrorAndThrow( \
282  _detail_BUS_REPORT_CONSTRUCTION(bin, __VA_ARGS__))
283 
284 #define BUS_WARNING_LOCAL(reporter, bin, ...) \
285  (reporter).reportWarning(_detail_BUS_REPORT_CONSTRUCTION(bin, __VA_ARGS__))
286 #define BUS_ERROR_LOCAL(reporter, bin, ...) \
287  (reporter).reportError(_detail_BUS_REPORT_CONSTRUCTION(bin, __VA_ARGS__))
288 
289 ////////////////////////////////////////////////////////////////////////////////////////////////////
290 #define _detail_SLAVE_REPORT_CONSTRUCTION(_sid, ...) \
291  armarx::control::ethercat::ReportingEntry() \
292  .errorType(armarx::control::ethercat::ReportingType::Slave) \
293  .metaInfo(__FILE__, __LINE__, ARMARX_FUNCTION) \
294  .message(__VA_ARGS__) \
295  .slaveIdentifier(_sid)
296 
297 #define SLAVE_DEBUG(sid, ...) \
298  armarx::control::ethercat::Reporting::getGlobalErrorReporter().reportDebug( \
299  _detail_SLAVE_REPORT_CONSTRUCTION(sid, __VA_ARGS__))
300 #define SLAVE_INFO(sid, ...) \
301  armarx::control::ethercat::Reporting::getGlobalErrorReporter().reportInfo( \
302  _detail_SLAVE_REPORT_CONSTRUCTION(sid, __VA_ARGS__))
303 #define SLAVE_WARNING(sid, ...) \
304  armarx::control::ethercat::reporting::Reporting::getGlobalErrorReporter().reportWarning( \
305  _detail_SLAVE_REPORT_CONSTRUCTION(sid, __VA_ARGS__))
306 #define SLAVE_ERROR(sid, ...) \
307  armarx::control::ethercat::reporting::Reporting::getGlobalErrorReporter().reportError( \
308  _detail_SLAVE_REPORT_CONSTRUCTION(sid, __VA_ARGS__))
309 #define SLAVE_FATAL_AND_THROW(sid, ...) \
310  armarx::control::ethercat::Reporting::getGlobalErrorReporter().reportErrorAndThrow( \
311  _detail_SLAVE_REPORT_CONSTRUCTION(sid, __VA_ARGS__))
312 
313 #define SLAVE_WARNING_LOCAL(reporter, sid, ...) \
314  (reporter).reportWarning(_detail_SLAVE_REPORT_CONSTRUCTION(sid, __VA_ARGS__))
315 #define SLAVE_ERROR_LOCAL(reporter, sid, ...) \
316  (reporter).reportError(_detail_SLAVE_REPORT_CONSTRUCTION(sid, __VA_ARGS__))
317 
318 ////////////////////////////////////////////////////////////////////////////////////////////////////
319 #define _detail_DEVICE_REPORT_CONSTRUCTION(devName, ...) \
320  armarx::control::ethercat::ReportingEntry() \
321  .errorType(armarx::control::ethercat::ReportingType::Device) \
322  .metaInfo(__FILE__, __LINE__, ARMARX_FUNCTION) \
323  .message(__VA_ARGS__) \
324  .deviceName(devName)
325 
326 #define DEVICE_WARNING(deviceName, ...) \
327  armarx::control::ethercat::Reporting::getGlobalErrorReporter().reportWarning( \
328  _detail_DEVICE_REPORT_CONSTRUCTION(deviceName, __VA_ARGS__))
329 #define DEVICE_ERROR(deviceName, ...) \
330  armarx::control::ethercat::Reporting::getGlobalErrorReporter().reportError( \
331  _detail_DEVICE_REPORT_CONSTRUCTION(deviceName, __VA_ARGS__))
332 #define DEVICE_FATAL_AND_THROW(deviceName, ...) \
333  armarx::control::ethercat::Reporting::getGlobalErrorReporter().reportErrorAndThrow( \
334  _detail_DEVICE_REPORT_CONSTRUCTION(deviceName, __VA_ARGS__))
335 
336 #define DEVICE_WARNING_LOCAL(reporter, deviceName, ...) \
337  (reporter).reportWarning(_detail_DEVICE_REPORT_CONSTRUCTION(deviceName, __VA_ARGS__))
338 #define DEVICE_ERROR_LOCAL(reporter, deviceName, ...) \
339  (reporter).reportError(_detail_DEVICE_REPORT_CONSTRUCTION(deviceName, __VA_ARGS__))
340 
341 
342 } // namespace armarx::control::ethercat
armarx::control::ethercat::reporting::Reporting::getGlobalErrorReporter
static Reporter & getGlobalErrorReporter()
Definition: ErrorReporting.cpp:95
armarx::control::ethercat::reporting::Severity::Debug
@ Debug
armarx::control::ethercat::reporting::Reporting::report
void report(Entry &&error)
Definition: ErrorReporting.cpp:102
armarx::control::ethercat::reporting
Definition: ErrorReporting.cpp:11
armarx::control::ethercat::reporting::Entry::busIterationNumber
Entry & busIterationNumber(std::uint64_t iteration)
Definition: ErrorReporting.cpp:378
armarx::control::ethercat::reporting::Type::Bus
@ Bus
Bussdfnödf.
armarx::control::ethercat::reporting::Reporter::hasErrors
bool hasErrors() const
Definition: ErrorReporting.cpp:315
armarx::control::ethercat::reporting::Type::General
@ General
armarx::control::ethercat::SlaveIdentifier
The SlaveIdentifier class is a POD-type representing a unique set of values identifying an EtherCAT s...
Definition: SlaveIdentifier.h:53
armarx::control::ethercat::reporting::Reporting::dumpToFile
std::optional< std::filesystem::path > dumpToFile(std::filesystem::path file, std::uint64_t lastNSeconds=1000000)
Definition: ErrorReporting.cpp:120
armarx::control::ethercat::reporting::Entry::toString
std::string toString() const
Definition: ErrorReporting.cpp:355
armarx::control::ethercat::reporting::operator<<
std::ostream & operator<<(std::ostream &stream, const Type &rhs)
Definition: ErrorReporting.cpp:14
armarx::control::ethercat::reporting::Entry::message
Entry & message(const char *fmt, T... args)
Definition: ErrorReporting.h:107
deactivateSpam
SpamFilterDataPtr deactivateSpam(SpamFilterDataPtr const &spamFilter, float deactivationDurationSec, const std::string &identifier, bool deactivate)
Definition: Logging.cpp:72
armarx::control::ethercat::reporting::Entry::~Entry
~Entry()=default
armarx::control::ethercat::reporting::Severity::Info
@ Info
armarx::control::ethercat::reporting::Type::Slave
@ Slave
sdfluieb,dj
armarx::control::ethercat::reporting::Severity
Severity
The Severity enum.
Definition: ErrorReporting.h:47
armarx::control::ethercat::reporting::Type::Device
@ Device
armarx::control::ethercat::reporting::Reporting::getErrorReporting
static Reporting & getErrorReporting()
Definition: ErrorReporting.cpp:82
armarx::control::ethercat::reporting::Reporter::reportDebug
ReportWrapper reportDebug(Entry &error)
Definition: ErrorReporting.cpp:276
armarx::control::ethercat
Definition: Bus.cpp:24
armarx::control::ethercat::reporting::Entry::Entry
Entry()=default
armarx::control::ethercat::reporting::Reporting::getErrorReporter
Reporter getErrorReporter()
Definition: ErrorReporting.cpp:89
armarx::control::ethercat::reporting::Reporting::setMaxErrorHistorySize
void setMaxErrorHistorySize(std::size_t maxErrorHistorySize)
Definition: ErrorReporting.cpp:114
armarx::armem::Time
armarx::core::time::DateTime Time
Definition: forward_declarations.h:13
armarx::control::ethercat::Reporting
reporting::Reporting Reporting
Definition: ErrorReporting.h:236
armarx::control::ethercat::reporting::Reporter::reportInfo
ReportWrapper reportInfo(Entry &error)
Definition: ErrorReporting.cpp:283
armarx::control::ethercat::reporting::Reporter
Brief description of class Reporter.
Definition: ErrorReporting.h:142
armarx::control::ethercat::reporting::Severity::Warning
@ Warning
armarx::control::ethercat::reporting::Entry::errorType
Entry & errorType(Type type)
Definition: ErrorReporting.cpp:332
armarx::Logging
Base Class for all Logging classes.
Definition: Logging.h:232
armarx::control::ethercat::reporting::Entry::deviceName
Entry & deviceName(const char *deviceName)
Definition: ErrorReporting.cpp:348
armarx::control::ethercat::reporting::Severity::Fatal
@ Fatal
armarx::control::ethercat::reporting::Reporter::reportWarning
ReportWrapper reportWarning(Entry &error)
Definition: ErrorReporting.cpp:290
armarx::operator<
bool operator<(const RemoteHandle< PrxTA > &fst, const RemoteHandle< PrxTB > &snd)
Definition: RemoteHandle.h:224
armarx::control::ethercat::reporting::Type
Type
Definition: ErrorReporting.h:31
armarx::control::ethercat::reporting::Reporter::reportError
ReportWrapper reportError(Entry &error)
Definition: ErrorReporting.cpp:298
armarx::control::ethercat::reporting::Reporting
Brief description of class Reporting.
Definition: ErrorReporting.h:183
armarx::control::ethercat::reporting::Severity::Error
@ Error
Logging.h
armarx::control::ethercat::reporting::Entry::slaveIdentifier
Entry & slaveIdentifier(SlaveIdentifier sid)
Definition: ErrorReporting.cpp:325
T
float T
Definition: UnscentedKalmanFilterTest.cpp:35
armarx::control::ethercat::reporting::Entry::metaInfo
Entry & metaInfo(const char *file, int line, const char *function)
Definition: ErrorReporting.cpp:339
armarx::control::ethercat::reporting::Reporter::reportErrorAndThrow
void reportErrorAndThrow(Entry &error)
Definition: ErrorReporting.cpp:306
armarx::control::ethercat::reporting::Reporting::QueueImpl
Definition: ErrorReporting.cpp:58
SlaveIdentifier.h
armarx::PropagateConst
Wrapper for a pointer to propagate const to the pointed to value.
Definition: PropagateConst.h:69
armarx::control::ethercat::reporting::Entry
Brief description of class Entry.
Definition: ErrorReporting.h:68
PropagateConst.h