The Gaudi Framework  v36r1 (3e2fb5a8)
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 //
96 void Message::setSource( std::string_view src ) { m_source = src; }
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 operator<( const Message& lhs, const Message& rhs ) {
117  return lhs.m_type < rhs.m_type || lhs.m_source < rhs.m_source || lhs.m_message < rhs.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 != COMP &&
209  *i != FILL && *i != WIDTH && *i != TIME && *i != UTIME && *i != SLOT && *i != EVTNUM && *i != THREAD &&
210  *i != EVENTID && *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 COMP:
289  sizeField( m_source, true );
290  break;
291 
292  case TYPE:
293  switch ( m_type ) {
294 #define SET( x ) \
295  case x: \
296  level = #x; \
297  break
298  SET( NIL );
299  SET( VERBOSE );
300  SET( DEBUG );
301  SET( INFO );
302  SET( WARNING );
303  SET( ERROR );
304  SET( FATAL );
305  case ALWAYS:
306  level = "SUCCESS";
307  break;
308  default:
309  level = "UNKNOWN";
310  break;
311 #undef SET
312  }
313  sizeField( level );
314  break;
315 
316  case FORMAT_PREFIX:
318  break;
319  case JUSTIFY_RIGHT:
320  m_left = false;
321  break;
322  case JUSTIFY_LEFT:
323  m_left = true;
324  break;
325  case WIDTH:
326  setWidth( FORMAT_PARAM );
327  break;
328  default:
329  invalidFormat();
330  break;
331  }
332  } else
333  invalidFormat();
334 }
335 
336 //#############################################################################
337 // ---------------------------------------------------------------------------
338 // Routine: invalidFormat.
339 // Purpose: called when invalid format found.
340 // ---------------------------------------------------------------------------
341 //
342 
344 
345 //#############################################################################
346 // ---------------------------------------------------------------------------
347 // Routine: setWidth
348 // Purpose: Sets the minimum width of a stream field.
349 // ---------------------------------------------------------------------------
350 //
351 namespace {
352  // Check that a container only contains digits.
353  constexpr struct all_digit_t {
354  template <typename C>
355  bool operator()( const C& c ) const {
356  return std::all_of( std::begin( c ), std::end( c ),
357  []( typename C::const_reference i ) { return isdigit( i ); } );
358  }
359  } all_digits{};
360 } // namespace
361 
362 void Message::setWidth( const std::string& formatArg ) const {
363  // Convert string to int, if string contains digits only...
364  if ( all_digits( formatArg ) )
365  m_width = std::stoi( formatArg );
366  else
367  invalidFormat();
368 }
369 
370 //#############################################################################
371 // ---------------------------------------------------------------------------
372 // Routine: sizeField
373 // Purpose: Truncates or pads the text to m_width as necessary
374 // ---------------------------------------------------------------------------
375 //
376 
377 void Message::sizeField( const std::string& text, bool middle ) const {
378  std::string newText;
379  if ( m_width == 0 || m_width == static_cast<int>( text.length() ) ) {
380  newText = text;
381  } else {
382  const size_t width = static_cast<size_t>( m_width );
383  // Truncate the text if it is too long.
384  if ( width < text.length() ) {
385  if ( middle && width > 4 ) { // truncate text in the middle
386  size_t iTrunc;
387  // If the text is a component-name-chain, try showing the last component
388  const size_t iDot = text.rfind( '.' );
389  if ( iDot != std::string::npos && width > text.length() - iDot + 3 ) {
390  iTrunc = iDot + 1;
391  } else {
392  // No dot or text after dot too long
393  iTrunc = text.length() - width / 2;
394  }
395  const size_t taillength = text.length() - iTrunc;
396  const size_t frontlength = width - taillength - 3;
397  newText.reserve( width );
398  newText.append( text, 0, frontlength );
399  newText.append( 3, '.' );
400  newText.append( text, iTrunc );
401  } // else if middle
402  else { // truncate text at the end
403  newText = text.substr( 0, m_width );
404  for ( int i = 0, j = newText.length() - 1; i < 3 && j >= 0; ++i, --j ) newText[j] = '.';
405  }
406  }
407  // Pad the text.
408  else {
409  newText = std::string( m_width, m_fill );
410  if ( m_left )
411  newText.replace( newText.begin(), newText.begin() + text.length(), text.begin(), text.end() );
412  else
413  newText.replace( newText.end() - text.length(), newText.end(), text.begin(), text.end() );
414  }
415  }
416 
417  m_formatted_msg += newText;
418 }
MSG
Print levels enumeration.
Definition: IMessageSvc.h:24
Message::FILL
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:162
Message::m_ecEvt
EventContext::ContextEvt_t m_ecEvt
Event number.
Definition: Message.h:115
Message::DEFAULT_FORMAT
static constexpr const char * DEFAULT_FORMAT
The default message format.
Definition: Message.h:169
Message::FORMAT_PREFIX
static const char FORMAT_PREFIX
The character used to prefix formatting commands.
Definition: Message.h:123
Write.stream
stream
Definition: Write.py:31
std::string
STL class.
Message::m_format
std::string m_format
The format string.
Definition: Message.h:105
Message::TYPE
static const char TYPE
The character used to indicate that the message type should be printed.
Definition: Message.h:135
Message::m_fill
char m_fill
Current fill character.
Definition: Message.h:108
std::move
T move(T... args)
Message::setTimeFormat
void setTimeFormat(std::string timeFormat) const
Set the time format string.
Definition: Message.cpp:184
MSG::INFO
@ INFO
Definition: IMessageSvc.h:25
Message::getTimeFormat
const std::string & getTimeFormat() const
Get the time format string.
Definition: Message.cpp:167
Message::SOURCE
static const char SOURCE
The character used to indicate that the message source should be printed.
Definition: Message.h:144
std::string::reserve
T reserve(T... args)
SuperAlgDynamicGraph.DEBUG
DEBUG
Definition: SuperAlgDynamicGraph.py:67
Message::getMessage
const std::string & getMessage() const
Get the message string.
Definition: Message.cpp:56
Message::m_ecThrd
pthread_t m_ecThrd
Thread ID.
Definition: Message.h:117
std::string::length
T length(T... args)
Message::sizeField
void sizeField(const std::string &text, bool middle=false) const
Truncate or pad the output string to the field width. If middle is true, cut the central part,...
Definition: Message.cpp:377
Message::WIDTH
static const char WIDTH
The character used to indicate that the previous decimal characters should be taken as the field widt...
Definition: Message.h:165
GaudiMP.FdsRegistry.msg
msg
Definition: FdsRegistry.py:18
Message::DEFAULT_TIME_FORMAT
static constexpr const char * DEFAULT_TIME_FORMAT
The default time format (accepts strftime formatters plus %f for milliseconds).
Definition: Message.h:172
EventContext::INVALID_CONTEXT_ID
static constexpr ContextID_t INVALID_CONTEXT_ID
Definition: EventContext.h:39
MSG::WARNING
@ WARNING
Definition: IMessageSvc.h:25
gaudirun.c
c
Definition: gaudirun.py:509
std::all_of
T all_of(T... args)
Message::EVENTID
static const char EVENTID
The character used to indicate that the full event ID should be printed.
Definition: Message.h:159
Message::EVTNUM
static const char EVTNUM
The character used to indicate that the event number should be printed.
Definition: Message.h:153
Message::m_left
bool m_left
The message alignment.
Definition: Message.h:110
IMessageSvc.h
std::string::clear
T clear(T... args)
Message::Message
Message()=default
Default constructor.
std::string::replace
T replace(T... args)
operator<<
std::ostream & operator<<(std::ostream &stream, const Message &msg)
Definition: Message.cpp:104
std::hex
T hex(T... args)
Message::getFormat
const std::string & getFormat() const
Get the format string.
Definition: Message.cpp:136
Message::getDefaultFormat
static const std::string getDefaultFormat()
Get the default format string.
Definition: Message.cpp:144
Message::m_width
int m_width
Current field width.
Definition: Message.h:109
EventIDBase::isValid
bool isValid() const
Definition: EventIDBase.h:157
Message::m_type
int m_type
The message type/level.
Definition: Message.h:104
std::stoi
T stoi(T... args)
Message::UTIME
static const char UTIME
The character used to indicate that the message timestamp should be printed in UTC time.
Definition: Message.h:141
Message::setMessage
void setMessage(std::string msg)
Set the message string.
Definition: Message.cpp:64
Gaudi::Time::format
std::string format(bool local, std::string spec="%c") const
Format the time using strftime.
Definition: Time.cpp:262
Message::m_ecSlot
EventContext::ContextID_t m_ecSlot
Event slot.
Definition: Message.h:114
Message
Definition: Message.h:27
std::ostream
STL class.
LIKELY
#define LIKELY(x)
Definition: Kernel.h:105
EventContext::INVALID_CONTEXT_EVT
static constexpr ContextEvt_t INVALID_CONTEXT_EVT
Definition: EventContext.h:40
Message::setSource
void setSource(std::string_view src)
Set the message source.
Definition: Message.cpp:96
Message::setFormat
void setFormat(std::string msg) const
Set the format string.
Definition: Message.cpp:153
Message::invalidFormat
void invalidFormat() const
Called when an invalid format string is encountered.
Definition: Message.cpp:343
format
GAUDI_API std::string format(const char *,...)
MsgStream format utility "a la sprintf(...)".
Definition: MsgStream.cpp:119
Message::m_message
std::string m_message
The message text.
Definition: Message.h:102
Message::TIME
static const char TIME
The character used to indicate that the message timestamp should be printed.
Definition: Message.h:138
gaudirun.level
level
Definition: gaudirun.py:346
operator==
bool operator==(const Message &a, const Message &b)
Definition: Message.cpp:126
MSG::FATAL
@ FATAL
Definition: IMessageSvc.h:25
std::string::append
T append(T... args)
Message::JUSTIFY_LEFT
static const char JUSTIFY_LEFT
The character used to indicate start of left text justification.
Definition: Message.h:126
Timing.h
std::string::substr
T substr(T... args)
std::ostringstream
STL class.
Message::COMP
static const char COMP
The character used to indicate that the message source should be printed, focus on the component.
Definition: Message.h:147
gaudirun.type
type
Definition: gaudirun.py:154
ThreadLocalContext.h
MSG::VERBOSE
@ VERBOSE
Definition: IMessageSvc.h:25
Message::m_source
std::string m_source
The message source.
Definition: Message.h:103
MSG::ALWAYS
@ ALWAYS
Definition: IMessageSvc.h:25
std::string::begin
T begin(T... args)
Time.h
Message::MESSAGE
static const char MESSAGE
The character used to indicate that the message should be printed.
Definition: Message.h:132
std
STL namespace.
MSG::NIL
@ NIL
Definition: IMessageSvc.h:25
MSG::ERROR
@ ERROR
Definition: IMessageSvc.h:25
fmt
Gaudi::Time::current
static Time current()
Returns the current time.
Definition: Time.cpp:119
Message::getSource
const std::string & getSource() const
Get the message source.
Definition: Message.cpp:88
Message::SLOT
static const char SLOT
The character used to indicate that the slot number should be printed.
Definition: Message.h:150
Message::THREAD
static const char THREAD
The character used to indicate that the thread ID should be printed.
Definition: Message.h:156
std::string::empty
T empty(T... args)
Message::m_ecEvtId
EventIDBase m_ecEvtId
Full event ID.
Definition: Message.h:116
Message::m_formatted_msg
std::string m_formatted_msg
Formatted message.
Definition: Message.h:107
Message::m_time_format
std::string m_time_format
Time format string.
Definition: Message.h:106
std::ostringstream::str
T str(T... args)
std::string::end
T end(T... args)
Message::getType
int getType() const
Get the message type.
Definition: Message.cpp:72
Message::decodeFormat
void decodeFormat(const std::string &format) const
Decode format.
Definition: Message.cpp:231
Message::setType
void setType(int msg_type)
Set the message type.
Definition: Message.cpp:80
operator<
bool operator<(const Message &lhs, const Message &rhs)
Definition: Message.cpp:116
Message::makeFormattedMsg
void makeFormattedMsg(const std::string &format) const
Format the message.
Definition: Message.cpp:194
std::string::rfind
T rfind(T... args)
SET
#define SET(x)
Message::setWidth
void setWidth(const std::string &formatArg) const
Set the width of a stream.
Definition: Message.cpp:362
Message.h
Message::JUSTIFY_RIGHT
static const char JUSTIFY_RIGHT
The character used to indicate start of right text justification.
Definition: Message.h:129
Message::getDefaultTimeFormat
static const std::string getDefaultTimeFormat()
Get the default time format string.
Definition: Message.cpp:175