The Gaudi Framework  v36r16 (ea80daf8)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
Message.cpp
Go to the documentation of this file.
1 /***********************************************************************************\
2 * (c) Copyright 1998-2022 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 )
40  : Message( std::string( src ), type, std::string( msg ) ) {}
41 
42 //#############################################################################
43 // ---------------------------------------------------------------------------
44 // Routine: Constructor.
45 // Purpose:
46 // ---------------------------------------------------------------------------
47 //
49  : m_message( std::move( msg ) ), m_source( std::move( src ) ), m_type( type ) {
50 
52  m_ecSlot = ctx.slot();
53  m_ecEvt = ctx.evt();
54  m_ecEvtId = ctx.eventID();
55  m_ecThrd = pthread_self();
56 }
57 
58 //#############################################################################
59 // ---------------------------------------------------------------------------
60 // Routine: operator <<
61 // Purpose:Insert the message into a stream.
62 // ---------------------------------------------------------------------------
63 //
65  msg.makeFormattedMsg( msg.m_format );
66  stream << msg.m_formatted_msg;
67  return stream;
68 }
69 
70 //#############################################################################
71 // ---------------------------------------------------------------------------
72 // Routine: operator <
73 // Purpose: comparison operator needed for maps
74 // ---------------------------------------------------------------------------
75 //
76 bool operator<( const Message& lhs, const Message& rhs ) {
77  return lhs.m_type < rhs.m_type || lhs.m_source < rhs.m_source || lhs.m_message < rhs.m_message;
78 }
79 
80 //#############################################################################
81 // ---------------------------------------------------------------------------
82 // Routine: operator ==
83 // Purpose: comparison op.
84 // ---------------------------------------------------------------------------
85 //
86 bool operator==( const Message& a, const Message& b ) {
87  return a.m_source == b.m_source && a.m_type == b.m_type && a.m_message == b.m_message;
88 }
89 
90 //#############################################################################
91 // ---------------------------------------------------------------------------
92 // Routine:
93 // Purpose: Set the format string -
94 // use isFormatted() to check for valid format.
95 // ---------------------------------------------------------------------------
96 //
98  if ( !format.empty() ) {
100  } else {
102  }
103 }
104 
105 //#############################################################################
106 // ---------------------------------------------------------------------------
107 // Routine:
108 // Purpose: Set the time format string -
109 // use isFormatted() to check for valid format.
110 // ---------------------------------------------------------------------------
111 //
112 void Message::setTimeFormat( std::string timeFormat ) const {
113  m_time_format = ( timeFormat.empty() ? DEFAULT_TIME_FORMAT : std::move( timeFormat ) );
114 }
115 
116 //#############################################################################
117 // ---------------------------------------------------------------------------
118 // Routine: makeFormattedMsg
119 // Purpose: This formats the message according to the format string.
120 // ---------------------------------------------------------------------------
121 //
124  auto i = format.begin();
125  while ( i != format.end() ) {
126 
127  // Output format string until format statement found.
128  while ( i != format.end() && *i != FORMAT_PREFIX ) m_formatted_msg += *i++;
129 
130  // Test for end of format string.
131  if ( i == format.end() ) break;
132  i++;
133 
134  // Find type of formatting.
135  std::string this_format;
136  while ( i != format.end() && *i != FORMAT_PREFIX && *i != MESSAGE && *i != TYPE && *i != SOURCE && *i != COMP &&
137  *i != FILL && *i != WIDTH && *i != TIME && *i != UTIME && *i != SLOT && *i != EVTNUM && *i != THREAD &&
138  *i != EVENTID && *i != JUSTIFY_LEFT && *i != JUSTIFY_RIGHT ) {
139  this_format += *i++;
140  }
141 
142  // Reached end of string with improper format.
143  if ( i == format.end() ) {
144  invalidFormat();
145  break;
146  }
147 
148  this_format += *i++;
149  decodeFormat( this_format );
150  }
151 }
152 
153 //#############################################################################
154 // ---------------------------------------------------------------------------
155 // Routine: decodeFormat
156 // Purpose: This the work horse that checks for a valid format string.
157 // ---------------------------------------------------------------------------
158 //
160  if ( !format.empty() ) {
161  const char FORMAT_TYPE = format[format.length() - 1];
162  const std::string FORMAT_PARAM = format.substr( 0, format.length() - 1 );
163 
164  // Now test the format.
166  switch ( FORMAT_TYPE ) {
167  case FILL:
168  if ( FORMAT_PARAM.length() == 1 ) {
169  m_fill = FORMAT_PARAM[0];
170  } else
171  invalidFormat();
172  break;
173 
174  case TIME: {
175  sizeField( formattedTime( m_time_format ) );
176  } break;
177 
178  case UTIME: {
179  sizeField( formattedTime( m_time_format, true ) );
180  } break;
181 
182  case THREAD: {
183  std::ostringstream ost;
184  // ost << "0x" << std::hex << pthread_self();
185  ost << "0x" << std::hex << m_ecThrd;
186  const std::string& thrStr( ost.str() );
187  sizeField( thrStr );
188  } break;
189 
190  case SLOT: {
191  std::ostringstream ost;
193  sizeField( ost.str() );
194  } break;
195 
196  case EVTNUM: {
197  std::ostringstream ost;
199  sizeField( ost.str() );
200  } break;
201 
202  case EVENTID: {
203  std::ostringstream ost;
204  if ( m_ecEvtId.isValid() ) { ost << m_ecEvtId; }
205  sizeField( ost.str() );
206  } break;
207 
208  case MESSAGE:
209  sizeField( m_message );
210  break;
211 
212  case SOURCE:
213  sizeField( m_source );
214  break;
215 
216  case COMP:
217  sizeField( m_source, true );
218  break;
219 
220  case TYPE:
221  switch ( m_type ) {
222 #define SET( x ) \
223  case x: \
224  level = #x; \
225  break
226  SET( NIL );
227  SET( VERBOSE );
228  SET( DEBUG );
229  SET( INFO );
230  SET( WARNING );
231  SET( ERROR );
232  SET( FATAL );
233  case ALWAYS:
234  level = "SUCCESS";
235  break;
236  default:
237  level = "UNKNOWN";
238  break;
239 #undef SET
240  }
241  sizeField( level );
242  break;
243 
244  case FORMAT_PREFIX:
246  break;
247  case JUSTIFY_RIGHT:
248  m_left = false;
249  break;
250  case JUSTIFY_LEFT:
251  m_left = true;
252  break;
253  case WIDTH:
254  setWidth( FORMAT_PARAM );
255  break;
256  default:
257  invalidFormat();
258  break;
259  }
260  } else
261  invalidFormat();
262 }
263 
264 //#############################################################################
265 // ---------------------------------------------------------------------------
266 // Routine: invalidFormat.
267 // Purpose: called when invalid format found.
268 // ---------------------------------------------------------------------------
269 //
270 
272 
273 //#############################################################################
274 // ---------------------------------------------------------------------------
275 // Routine: setWidth
276 // Purpose: Sets the minimum width of a stream field.
277 // ---------------------------------------------------------------------------
278 //
279 namespace {
280  // Check that a container only contains digits.
281  constexpr struct all_digit_t {
282  template <typename C>
283  bool operator()( const C& c ) const {
284  return std::all_of( std::begin( c ), std::end( c ),
285  []( typename C::const_reference i ) { return isdigit( i ); } );
286  }
287  } all_digits{};
288 } // namespace
289 
290 void Message::setWidth( const std::string& formatArg ) const {
291  // Convert string to int, if string contains digits only...
292  if ( all_digits( formatArg ) )
293  m_width = std::stoi( formatArg );
294  else
295  invalidFormat();
296 }
297 
298 //#############################################################################
299 // ---------------------------------------------------------------------------
300 // Routine: sizeField
301 // Purpose: Truncates or pads the text to m_width as necessary
302 // ---------------------------------------------------------------------------
303 //
304 
305 void Message::sizeField( const std::string& text, bool middle ) const {
306  std::string newText;
307  if ( m_width == 0 || m_width == static_cast<int>( text.length() ) ) {
308  newText = text;
309  } else {
310  const size_t width = static_cast<size_t>( m_width );
311  // Truncate the text if it is too long.
312  if ( width < text.length() ) {
313  if ( middle && width > 4 ) { // truncate text in the middle
314  size_t iTrunc;
315  // If the text is a component-name-chain, try showing the last component
316  const size_t iDot = text.rfind( '.' );
317  if ( iDot != std::string::npos && width > text.length() - iDot + 3 ) {
318  iTrunc = iDot + 1;
319  } else {
320  // No dot or text after dot too long
321  iTrunc = text.length() - width / 2;
322  }
323  const size_t taillength = text.length() - iTrunc;
324  const size_t frontlength = width - taillength - 3;
325  newText.reserve( width );
326  newText.append( text, 0, frontlength );
327  newText.append( 3, '.' );
328  newText.append( text, iTrunc );
329  } // else if middle
330  else { // truncate text at the end
331  newText = text.substr( 0, m_width );
332  for ( int i = 0, j = newText.length() - 1; i < 3 && j >= 0; ++i, --j ) newText[j] = '.';
333  }
334  }
335  // Pad the text.
336  else {
337  newText = std::string( m_width, m_fill );
338  if ( m_left )
339  newText.replace( newText.begin(), newText.begin() + text.length(), text.begin(), text.end() );
340  else
341  newText.replace( newText.end() - text.length(), newText.end(), text.begin(), text.end() );
342  }
343  }
344 
345  m_formatted_msg += newText;
346 }
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:168
Message::m_ecEvt
EventContext::ContextEvt_t m_ecEvt
Event number.
Definition: Message.h:121
Message::DEFAULT_FORMAT
static constexpr const char * DEFAULT_FORMAT
The default message format.
Definition: Message.h:175
Message::FORMAT_PREFIX
static const char FORMAT_PREFIX
The character used to prefix formatting commands.
Definition: Message.h:129
Write.stream
stream
Definition: Write.py:32
std::string
STL class.
Message::m_format
std::string m_format
The format string.
Definition: Message.h:111
Message::TYPE
static const char TYPE
The character used to indicate that the message type should be printed.
Definition: Message.h:141
Message::m_fill
char m_fill
Current fill character.
Definition: Message.h:114
std::move
T move(T... args)
Message::setTimeFormat
void setTimeFormat(std::string timeFormat) const
Set the time format string.
Definition: Message.cpp:112
Gaudi::Hive::currentContext
GAUDI_API const EventContext & currentContext()
Definition: ThreadLocalContext.cpp:30
Message::SOURCE
static const char SOURCE
The character used to indicate that the message source should be printed.
Definition: Message.h:150
std::string::reserve
T reserve(T... args)
SuperAlgDynamicGraph.DEBUG
DEBUG
Definition: SuperAlgDynamicGraph.py:67
Message::m_ecThrd
pthread_t m_ecThrd
Thread ID.
Definition: Message.h:123
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:305
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:171
GaudiMP.FdsRegistry.msg
msg
Definition: FdsRegistry.py:19
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:178
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:527
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:165
Message::EVTNUM
static const char EVTNUM
The character used to indicate that the event number should be printed.
Definition: Message.h:159
Message::m_left
bool m_left
The message alignment.
Definition: Message.h:116
IMessageSvc.h
std::string::clear
T clear(T... args)
Message::Message
Message()=default
Default constructor.
std::string::replace
T replace(T... args)
Read.INFO
INFO
Definition: Read.py:30
operator<<
std::ostream & operator<<(std::ostream &stream, const Message &msg)
Definition: Message.cpp:64
std::hex
T hex(T... args)
Message::m_width
int m_width
Current field width.
Definition: Message.h:115
EventIDBase::isValid
bool isValid() const
Definition: EventIDBase.h:157
Message::m_type
int m_type
The message type/level.
Definition: Message.h:110
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:147
Gaudi::Time::format
std::string format(bool local, std::string spec="%c") const
Format the time using strftime.
Definition: Time.cpp:262
GaudiPython.Pythonizations.ctx
ctx
Definition: Pythonizations.py:588
Message::m_ecSlot
EventContext::ContextID_t m_ecSlot
Event slot.
Definition: Message.h:120
Message
Definition: Message.h:26
ProduceConsume.j
j
Definition: ProduceConsume.py:101
std::ostream
STL class.
EventContext::INVALID_CONTEXT_EVT
static constexpr ContextEvt_t INVALID_CONTEXT_EVT
Definition: EventContext.h:40
Message::setFormat
void setFormat(std::string msg) const
Set the format string.
Definition: Message.cpp:97
Message::invalidFormat
void invalidFormat() const
Called when an invalid format string is encountered.
Definition: Message.cpp:271
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:108
Message::TIME
static const char TIME
The character used to indicate that the message timestamp should be printed.
Definition: Message.h:144
gaudirun.level
level
Definition: gaudirun.py:366
operator==
bool operator==(const Message &a, const Message &b)
Definition: Message.cpp:86
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:132
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:153
gaudirun.type
type
Definition: gaudirun.py:162
ThreadLocalContext.h
MSG::VERBOSE
@ VERBOSE
Definition: IMessageSvc.h:25
Message::m_source
std::string m_source
The message source.
Definition: Message.h:109
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:138
std
STL namespace.
MSG::NIL
@ NIL
Definition: IMessageSvc.h:25
MSG::ERROR
@ ERROR
Definition: IMessageSvc.h:25
fmt
Definition: MessageSvcSink.cpp:25
Gaudi::Time::current
static Time current()
Returns the current time.
Definition: Time.cpp:119
Message::SLOT
static const char SLOT
The character used to indicate that the slot number should be printed.
Definition: Message.h:156
EventContext
Definition: EventContext.h:34
Message::THREAD
static const char THREAD
The character used to indicate that the thread ID should be printed.
Definition: Message.h:162
std::string::empty
T empty(T... args)
Message::m_ecEvtId
EventIDBase m_ecEvtId
Full event ID.
Definition: Message.h:122
Message::m_formatted_msg
std::string m_formatted_msg
Formatted message.
Definition: Message.h:113
Message::m_time_format
std::string m_time_format
Time format string.
Definition: Message.h:112
std::ostringstream::str
T str(T... args)
std::string::end
T end(T... args)
Message::decodeFormat
void decodeFormat(const std::string &format) const
Decode format.
Definition: Message.cpp:159
operator<
bool operator<(const Message &lhs, const Message &rhs)
Definition: Message.cpp:76
Message::makeFormattedMsg
void makeFormattedMsg(const std::string &format) const
Format the message.
Definition: Message.cpp:122
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:290
Message.h
Message::JUSTIFY_RIGHT
static const char JUSTIFY_RIGHT
The character used to indicate start of right text justification.
Definition: Message.h:135