The Gaudi Framework  master (933c680c)
Loading...
Searching...
No Matches
Message.cpp
Go to the documentation of this file.
1/***********************************************************************************\
2* (c) Copyright 1998-2024 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\***********************************************************************************/
12#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
24using namespace MSG;
25
26namespace {
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//
39Message::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//
48Message::Message( std::string src, int type, std::string msg )
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//
64std::ostream& operator<<( std::ostream& stream, const Message& msg ) {
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//
76bool 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//
86bool 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//
97void Message::setFormat( std::string format ) const {
98 if ( !format.empty() ) {
99 m_format = std::move( format );
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//
112void 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//
122void Message::makeFormattedMsg( const std::string& format ) const {
123 m_formatted_msg.clear();
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() ) {
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//
159void Message::decodeFormat( const std::string& format ) const {
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.
165 std::string level;
166 switch ( FORMAT_TYPE ) {
167 case FILL:
168 if ( FORMAT_PARAM.length() == 1 ) {
169 m_fill = FORMAT_PARAM[0];
170 } else
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:
210 break;
211
212 case 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:
258 break;
259 }
260 } else
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//
279namespace {
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
290void 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
296}
297
298// #############################################################################
299// ---------------------------------------------------------------------------
300// Routine: sizeField
301// Purpose: Truncates or pads the text to m_width as necessary
302// ---------------------------------------------------------------------------
303//
304
305void 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}
#define SET(x)
bool operator==(const Message &a, const Message &b)
Definition Message.cpp:86
std::ostream & operator<<(std::ostream &stream, const Message &msg)
Definition Message.cpp:64
bool operator<(const Message &lhs, const Message &rhs)
Definition Message.cpp:76
GAUDI_API std::string format(const char *,...)
MsgStream format utility "a la sprintf(...)".
Definition MsgStream.cpp:93
This class represents an entry point to all the event specific data.
static constexpr ContextEvt_t INVALID_CONTEXT_EVT
static constexpr ContextID_t INVALID_CONTEXT_ID
std::string format(bool local, std::string spec="%c") const
Format the time using strftime.
Definition Time.cpp:155
static Time current()
Returns the current time.
Definition Time.cpp:41
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
static const char SLOT
The character used to indicate that the slot number should be printed.
Definition Message.h:155
void setTimeFormat(std::string timeFormat) const
Set the time format string.
Definition Message.cpp:112
std::string m_message
The message text.
Definition Message.h:107
static constexpr const char * DEFAULT_FORMAT
The default message format.
Definition Message.h:174
std::string m_formatted_msg
Formatted message.
Definition Message.h:112
bool m_left
The message alignment.
Definition Message.h:115
void decodeFormat(const std::string &format) const
Decode format.
Definition Message.cpp:159
EventIDBase m_ecEvtId
Full event ID.
Definition Message.h:121
int m_width
Current field width.
Definition Message.h:114
void invalidFormat() const
Called when an invalid format string is encountered.
Definition Message.cpp:271
Message()=default
Default constructor.
EventContext::ContextID_t m_ecSlot
Event slot.
Definition Message.h:119
static const char THREAD
The character used to indicate that the thread ID should be printed.
Definition Message.h:161
int m_type
The message type/level.
Definition Message.h:109
static const char UTIME
The character used to indicate that the message timestamp should be printed in UTC time.
Definition Message.h:146
static const char EVTNUM
The character used to indicate that the event number should be printed.
Definition Message.h:158
std::string m_source
The message source.
Definition Message.h:108
static const char SOURCE
The character used to indicate that the message source should be printed.
Definition Message.h:149
static const char COMP
The character used to indicate that the message source should be printed, focus on the component.
Definition Message.h:152
static const char TIME
The character used to indicate that the message timestamp should be printed.
Definition Message.h:143
static const char JUSTIFY_LEFT
The character used to indicate start of left text justification.
Definition Message.h:131
static const char EVENTID
The character used to indicate that the full event ID should be printed.
Definition Message.h:164
static const char FORMAT_PREFIX
The character used to prefix formatting commands.
Definition Message.h:128
static const char WIDTH
The character used to indicate that the previous decimal characters should be taken as the field widt...
Definition Message.h:170
static const char TYPE
The character used to indicate that the message type should be printed.
Definition Message.h:140
std::string m_time_format
Time format string.
Definition Message.h:111
void setFormat(std::string msg) const
Set the format string.
Definition Message.cpp:97
pthread_t m_ecThrd
Thread ID.
Definition Message.h:122
static const char JUSTIFY_RIGHT
The character used to indicate start of right text justification.
Definition Message.h:134
static constexpr const char * DEFAULT_TIME_FORMAT
The default time format (accepts strftime formatters plus %f for milliseconds).
Definition Message.h:177
void makeFormattedMsg(const std::string &format) const
Format the message.
Definition Message.cpp:122
char m_fill
Current fill character.
Definition Message.h:113
EventContext::ContextEvt_t m_ecEvt
Event number.
Definition Message.h:120
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:167
std::string m_format
The format string.
Definition Message.h:110
void setWidth(const std::string &formatArg) const
Set the width of a stream.
Definition Message.cpp:290
static const char MESSAGE
The character used to indicate that the message should be printed.
Definition Message.h:137
STL class.
GAUDI_API const EventContext & currentContext()
Print levels enumeration.
Definition IMessageSvc.h:21
@ NIL
Definition IMessageSvc.h:22
@ WARNING
Definition IMessageSvc.h:22
@ FATAL
Definition IMessageSvc.h:22
@ DEBUG
Definition IMessageSvc.h:22
@ ERROR
Definition IMessageSvc.h:22
@ ALWAYS
Definition IMessageSvc.h:22
@ INFO
Definition IMessageSvc.h:22
@ VERBOSE
Definition IMessageSvc.h:22
STL namespace.