HOPS
HOPS class reference
MHO_Message.hh
Go to the documentation of this file.
1 #ifndef MHO_Message_HH__
2 #define MHO_Message_HH__
3 
4 #include <cstdlib>
5 #include <cstdint>
6 #include <iostream>
7 #include <mutex>
8 #include <ostream>
9 #include <set>
10 #include <sstream>
11 #include <stdio.h>
12 #include <string>
13 
14 #include "MHO_SelfName.hh"
15 #include "MHO_TestAssertions.hh"
16 
17 //include the profiler here to make it visible just about everywhere
18 #include "MHO_Profiler.hh"
19 
20 //MACROS handy for stringifying compiler defines
21 #define STR(str) #str
22 #define STRING(str) STR(str)
23 
24 #ifdef HOPS_ENABLE_DEV_TODO
25  #if defined(__clang__)
26  #define DO_PRAGMA(x) _Pragma(#x)
27  #define TODO_FIXME_MSG(x) DO_PRAGMA(message #x)
28  #elif defined(__GNUC__)
29  #define DO_PRAGMA(x) _Pragma(#x)
30  #define TODO_FIXME_MSG(x) DO_PRAGMA(message #x)
31  #else
32  #error Unsupported compiler
33  #endif
34 #else
35  #define TODO_FIXME_MSG(x)
36 #endif
37 
38 namespace hops
39 {
40 
49 namespace sn = selfname;
50 
55 {};
56 
61 {};
62 
63 static const MHO_MessageNewline ret = MHO_MessageNewline();
64 static const MHO_MessageNewline eol = MHO_MessageNewline();
65 static const MHO_MessageEndline eom = MHO_MessageEndline();
66 
67 enum MHO_MessageLevel : int
68 {
75  eInfoLevel = 4,
76  eDebugLevel = 5
77 };
78 
88 
89 using hops::eDebug;
90 using hops::eError;
91 using hops::eFatal;
92 using hops::eInfo;
93 using hops::eSilent;
94 using hops::eSpecial;
95 using hops::eStatus;
96 using hops::eWarning;
97 
100 {
101 
102  public:
104  MHO_Message(MHO_Message const&) = delete;
108  MHO_Message& operator=(MHO_Message const&) = delete;
111 
116  {
117  if(fInstance == nullptr)
118  {
119  fInstance = new MHO_Message();
120  }
121  return *fInstance;
122  }
123 
125  void Lock() { fMutex.lock(); };
126 
128  void Unlock() { fMutex.unlock(); };
129 
131  void AcceptAllKeys() { fAcceptAllKeys = true; }
132 
134  void LimitToKeySet() { fAcceptAllKeys = false; }
135 
138  void AddKey(const std::string& key);
139  void AddKey(const char* key);
140 
143  void RemoveKey(const std::string& key);
144  void RemoveKey(const char* key);
145 
147  void RemoveAllKeys();
148 
150  void Flush();
151 
154  void SetMessageLevel(MHO_MessageLevel level) { fAllowedLevel = level; }
155 
158  void SetLegacyMessageLevel(int legacy_message_level);
159 
162  MHO_MessageLevel GetMessageLevel() const { return fAllowedLevel; }
163 
169  MHO_Message& SendMessage(const MHO_MessageLevel& level, const std::string& key);
170  MHO_Message& SendMessage(const MHO_MessageLevel& level, const char* key);
171 
177  template< class XStreamableItemType > MHO_Message& operator<<(const XStreamableItemType& item);
178 
181 
182  private:
183  //no public access to constructor
184  //set up the stream, for now just point to std::cout
185  //but we may want to allow this to be configured post-construction
186  //perhaps we should also pipe information into log file(s)
187  MHO_Message()
188  : fTerminalStream(&std::cout), fAllowedLevel(eStatus), fCurrentLevel(eInfo), fCurrentKeyIsAllowed(false),
189  fAcceptAllKeys(false), fWasLastLineNewLine(false){};
190  virtual ~MHO_Message(){};
191 
192  bool PassMessage();
193  std::string GetCurrentPrefix(const MHO_MessageLevel& level, const std::string& key);
194 
195  std::mutex fMutex;
196 
197  static MHO_Message* fInstance; //static global class instance
198  std::ostream* fTerminalStream; //stream to terminal output
199  std::set< std::string > fKeys; //keys of which messages we will accept for output
200  MHO_MessageLevel fAllowedLevel;
201 
202  MHO_MessageLevel fCurrentLevel; //level of the current message
203  bool fCurrentKeyIsAllowed; //current key is in allowed set
204  bool fAcceptAllKeys;
205  std::stringstream fMessageStream; //the message container to be filled/flushed
206 
207  static std::string fRed; //fatal
208  static std::string fYellow; //error
209  static std::string fOrange; //orange
210  static std::string fBlue; //status
211  static std::string fGreen; //info
212  static std::string fCyan; //debug
213  static std::string fWhite; //default
214  static std::string fColorSuffix; //color close
215 
216  bool fWasLastLineNewLine;
217 };
218 
219 template< class XStreamableItemType > MHO_Message& MHO_Message::operator<<(const XStreamableItemType& item)
220 {
221  if(PassMessage())
222  {
223  fMessageStream << item;
224  }
225  return *fInstance;
226 }
227 
228 //abuse do-while for multiline message macros
229 
230 //FATAL/////////////////////////////////////////////////////////////////////////
231 
232 #ifndef HOPS_EXTRA_VERBOSE_MSG
233 
234  #define msg_fatal(xKEY, xCONTENT) \
235  do \
236  { \
237  MHO_Message::GetInstance().Lock(); \
238  MHO_Message::GetInstance().SendMessage(eFatal, xKEY) << xCONTENT; \
239  MHO_Message::GetInstance().Unlock(); \
240  } \
241  while(0)
242 
243  //ERROR/////////////////////////////////////////////////////////////////////////
244  #define msg_error(xKEY, xCONTENT) \
245  do \
246  { \
247  MHO_Message::GetInstance().Lock(); \
248  MHO_Message::GetInstance().SendMessage(eError, xKEY) << xCONTENT; \
249  MHO_Message::GetInstance().Unlock(); \
250  } \
251  while(0)
252 
253  //WARNING///////////////////////////////////////////////////////////////////////
254  #define msg_warn(xKEY, xCONTENT) \
255  do \
256  { \
257  MHO_Message::GetInstance().Lock(); \
258  MHO_Message::GetInstance().SendMessage(eWarning, xKEY) << xCONTENT; \
259  MHO_Message::GetInstance().Unlock(); \
260  } \
261  while(0)
262 
263  //STATUS////////////////////////////////////////////////////////////////////////
264  #define msg_status(xKEY, xCONTENT) \
265  do \
266  { \
267  MHO_Message::GetInstance().Lock(); \
268  MHO_Message::GetInstance().SendMessage(eStatus, xKEY) << xCONTENT; \
269  MHO_Message::GetInstance().Unlock(); \
270  } \
271  while(0)
272 
273  //INFO//////////////////////////////////////////////////////////////////////////
274  #define msg_info(xKEY, xCONTENT) \
275  do \
276  { \
277  MHO_Message::GetInstance().Lock(); \
278  MHO_Message::GetInstance().SendMessage(eInfo, xKEY) << xCONTENT; \
279  MHO_Message::GetInstance().Unlock(); \
280  } \
281  while(0)
282 
283  //allow debug messages when debug flag is active
284  #ifdef HOPS_ENABLE_DEBUG_MSG //this is defined as a compiler flag via build system
285 
286  //DEBUG/////////////////////////////////////////////////////////////////////////
287  #define msg_debug(xKEY, xCONTENT) \
288  do \
289  { \
290  MHO_Message::GetInstance().Lock(); \
291  MHO_Message::GetInstance().SendMessage(eDebug, xKEY) << xCONTENT; \
292  MHO_Message::GetInstance().Unlock(); \
293  } \
294  while(0)
295  #else
296  //debug is not enabled, so we remove them from compilation
297  #define msg_debug(xKEY, xCONTENT)
298  #endif
299 
300 #else //HOPS_EXTRA_VERBOSE_MSG is defined
301 
302  #define msg_fatal(xKEY, xCONTENT) \
303  do \
304  { \
305  MHO_Message::GetInstance().Lock(); \
306  MHO_Message::GetInstance().SendMessage(eFatal, xKEY) \
307  << "(" << sn::file_basename(__FILE__) << ":" << __LINE__ << ") " << xCONTENT; \
308  MHO_Message::GetInstance().Unlock(); \
309  } \
310  while(0)
311 
312  //ERROR/////////////////////////////////////////////////////////////////////////
313  #define msg_error(xKEY, xCONTENT) \
314  do \
315  { \
316  MHO_Message::GetInstance().Lock(); \
317  MHO_Message::GetInstance().SendMessage(eError, xKEY) \
318  << "(" << sn::file_basename(__FILE__) << ":" << __LINE__ << ") " << xCONTENT; \
319  MHO_Message::GetInstance().Unlock(); \
320  } \
321  while(0)
322 
323  //WARNING///////////////////////////////////////////////////////////////////////
324  #define msg_warn(xKEY, xCONTENT) \
325  do \
326  { \
327  MHO_Message::GetInstance().Lock(); \
328  MHO_Message::GetInstance().SendMessage(eWarning, xKEY) \
329  << "(" << sn::file_basename(__FILE__) << ":" << __LINE__ << ") " << xCONTENT; \
330  MHO_Message::GetInstance().Unlock(); \
331  } \
332  while(0)
333 
334  //STATUS////////////////////////////////////////////////////////////////////////
335  #define msg_status(xKEY, xCONTENT) \
336  do \
337  { \
338  MHO_Message::GetInstance().Lock(); \
339  MHO_Message::GetInstance().SendMessage(eStatus, xKEY) \
340  << "(" << sn::file_basename(__FILE__) << ":" << __LINE__ << ") " << xCONTENT; \
341  MHO_Message::GetInstance().Unlock(); \
342  } \
343  while(0)
344 
345  //INFO//////////////////////////////////////////////////////////////////////////
346  #define msg_info(xKEY, xCONTENT) \
347  do \
348  { \
349  MHO_Message::GetInstance().Lock(); \
350  MHO_Message::GetInstance().SendMessage(eInfo, xKEY) \
351  << "(" << sn::file_basename(__FILE__) << ":" << __LINE__ << ") " << xCONTENT; \
352  MHO_Message::GetInstance().Unlock(); \
353  } \
354  while(0)
355 
356  //allow debug messages when debug flag is active
357  #ifdef HOPS_ENABLE_DEBUG_MSG //this is defined as a compiler flag via build system
358 
359  //DEBUG/////////////////////////////////////////////////////////////////////////
360  #define msg_debug(xKEY, xCONTENT) \
361  do \
362  { \
363  MHO_Message::GetInstance().Lock(); \
364  MHO_Message::GetInstance().SendMessage(eDebug, xKEY) \
365  << "(" << sn::file_basename(__FILE__) << ":" << __LINE__ << ") " << xCONTENT; \
366  MHO_Message::GetInstance().Unlock(); \
367  } \
368  while(0)
369  #else
370  //debug is not enabled, so we remove them from compilation
371  #define msg_debug(xKEY, xCONTENT)
372  #endif
373 
374 #endif
375 
376 #ifdef HOPS_ENABLE_STEPWISE_CHECK //this is defined as a compiler flag via build system
377  //error check is enabled, so that we can verify a boolean return value is true
378  #define check_step_error(xVALUE, xKEY, xCONTENT) \
379  if(!xVALUE) \
380  { \
381  MHO_Message::GetInstance().SendMessage(eError, xKEY) << xCONTENT; \
382  }
383  #define check_step_fatal(xVALUE, xKEY, xCONTENT) \
384  if(!xVALUE) \
385  { \
386  MHO_Message::GetInstance().SendMessage(eFatal, xKEY) << xCONTENT; \
387  HOPS_ASSERT_THROW(xVALUE); \
388  }
389 #else
390  //error check is competely disabled
391  #define check_step_error(xVALUE, xKEY, xCONTENT)
392  #define check_step_fatal(xVALUE, xKEY, xCONTENT)
393 #endif
394 
395 } // namespace hops
396 
397 #endif
constexpr to strip path prefix from FILE macros
uses the singleton pattern (as we only have one terminal)
Definition: MHO_Message.hh:100
MHO_Message(MHO_Message const &)=delete
Deleted copy constructor (singleton).
MHO_Message & SendMessage(const MHO_MessageLevel &level, const std::string &key)
Begin a new message with a specific level and key.
Definition: MHO_Message.cc:66
void SetLegacyMessageLevel(int legacy_message_level)
Set the message level using a legacy integer interface.
Definition: MHO_Message.cc:206
MHO_Message & operator=(MHO_Message const &)=delete
Deleted copy assignment operator (singleton).
void AcceptAllKeys()
Allow all message keys (no category/library filtering).
Definition: MHO_Message.hh:131
void LimitToKeySet()
Restrict messages to a defined key set.
Definition: MHO_Message.hh:134
void RemoveAllKeys()
Remove all message keys (disables all filtering).
Definition: MHO_Message.cc:50
void SetMessageLevel(MHO_MessageLevel level)
Set the allowed message level threshold.
Definition: MHO_Message.hh:154
void RemoveKey(const std::string &key)
Remove a message key from the allowed key set.
Definition: MHO_Message.cc:31
MHO_Message(MHO_Message &&)=delete
Deleted move constructor (singleton).
MHO_Message & operator<<(const XStreamableItemType &item)
Stream an item into the current message.
Definition: MHO_Message.hh:219
void Flush()
Flush the current output stream buffer.
Definition: MHO_Message.cc:55
void Lock()
Lock the message handler for thread-safe operations.
Definition: MHO_Message.hh:125
void AddKey(const std::string &key)
Add a message key to the allowed key set.
Definition: MHO_Message.cc:21
void Unlock()
Unlock the message handler.
Definition: MHO_Message.hh:128
MHO_Message & operator=(MHO_Message &&)=delete
Deleted move assignment operator (singleton).
MHO_MessageLevel GetMessageLevel() const
Get the currently configured message level threshold.
Definition: MHO_Message.hh:162
static MHO_Message & GetInstance()
Access the singleton instance of the message handler.
Definition: MHO_Message.hh:115
Definition: MHO_ChannelLabeler.hh:17
MHO_MessageLevel
Definition: MHO_Message.hh:68
@ eStatusLevel
use to inform about unexpected state which may lead to errors
Definition: MHO_Message.hh:74
@ eDebugLevel
extra information to inform about configuration/state of program
Definition: MHO_Message.hh:76
@ eWarningLevel
use for non-fatal errors which may lead to unexpected behavior
Definition: MHO_Message.hh:73
@ eSpecialLevel
Definition: MHO_Message.hh:69
@ eErrorLevel
use for fatal errors (program termination imminent)
Definition: MHO_Message.hh:72
@ eInfoLevel
information about the current execution status of the program
Definition: MHO_Message.hh:75
@ eFatalErrorLevel
mute all messages entirely, including fatal ones
Definition: MHO_Message.hh:71
@ eSilentErrorLevel
special print level
Definition: MHO_Message.hh:70
Class MHO_MessageEndline.
Definition: MHO_Message.hh:61
Class MHO_MessageNewline.
Definition: MHO_Message.hh:55