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 <cstdint>
5 #include <cstdlib>
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 
98 #define MSG_ALIGN_PAD 32
99 
102 {
103 
104  public:
106  MHO_Message(MHO_Message const&) = delete;
110  MHO_Message& operator=(MHO_Message const&) = delete;
113 
118  {
119  static MHO_Message instance;
120  return instance;
121  }
122 
124  void Lock() { fMutex.lock(); };
125 
127  void Unlock() { fMutex.unlock(); };
128 
130  void AcceptAllKeys() { fAcceptAllKeys = true; }
131 
133  void LimitToKeySet() { fAcceptAllKeys = false; }
134 
137  void AddKey(const std::string& key);
138 
141  void RemoveKey(const std::string& key);
142 
144  void RemoveAllKeys();
145 
147  void Flush();
148 
151  void SetMessageLevel(MHO_MessageLevel level) { fAllowedLevel = level; }
152 
155  void SetLegacyMessageLevel(int legacy_message_level);
156 
159  MHO_MessageLevel GetMessageLevel() const { return fAllowedLevel; }
160 
166  MHO_Message& SendMessage(const MHO_MessageLevel& level, const std::string& key);
167  MHO_Message& SendMessage(const MHO_MessageLevel& level, const char* key);
168 
174  template< class XStreamableItemType > MHO_Message& operator<<(const XStreamableItemType& item);
175 
178 
179  private:
180  //no public access to constructor
181  //set up the stream, for now just point to std::cout
182  //but we may want to allow this to be configured post-construction
183  //perhaps we should also pipe information into log file(s)
184  MHO_Message()
185  : fTerminalStream(&std::cout), fAllowedLevel(eStatus), fCurrentLevel(eInfo), fCurrentKeyIsAllowed(false),
186  fAcceptAllKeys(false), fWasLastLineNewLine(false)
187  {
188  fPadding = std::string(MSG_ALIGN_PAD, ' ');
189  };
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  std::ostream* fTerminalStream; //stream to terminal output
198  std::set< std::string > fKeys; //keys of which messages we will accept for output
199  MHO_MessageLevel fAllowedLevel;
200 
201  MHO_MessageLevel fCurrentLevel; //level of the current message
202  bool fCurrentKeyIsAllowed; //current key is in allowed set
203  bool fAcceptAllKeys;
204  std::stringstream fMessageStream; //the message container to be filled/flushed
205 
206  static std::string fRed; //fatal
207  static std::string fYellow; //error
208  static std::string fOrange; //orange
209  static std::string fBlue; //status
210  static std::string fGreen; //info
211  static std::string fCyan; //debug
212  static std::string fWhite; //default
213  static std::string fColorSuffix; //color close
214 
215  bool fWasLastLineNewLine;
216 
217  //whitespace padding
218  std::string fPadding;
219 };
220 
221 template< class XStreamableItemType > MHO_Message& MHO_Message::operator<<(const XStreamableItemType& item)
222 {
223  if(PassMessage())
224  {
225  fMessageStream << item;
226  }
227  return GetInstance();
228 }
229 
230 //abuse do-while for multiline message macros
231 
232 //FATAL/////////////////////////////////////////////////////////////////////////
233 
234 #ifndef HOPS_EXTRA_VERBOSE_MSG
235 
236  #define msg_fatal(xKEY, xCONTENT) \
237  do \
238  { \
239  MHO_Message::GetInstance().Lock(); \
240  MHO_Message::GetInstance().SendMessage(eFatal, xKEY) << xCONTENT; \
241  MHO_Message::GetInstance().Unlock(); \
242  } \
243  while(0)
244 
245  //ERROR/////////////////////////////////////////////////////////////////////////
246  #define msg_error(xKEY, xCONTENT) \
247  do \
248  { \
249  MHO_Message::GetInstance().Lock(); \
250  MHO_Message::GetInstance().SendMessage(eError, xKEY) << xCONTENT; \
251  MHO_Message::GetInstance().Unlock(); \
252  } \
253  while(0)
254 
255  //WARNING///////////////////////////////////////////////////////////////////////
256  #define msg_warn(xKEY, xCONTENT) \
257  do \
258  { \
259  MHO_Message::GetInstance().Lock(); \
260  MHO_Message::GetInstance().SendMessage(eWarning, xKEY) << xCONTENT; \
261  MHO_Message::GetInstance().Unlock(); \
262  } \
263  while(0)
264 
265  //STATUS////////////////////////////////////////////////////////////////////////
266  #define msg_status(xKEY, xCONTENT) \
267  do \
268  { \
269  MHO_Message::GetInstance().Lock(); \
270  MHO_Message::GetInstance().SendMessage(eStatus, xKEY) << xCONTENT; \
271  MHO_Message::GetInstance().Unlock(); \
272  } \
273  while(0)
274 
275  //INFO//////////////////////////////////////////////////////////////////////////
276  #define msg_info(xKEY, xCONTENT) \
277  do \
278  { \
279  MHO_Message::GetInstance().Lock(); \
280  MHO_Message::GetInstance().SendMessage(eInfo, xKEY) << xCONTENT; \
281  MHO_Message::GetInstance().Unlock(); \
282  } \
283  while(0)
284 
285  //allow debug messages when debug flag is active
286  #ifdef HOPS_ENABLE_DEBUG_MSG //this is defined as a compiler flag via build system
287 
288  //DEBUG/////////////////////////////////////////////////////////////////////////
289  #define msg_debug(xKEY, xCONTENT) \
290  do \
291  { \
292  MHO_Message::GetInstance().Lock(); \
293  MHO_Message::GetInstance().SendMessage(eDebug, xKEY) << xCONTENT; \
294  MHO_Message::GetInstance().Unlock(); \
295  } \
296  while(0)
297  #else
298  //debug is not enabled, so we remove them from compilation
299  #define msg_debug(xKEY, xCONTENT)
300  #endif
301 
302 #else //HOPS_EXTRA_VERBOSE_MSG is defined
303 
304  #define msg_fatal(xKEY, xCONTENT) \
305  do \
306  { \
307  MHO_Message::GetInstance().Lock(); \
308  MHO_Message::GetInstance().SendMessage(eFatal, xKEY) \
309  << "(" << sn::file_basename(__FILE__) << ":" << __LINE__ << ") " << xCONTENT; \
310  MHO_Message::GetInstance().Unlock(); \
311  } \
312  while(0)
313 
314  //ERROR/////////////////////////////////////////////////////////////////////////
315  #define msg_error(xKEY, xCONTENT) \
316  do \
317  { \
318  MHO_Message::GetInstance().Lock(); \
319  MHO_Message::GetInstance().SendMessage(eError, xKEY) \
320  << "(" << sn::file_basename(__FILE__) << ":" << __LINE__ << ") " << xCONTENT; \
321  MHO_Message::GetInstance().Unlock(); \
322  } \
323  while(0)
324 
325  //WARNING///////////////////////////////////////////////////////////////////////
326  #define msg_warn(xKEY, xCONTENT) \
327  do \
328  { \
329  MHO_Message::GetInstance().Lock(); \
330  MHO_Message::GetInstance().SendMessage(eWarning, xKEY) \
331  << "(" << sn::file_basename(__FILE__) << ":" << __LINE__ << ") " << xCONTENT; \
332  MHO_Message::GetInstance().Unlock(); \
333  } \
334  while(0)
335 
336  //STATUS////////////////////////////////////////////////////////////////////////
337  #define msg_status(xKEY, xCONTENT) \
338  do \
339  { \
340  MHO_Message::GetInstance().Lock(); \
341  MHO_Message::GetInstance().SendMessage(eStatus, xKEY) \
342  << "(" << sn::file_basename(__FILE__) << ":" << __LINE__ << ") " << xCONTENT; \
343  MHO_Message::GetInstance().Unlock(); \
344  } \
345  while(0)
346 
347  //INFO//////////////////////////////////////////////////////////////////////////
348  #define msg_info(xKEY, xCONTENT) \
349  do \
350  { \
351  MHO_Message::GetInstance().Lock(); \
352  MHO_Message::GetInstance().SendMessage(eInfo, xKEY) \
353  << "(" << sn::file_basename(__FILE__) << ":" << __LINE__ << ") " << xCONTENT; \
354  MHO_Message::GetInstance().Unlock(); \
355  } \
356  while(0)
357 
358  //allow debug messages when debug flag is active
359  #ifdef HOPS_ENABLE_DEBUG_MSG //this is defined as a compiler flag via build system
360 
361  //DEBUG/////////////////////////////////////////////////////////////////////////
362  #define msg_debug(xKEY, xCONTENT) \
363  do \
364  { \
365  MHO_Message::GetInstance().Lock(); \
366  MHO_Message::GetInstance().SendMessage(eDebug, xKEY) \
367  << "(" << sn::file_basename(__FILE__) << ":" << __LINE__ << ") " << xCONTENT; \
368  MHO_Message::GetInstance().Unlock(); \
369  } \
370  while(0)
371  #else
372  //debug is not enabled, so we remove them from compilation
373  #define msg_debug(xKEY, xCONTENT)
374  #endif
375 
376 #endif
377 
378 #ifdef HOPS_ENABLE_STEPWISE_CHECK //this is defined as a compiler flag via build system
379  //error check is enabled, so that we can verify a boolean return value is true
380  #define check_step_error(xVALUE, xKEY, xCONTENT) \
381  if(!xVALUE) \
382  { \
383  MHO_Message::GetInstance().SendMessage(eError, xKEY) << xCONTENT; \
384  }
385  #define check_step_fatal(xVALUE, xKEY, xCONTENT) \
386  if(!xVALUE) \
387  { \
388  MHO_Message::GetInstance().SendMessage(eFatal, xKEY) << xCONTENT; \
389  HOPS_ASSERT_THROW(xVALUE); \
390  }
391 #else
392  //error check is competely disabled
393  #define check_step_error(xVALUE, xKEY, xCONTENT)
394  #define check_step_fatal(xVALUE, xKEY, xCONTENT)
395 #endif
396 
397 } // namespace hops
398 
399 #endif
#define MSG_ALIGN_PAD
Definition: MHO_Message.hh:98
constexpr to strip path prefix from FILE macros
uses the singleton pattern (as we only have one terminal)
Definition: MHO_Message.hh:102
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:45
void SetLegacyMessageLevel(int legacy_message_level)
Set the message level using a legacy integer interface.
Definition: MHO_Message.cc:189
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:130
void LimitToKeySet()
Restrict messages to a defined key set.
Definition: MHO_Message.hh:133
void RemoveAllKeys()
Remove all message keys (disables all filtering).
Definition: MHO_Message.cc:29
void SetMessageLevel(MHO_MessageLevel level)
Set the allowed message level threshold.
Definition: MHO_Message.hh:151
void RemoveKey(const std::string &key)
Remove a message key from the allowed key set.
Definition: MHO_Message.cc:20
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:221
void Flush()
Flush the current output stream buffer.
Definition: MHO_Message.cc:34
void Lock()
Lock the message handler for thread-safe operations.
Definition: MHO_Message.hh:124
void AddKey(const std::string &key)
Add a message key to the allowed key set.
Definition: MHO_Message.cc:15
void Unlock()
Unlock the message handler.
Definition: MHO_Message.hh:127
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:159
static MHO_Message & GetInstance()
Access the singleton instance of the message handler.
Definition: MHO_Message.hh:117
Definition: MHO_AdhocFlagging.hh:18
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