The Gaudi Framework  v33r2 (a6f0ec87)
Message.cpp
Go to the documentation of this file.
1 /***********************************************************************************\
2 * (c) Copyright 1998-2019 CERN for the benefit of the LHCb and ATLAS collaborations *
3 * *
4 * This software is distributed under the terms of the Apache version 2 licence, *
5 * copied verbatim in the file "LICENSE". *
6 * *
7 * In applying this licence, CERN does not waive the privileges and immunities *
8 * granted to it by virtue of its status as an Intergovernmental Organization *
9 * or submit itself to any jurisdiction. *
10 \***********************************************************************************/
11 #include "GaudiKernel/Message.h"
14 #include "GaudiKernel/Time.h"
15 #include "GaudiKernel/Timing.h"
16 #include <algorithm>
17 #include <cctype>
18 #include <cstdio>
19 #include <cstdlib>
20 #include <iomanip>
21 #include <iostream>
22 #include <string>
23 
24 using namespace MSG;
25 
26 namespace {
27  // get the current time from the system and format it according to the format
28  inline std::string formattedTime( const std::string& fmt, bool universal = false ) {
29  return Gaudi::Time::current().format( !universal, fmt );
30  }
31 } // namespace
32 
33 //#############################################################################
34 // ---------------------------------------------------------------------------
35 // Routine: Constructor.
36 // Purpose:
37 // ---------------------------------------------------------------------------
38 //
39 Message::Message( const char* src, int type, const char* msg ) : m_message( msg ), m_source( src ), m_type( type ) {}
40 
41 //#############################################################################
42 // ---------------------------------------------------------------------------
43 // Routine: Constructor.
44 // Purpose:
45 // ---------------------------------------------------------------------------
46 //
48  : m_message( std::move( msg ) ), m_source( std::move( src ) ), m_type( type ) {}
49 
50 //#############################################################################
51 // ---------------------------------------------------------------------------
52 // Routine: getMessage
53 // Purpose: Get the message string.
54 // ---------------------------------------------------------------------------
55 //
56 const std::string& Message::getMessage() const { return m_message; }
57 
58 //#############################################################################
59 // ---------------------------------------------------------------------------
60 // Routine: setMessage
61 // Purpose: Set the message string.
62 // ---------------------------------------------------------------------------
63 //
65 
66 //#############################################################################
67 // ---------------------------------------------------------------------------
68 // Routine: getType
69 // Purpose: Get the message type.
70 // ---------------------------------------------------------------------------
71 //
72 int Message::getType() const { return m_type; }
73 
74 //#############################################################################
75 // ---------------------------------------------------------------------------
76 // Routine: setType
77 // Purpose: Set the message type.
78 // ---------------------------------------------------------------------------
79 //
80 void Message::setType( int msg_type ) { m_type = msg_type; }
81 
82 //#############################################################################
83 // ---------------------------------------------------------------------------
84 // Routine: getSource
85 // Purpose: Get the message source.
86 // ---------------------------------------------------------------------------
87 //
88 const std::string& Message::getSource() const { return m_source; }
89 
90 //#############################################################################
91 // ---------------------------------------------------------------------------
92 // Routine: setSource
93 // Purpose: Set the message source.
94 // ---------------------------------------------------------------------------
95 //
97 
98 //#############################################################################
99 // ---------------------------------------------------------------------------
100 // Routine: operator <<
101 // Purpose:Insert the message into a stream.
102 // ---------------------------------------------------------------------------
103 //
105  msg.makeFormattedMsg( msg.m_format );
106  stream << msg.m_formatted_msg;
107  return stream;
108 }
109 
110 //#############################################################################
111 // ---------------------------------------------------------------------------
112 // Routine: operator <
113 // Purpose: comparison operator needed for maps
114 // ---------------------------------------------------------------------------
115 //
116 bool Message::operator<( const Message& b ) {
117  return m_type < b.m_type || m_source < b.m_source || m_message < b.m_message;
118 }
119 
120 //#############################################################################
121 // ---------------------------------------------------------------------------
122 // Routine: operator ==
123 // Purpose: comparison op.
124 // ---------------------------------------------------------------------------
125 //
126 bool operator==( const Message& a, const Message& b ) {
127  return a.m_source == b.m_source && a.m_type == b.m_type && a.m_message == b.m_message;
128 }
129 
130 //#############################################################################
131 // ---------------------------------------------------------------------------
132 // Routine:
133 // Purpose: Get the format string.
134 // ---------------------------------------------------------------------------
135 //
136 const std::string& Message::getFormat() const { return m_format; }
137 
138 //#############################################################################
139 // ---------------------------------------------------------------------------
140 // Routine:
141 // Purpose: Get the default format string.
142 // ---------------------------------------------------------------------------
143 //
145 
146 //#############################################################################
147 // ---------------------------------------------------------------------------
148 // Routine:
149 // Purpose: Set the format string -
150 // use isFormatted() to check for valid format.
151 // ---------------------------------------------------------------------------
152 //
154  if ( LIKELY( !format.empty() ) ) {
156  } else {
158  }
159 }
160 
161 //#############################################################################
162 // ---------------------------------------------------------------------------
163 // Routine:
164 // Purpose: Get the time format string.
165 // ---------------------------------------------------------------------------
166 //
168 
169 //#############################################################################
170 // ---------------------------------------------------------------------------
171 // Routine:
172 // Purpose: Get the default time format string.
173 // ---------------------------------------------------------------------------
174 //
176 
177 //#############################################################################
178 // ---------------------------------------------------------------------------
179 // Routine:
180 // Purpose: Set the time format string -
181 // use isFormatted() to check for valid format.
182 // ---------------------------------------------------------------------------
183 //
184 void Message::setTimeFormat( std::string timeFormat ) const {
185  m_time_format = ( timeFormat.empty() ? DEFAULT_TIME_FORMAT : std::move( timeFormat ) );
186 }
187 
188 //#############################################################################
189 // ---------------------------------------------------------------------------
190 // Routine: makeFormattedMsg
191 // Purpose: This formats the message according to the format string.
192 // ---------------------------------------------------------------------------
193 //
196  auto i = format.begin();
197  while ( i != format.end() ) {
198 
199  // Output format string until format statement found.
200  while ( i != format.end() && *i != FORMAT_PREFIX ) m_formatted_msg += *i++;
201 
202  // Test for end of format string.
203  if ( i == format.end() ) break;
204  i++;
205 
206  // Find type of formatting.
207  std::string this_format;
208  while ( i != format.end() && *i != FORMAT_PREFIX && *i != MESSAGE && *i != TYPE && *i != SOURCE && *i != FILL &&
209  *i != WIDTH && *i != TIME && *i != UTIME && *i != SLOT && *i != EVTNUM && *i != THREAD && *i != EVENTID &&
210  *i != JUSTIFY_LEFT && *i != JUSTIFY_RIGHT ) {
211  this_format += *i++;
212  }
213 
214  // Reached end of string with improper format.
215  if ( i == format.end() ) {
216  invalidFormat();
217  break;
218  }
219 
220  this_format += *i++;
221  decodeFormat( this_format );
222  }
223 }
224 
225 //#############################################################################
226 // ---------------------------------------------------------------------------
227 // Routine: decodeFormat
228 // Purpose: This the work horse that checks for a valid format string.
229 // ---------------------------------------------------------------------------
230 //
232  if ( !format.empty() ) {
233  const char FORMAT_TYPE = format[format.length() - 1];
234  const std::string FORMAT_PARAM = format.substr( 0, format.length() - 1 );
235 
236  // Now test the format.
238  switch ( FORMAT_TYPE ) {
239  case FILL:
240  if ( FORMAT_PARAM.length() == 1 ) {
241  m_fill = FORMAT_PARAM[0];
242  } else
243  invalidFormat();
244  break;
245 
246  case TIME: {
247  sizeField( formattedTime( m_time_format ) );
248  } break;
249 
250  case UTIME: {
251  sizeField( formattedTime( m_time_format, true ) );
252  } break;
253 
254  case THREAD: {
255  std::ostringstream ost;
256  // ost << "0x" << std::hex << pthread_self();
257  ost << "0x" << std::hex << m_ecThrd;
258  const std::string& thrStr( ost.str() );
259  sizeField( thrStr );
260  } break;
261 
262  case SLOT: {
263  std::ostringstream ost;
265  sizeField( ost.str() );
266  } break;
267 
268  case EVTNUM: {
269  std::ostringstream ost;
271  sizeField( ost.str() );
272  } break;
273 
274  case EVENTID: {
275  std::ostringstream ost;
276  if ( m_ecEvtId.isValid() ) { ost << m_ecEvtId; }
277  sizeField( ost.str() );
278  } break;
279 
280  case MESSAGE:
281  sizeField( m_message );
282  break;
283 
284  case SOURCE:
285  sizeField( m_source );
286  break;
287 
288  case TYPE:
289  switch ( m_type ) {
290 #define SET( x ) \
291  case x: \
292  level = #x; \
293  break
294  SET( NIL );
295  SET( VERBOSE );
296  SET( DEBUG );
297  SET( INFO );
298  SET( WARNING );
299  SET( ERROR );
300  SET( FATAL );
301  case ALWAYS:
302  level = "SUCCESS";
303  break;
304  default:
305  level = "UNKNOWN";
306  break;
307 #undef SET
308  }
309  sizeField( level );
310  break;
311 
312  case FORMAT_PREFIX:
314  break;
315  case JUSTIFY_RIGHT:
316  m_left = false;
317  break;
318  case JUSTIFY_LEFT:
319  m_left = true;
320  break;
321  case WIDTH:
322  setWidth( FORMAT_PARAM );
323  break;
324  default:
325  invalidFormat();
326  break;
327  }
328  } else
329  invalidFormat();
330 }
331 
332 //#############################################################################
333 // ---------------------------------------------------------------------------
334 // Routine: invalidFormat.
335 // Purpose: called when invalid format found.
336 // ---------------------------------------------------------------------------
337 //
338 
340 
341 //#############################################################################
342 // ---------------------------------------------------------------------------
343 // Routine: setWidth
344 // Purpose: Sets the minimum width of a stream field.
345 // ---------------------------------------------------------------------------
346 //
347 namespace {
348  // Check that a container only contains digits.
349  constexpr struct all_digit_t {
350  template <typename C>
351  bool operator()( const C& c ) const {
352  return std::all_of( std::begin( c ), std::end( c ),
353  []( typename C::const_reference i ) { return isdigit( i ); } );
354  }
355  } all_digits{};
356 } // namespace
357 
358 void Message::setWidth( const std::string& formatArg ) const {
359  // Convert string to int, if string contains digits only...
360  if ( all_digits( formatArg ) )
361  m_width = std::stoi( formatArg );
362  else
363  invalidFormat();
364 }
365 
366 //#############################################################################
367 // ---------------------------------------------------------------------------
368 // Routine: sizeField
369 // Purpose: Truncates or pads the text to m_width as necessary
370 // ---------------------------------------------------------------------------
371 //
372 
373 void Message::sizeField( const std::string& text ) const {
374  std::string newText;
375  if ( m_width == 0 || m_width == static_cast<int>( text.length() ) ) {
376  newText = text;
377  } else {
378 
379  // Truncate the text if it is too long.
380  if ( m_width < static_cast<int>( text.length() ) ) {
381  newText = text.substr( 0, m_width );
382  for ( int i = 0, j = newText.length() - 1; i < 3 && j >= 0; ++i, --j ) newText[j] = '.';
383  }
384 
385  // Pad the text.
386  else {
387  newText = std::string( m_width, m_fill );
388  if ( m_left )
389  newText.replace( newText.begin(), newText.begin() + text.length(), text.begin(), text.end() );
390  else
391  newText.replace( newText.end() - text.length(), newText.end(), text.begin(), text.end() );
392  }
393  }
394 
395  m_formatted_msg += newText;
396 }
static const char TYPE
The character used to indicate that the message type should be printed.
Definition: Message.h:135
bool m_left
The message alignment.
Definition: Message.h:110
static const char MESSAGE
The character used to indicate that the message should be printed.
Definition: Message.h:132
char m_fill
Current fill character.
Definition: Message.h:108
static const char JUSTIFY_LEFT
The character used to indicate start of left text justification.
Definition: Message.h:126
T empty(T... args)
void sizeField(const std::string &text) const
Truncate or pad the output string to the field width as necessary.
Definition: Message.cpp:373
void decodeFormat(const std::string &format) const
Decode format.
Definition: Message.cpp:231
GAUDI_API std::string format(const char *,...)
MsgStream format utility "a la sprintf(...)".
Definition: MsgStream.cpp:119
std::string m_formatted_msg
Formatted message.
Definition: Message.h:107
static const char THREAD
The character used to indicate that the thread ID should be printed.
Definition: Message.h:153
std::string m_time_format
Time format string.
Definition: Message.h:106
int getType() const
Get the message type.
Definition: Message.cpp:72
Message()=default
Default constructor.
bool operator<(const Message &test)
Needed to build maps.
Definition: Message.cpp:116
bool operator==(const Message &a, const Message &b)
Insert the message into a stream.
Definition: Message.cpp:126
EventContext::ContextEvt_t m_ecEvt
Event number.
Definition: Message.h:115
static Time current()
Returns the current time.
Definition: Time.cpp:119
std::string m_message
The message text.
Definition: Message.h:102
void setMessage(std::string msg)
Set the message string.
Definition: Message.cpp:64
STL namespace.
void setType(int msg_type)
Set the message type.
Definition: Message.cpp:80
void setWidth(const std::string &formatArg) const
Set the width of a stream.
Definition: Message.cpp:358
T end(T... args)
#define SET(x)
EventIDBase m_ecEvtId
Full event ID.
Definition: Message.h:116
static const char EVENTID
The character used to indicate that the full event ID should be printed.
Definition: Message.h:156
void setSource(std::string src)
Set the message source.
Definition: Message.cpp:96
const std::string & getSource() const
Get the message source.
Definition: Message.cpp:88
void setFormat(std::string msg) const
Set the format string.
Definition: Message.cpp:153
STL class.
static constexpr ContextEvt_t INVALID_CONTEXT_EVT
Definition: EventContext.h:40
T replace(T... args)
static const std::string getDefaultTimeFormat()
Get the default time format string.
Definition: Message.cpp:175
void invalidFormat() const
Called when an invalid format string is encountered.
Definition: Message.cpp:339
std::ostream & operator<<(std::ostream &stream, const Message &msg)
Insert the message into a stream.
Definition: Message.cpp:104
static const std::string getDefaultFormat()
Get the default format string.
Definition: Message.cpp:144
static constexpr ContextID_t INVALID_CONTEXT_ID
Definition: EventContext.h:39
T str(T... args)
static const char EVTNUM
The character used to indicate that the event number should be printed.
Definition: Message.h:150
T clear(T... args)
T move(T... args)
EventContext::ContextID_t m_ecSlot
Event slot.
Definition: Message.h:114
#define LIKELY(x)
Definition: Kernel.h:105
bool isValid() const
Definition: EventIDBase.h:157
const std::string & getFormat() const
Get the format string.
Definition: Message.cpp:136
void makeFormattedMsg(const std::string &format) const
Format the message.
Definition: Message.cpp:194
int m_width
Current field width.
Definition: Message.h:109
static const char TIME
The character used to indicate that the message timestamp should be printed.
Definition: Message.h:138
std::string m_format
The format string.
Definition: Message.h:105
T length(T... args)
std::string format(bool local, std::string spec="%c") const
Format the time using strftime.
Definition: Time.cpp:262
static const char JUSTIFY_RIGHT
The character used to indicate start of right text justification.
Definition: Message.h:129
void setTimeFormat(std::string timeFormat) const
Set the time format string.
Definition: Message.cpp:184
static const char UTIME
The character used to indicate that the message timestamp should be printed in UTC time.
Definition: Message.h:141
The Message class.
Definition: Message.h:27
static const char SLOT
The character used to indicate that the slot number should be printed.
Definition: Message.h:147
T begin(T... args)
const std::string & getMessage() const
Get the message string.
Definition: Message.cpp:56
pthread_t m_ecThrd
Thread ID.
Definition: Message.h:117
T all_of(T... args)
static const char FILL
The character used to indicate that the previous character is used to pad fields if the text is not l...
Definition: Message.h:159
Print levels enumeration.
Definition: IMessageSvc.h:24
T hex(T... args)
T substr(T... args)
static constexpr const char * DEFAULT_FORMAT
The default message format.
Definition: Message.h:166
static const char FORMAT_PREFIX
The character used to prefix formatting commands.
Definition: Message.h:123
std::string m_source
The message source.
Definition: Message.h:103
STL class.
static const char WIDTH
The character used to indicate that the previous decimal characters should be taken as the field widt...
Definition: Message.h:162
T stoi(T... args)
static const char SOURCE
The character used to indicate that the message source should be printed.
Definition: Message.h:144
static constexpr const char * DEFAULT_TIME_FORMAT
The default time format (accepts strftime formatters plus %f for milliseconds).
Definition: Message.h:169
const std::string & getTimeFormat() const
Get the time format string.
Definition: Message.cpp:167
int m_type
The message type/level.
Definition: Message.h:104