Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/utils/common/MsgHandler.cpp
169678 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.
4
// This program and the accompanying materials are made available under the
5
// terms of the Eclipse Public License 2.0 which is available at
6
// https://www.eclipse.org/legal/epl-2.0/
7
// This Source Code may also be made available under the following Secondary
8
// Licenses when the conditions for such availability set forth in the Eclipse
9
// Public License 2.0 are satisfied: GNU General Public License, version 2
10
// or later which is available at
11
// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13
/****************************************************************************/
14
/// @file MsgHandler.cpp
15
/// @author Daniel Krajzewicz
16
/// @author Michael Behrisch
17
/// @author Mirko Barthauer
18
/// @date Tue, 17 Jun 2003
19
///
20
// Retrieves messages about the process and gives them further to output
21
/****************************************************************************/
22
#include <config.h>
23
24
#include <string>
25
#include <cassert>
26
#include <vector>
27
#include <algorithm>
28
#include <iostream>
29
#ifdef WIN32
30
#define NOMINMAX
31
#include <windows.h>
32
#undef NOMINMAX
33
#else
34
#include <unistd.h>
35
#endif
36
#include <utils/options/OptionsCont.h>
37
#include <utils/iodevices/OutputDevice.h>
38
#include <utils/common/UtilExceptions.h>
39
#include "MsgHandler.h"
40
41
42
// ===========================================================================
43
// static member variables
44
// ===========================================================================
45
MsgHandler::Factory MsgHandler::myFactory = nullptr;
46
MsgHandler* MsgHandler::myErrorInstance = nullptr;
47
MsgHandler* MsgHandler::myWarningInstance = nullptr;
48
MsgHandler* MsgHandler::myMessageInstance = nullptr;
49
bool MsgHandler::myAmProcessingProcess = false;
50
bool MsgHandler::myWriteDebugMessages = false;
51
bool MsgHandler::myWriteDebugGLMessages = false;
52
bool MsgHandler::myWriteTimestamps = false;
53
bool MsgHandler::myWriteProcessId = false;
54
std::string MsgHandler::myErrorPrefix = "Error: ";
55
std::string MsgHandler::myWarningPrefix = "Warning: ";
56
57
58
// ===========================================================================
59
// method definitions
60
// ===========================================================================
61
62
MsgHandler*
63
MsgHandler::getMessageInstance() {
64
if (myMessageInstance == nullptr) {
65
if (myFactory == nullptr) {
66
myMessageInstance = new MsgHandler(MsgType::MT_MESSAGE);
67
} else {
68
myMessageInstance = myFactory(MsgType::MT_MESSAGE);
69
}
70
}
71
return myMessageInstance;
72
}
73
74
75
MsgHandler*
76
MsgHandler::getWarningInstance() {
77
if (myWarningInstance == nullptr) {
78
if (myFactory == nullptr) {
79
myWarningInstance = new MsgHandler(MsgType::MT_WARNING);
80
} else {
81
myWarningInstance = myFactory(MsgType::MT_WARNING);
82
}
83
}
84
return myWarningInstance;
85
}
86
87
88
MsgHandler*
89
MsgHandler::getErrorInstance() {
90
if (myErrorInstance == nullptr) {
91
myErrorInstance = new MsgHandler(MsgType::MT_ERROR);
92
}
93
return myErrorInstance;
94
}
95
96
97
void
98
MsgHandler::enableDebugMessages(bool enable) {
99
myWriteDebugMessages = enable;
100
}
101
102
void
103
MsgHandler::enableDebugGLMessages(bool enable) {
104
myWriteDebugGLMessages = enable;
105
}
106
107
108
std::string
109
MsgHandler::insertLineBreaks(std::string msg, int lineWidth) {
110
// TODO: check what FXFont::getTextWidth can do
111
//int textWidth = getApp()->getNormalFont()->getTextWidth
112
if ((int)msg.size() <= lineWidth) {
113
return msg;
114
}
115
size_t pos = 0;
116
size_t nextLineBreak = msg.find('\n');
117
size_t spaceAfterLine = msg.find(' ', lineWidth);
118
while (spaceAfterLine != std::string::npos) {
119
if (nextLineBreak == std::string::npos || nextLineBreak > spaceAfterLine) {
120
msg = msg.replace(spaceAfterLine, 1, "\n");
121
pos = spaceAfterLine + 1;
122
} else {
123
pos = nextLineBreak + 1;
124
}
125
spaceAfterLine = msg.find(' ', pos + lineWidth);
126
nextLineBreak = msg.find('\n', pos);
127
}
128
return msg;
129
}
130
131
132
void
133
MsgHandler::inform(std::string msg, bool addType) {
134
if (addType && !myInitialMessages.empty() && myInitialMessages.size() < 5) {
135
myInitialMessages.push_back(msg);
136
}
137
// beautify progress output
138
if (myAmProcessingProcess) {
139
myAmProcessingProcess = false;
140
MsgHandler::getMessageInstance()->inform("");
141
}
142
msg = build(msg, addType);
143
// inform all receivers
144
for (auto i : myRetrievers) {
145
i->inform(msg);
146
}
147
// set the information that something occurred
148
myWasInformed = true;
149
}
150
151
152
void
153
MsgHandler::beginProcessMsg(std::string msg, bool addType) {
154
msg = build(msg, addType);
155
// inform all other receivers
156
for (auto i : myRetrievers) {
157
i->inform(msg, true);
158
myAmProcessingProcess = true;
159
}
160
// set the information that something occurred
161
myWasInformed = true;
162
}
163
164
165
void
166
MsgHandler::endProcessMsg2(bool success, long duration) {
167
if (success) {
168
if (duration > -1) {
169
endProcessMsg(TLF(" done (%ms).", toString(duration)));
170
} else {
171
endProcessMsg(TL(" done."));
172
}
173
} else {
174
endProcessMsg(TL(" failed."));
175
}
176
}
177
178
179
void
180
MsgHandler::endProcessMsg(std::string msg) {
181
// inform all other receivers
182
for (auto i : myRetrievers) {
183
i->inform(msg);
184
}
185
// set the information that something occurred
186
myWasInformed = true;
187
myAmProcessingProcess = false;
188
}
189
190
191
void
192
MsgHandler::clear(bool resetInformed) {
193
if (myAggregationThreshold >= 0) {
194
for (const auto& i : myAggregationCount) {
195
if (i.second > myAggregationThreshold) {
196
inform(toString(i.second) + " total messages of type: " + i.first);
197
}
198
}
199
}
200
myAggregationCount.clear();
201
if (!resetInformed && myInitialMessages.size() > 1) {
202
const bool wasInformed = myWasInformed;
203
for (const std::string& msg : myInitialMessages) {
204
inform(msg, false);
205
}
206
myInitialMessages.clear();
207
myWasInformed = wasInformed;
208
}
209
if (resetInformed) {
210
myWasInformed = false;
211
}
212
}
213
214
215
void
216
MsgHandler::addRetriever(OutputDevice* retriever) {
217
if (!isRetriever(retriever)) {
218
myRetrievers.push_back(retriever);
219
}
220
}
221
222
223
void
224
MsgHandler::removeRetriever(OutputDevice* retriever) {
225
std::vector<OutputDevice*>::iterator i = find(myRetrievers.begin(), myRetrievers.end(), retriever);
226
if (i != myRetrievers.end()) {
227
myRetrievers.erase(i);
228
}
229
}
230
231
232
bool
233
MsgHandler::isRetriever(OutputDevice* retriever) const {
234
return std::find(myRetrievers.begin(), myRetrievers.end(), retriever) != myRetrievers.end();
235
}
236
237
238
void
239
MsgHandler::removeRetrieverFromAllInstances(OutputDevice* out) {
240
if (myErrorInstance != nullptr) {
241
myErrorInstance->removeRetriever(out);
242
}
243
if (myWarningInstance != nullptr) {
244
myWarningInstance->removeRetriever(out);
245
}
246
if (myMessageInstance != nullptr) {
247
myMessageInstance->removeRetriever(out);
248
}
249
}
250
251
252
void
253
MsgHandler::setupI18n(const std::string& locale) {
254
#ifdef HAVE_INTL
255
if (locale != "") {
256
#ifdef WIN32
257
_putenv_s("LANGUAGE", locale.data());
258
#else
259
setenv("LANGUAGE", locale.data(), true);
260
#endif
261
}
262
if (!setlocale(LC_MESSAGES, "")) {
263
WRITE_WARNINGF(TL("Could not set locale to '%'."), locale);
264
}
265
const char* sumoPath = getenv("SUMO_HOME");
266
if (sumoPath == nullptr) {
267
if (!bindtextdomain("sumo", nullptr)) {
268
WRITE_WARNING(TL("Environment variable SUMO_HOME is not set, could not find localized messages."));
269
return;
270
}
271
} else {
272
const std::string path = sumoPath + std::string("/data/locale/");
273
if (!bindtextdomain("sumo", path.data())) {
274
WRITE_WARNING(TL("Could not find localized messages."));
275
return;
276
}
277
}
278
bind_textdomain_codeset("sumo", "UTF-8");
279
textdomain("sumo");
280
#ifdef WIN32
281
SetConsoleOutputCP(CP_UTF8);
282
#endif
283
#else
284
UNUSED_PARAMETER(locale);
285
#endif
286
myWarningPrefix = TL("Warning: ");
287
myErrorPrefix = TL("Error: ");
288
}
289
290
291
void
292
MsgHandler::initOutputOptions() {
293
// initialize console properly
294
OutputDevice::getDevice("stdout");
295
OutputDevice::getDevice("stderr");
296
OptionsCont& oc = OptionsCont::getOptions();
297
getWarningInstance()->setAggregationThreshold(oc.getInt("aggregate-warnings"));
298
getErrorInstance()->setAggregationThreshold(oc.getInt("aggregate-warnings"));
299
if (oc.getBool("no-warnings")) {
300
getWarningInstance()->removeRetriever(&OutputDevice::getDevice("stderr"));
301
}
302
// build the logger if possible
303
if (oc.isSet("log", false)) {
304
OutputDevice* logFile = &OutputDevice::getDevice(oc.getString("log"));
305
getErrorInstance()->addRetriever(logFile);
306
if (!oc.getBool("no-warnings")) {
307
getWarningInstance()->addRetriever(logFile);
308
}
309
getMessageInstance()->addRetriever(logFile);
310
if (oc.getBool("log.timestamps")) {
311
myWriteTimestamps = true;
312
}
313
if (oc.getBool("log.processid")) {
314
myWriteProcessId = true;
315
}
316
}
317
if (oc.isSet("message-log", false)) {
318
OutputDevice* logFile = &OutputDevice::getDevice(oc.getString("message-log"));
319
getMessageInstance()->addRetriever(logFile);
320
}
321
if (oc.isSet("error-log", false)) {
322
OutputDevice* logFile = &OutputDevice::getDevice(oc.getString("error-log"));
323
getErrorInstance()->addRetriever(logFile);
324
getWarningInstance()->addRetriever(logFile);
325
}
326
if (oc.getBool("verbose")) {
327
getErrorInstance()->myInitialMessages.push_back("Repeating initial error messages:");
328
} else {
329
getMessageInstance()->removeRetriever(&OutputDevice::getDevice("stdout"));
330
}
331
}
332
333
334
void
335
MsgHandler::cleanupOnEnd() {
336
delete myMessageInstance;
337
myMessageInstance = nullptr;
338
delete myWarningInstance;
339
myWarningInstance = nullptr;
340
delete myErrorInstance;
341
myErrorInstance = nullptr;
342
}
343
344
345
std::string
346
MsgHandler::buildProcessIdPrefix() const {
347
std::stringstream prefix;
348
prefix << "[PID: ";
349
#ifdef WIN32
350
prefix << GetCurrentProcessId();
351
#else
352
prefix << getpid();
353
#endif
354
prefix << "] ";
355
return prefix.str();
356
}
357
358
359
MsgHandler::MsgHandler(MsgType type) :
360
myType(type), myWasInformed(false), myAggregationThreshold(-1) {
361
if (type == MsgType::MT_MESSAGE) {
362
addRetriever(&OutputDevice::getDevice("stdout"));
363
} else {
364
addRetriever(&OutputDevice::getDevice("stderr"));
365
}
366
}
367
368
369
MsgHandler::~MsgHandler() {
370
}
371
372
373
bool
374
MsgHandler::wasInformed() const {
375
return myWasInformed;
376
}
377
378
379
/****************************************************************************/
380
381