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