Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/utils/common/MsgHandler.cpp
193724 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-2026 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
gLocaleInitialized = true;
289
}
290
291
292
void
293
MsgHandler::initOutputOptions() {
294
// initialize console properly
295
OutputDevice::getDevice("stdout");
296
OutputDevice::getDevice("stderr");
297
OptionsCont& oc = OptionsCont::getOptions();
298
getWarningInstance()->setAggregationThreshold(oc.getInt("aggregate-warnings"));
299
getErrorInstance()->setAggregationThreshold(oc.getInt("aggregate-warnings"));
300
if (oc.getBool("no-warnings")) {
301
getWarningInstance()->removeRetriever(&OutputDevice::getDevice("stderr"));
302
}
303
// build the logger if possible
304
if (oc.isSet("log", false)) {
305
OutputDevice* logFile = &OutputDevice::getDevice(oc.getString("log"));
306
getErrorInstance()->addRetriever(logFile);
307
if (!oc.getBool("no-warnings")) {
308
getWarningInstance()->addRetriever(logFile);
309
}
310
getMessageInstance()->addRetriever(logFile);
311
if (oc.getBool("log.timestamps")) {
312
myWriteTimestamps = true;
313
}
314
if (oc.getBool("log.processid")) {
315
myWriteProcessId = true;
316
}
317
}
318
if (oc.isSet("message-log", false)) {
319
OutputDevice* logFile = &OutputDevice::getDevice(oc.getString("message-log"));
320
getMessageInstance()->addRetriever(logFile);
321
}
322
if (oc.isSet("error-log", false)) {
323
OutputDevice* logFile = &OutputDevice::getDevice(oc.getString("error-log"));
324
getErrorInstance()->addRetriever(logFile);
325
getWarningInstance()->addRetriever(logFile);
326
}
327
if (oc.getBool("verbose")) {
328
getErrorInstance()->myInitialMessages.push_back("Repeating initial error messages:");
329
} else {
330
getMessageInstance()->removeRetriever(&OutputDevice::getDevice("stdout"));
331
}
332
}
333
334
335
void
336
MsgHandler::cleanupOnEnd() {
337
delete myMessageInstance;
338
myMessageInstance = nullptr;
339
delete myWarningInstance;
340
myWarningInstance = nullptr;
341
delete myErrorInstance;
342
myErrorInstance = nullptr;
343
}
344
345
346
std::string
347
MsgHandler::buildProcessIdPrefix() const {
348
std::stringstream prefix;
349
prefix << "[PID: ";
350
#ifdef WIN32
351
prefix << GetCurrentProcessId();
352
#else
353
prefix << getpid();
354
#endif
355
prefix << "] ";
356
return prefix.str();
357
}
358
359
360
MsgHandler::MsgHandler(MsgType type) :
361
myType(type), myWasInformed(false), myAggregationThreshold(-1) {
362
if (type == MsgType::MT_MESSAGE) {
363
addRetriever(&OutputDevice::getDevice("stdout"));
364
} else {
365
addRetriever(&OutputDevice::getDevice("stderr"));
366
}
367
}
368
369
370
MsgHandler::~MsgHandler() {
371
}
372
373
374
bool
375
MsgHandler::wasInformed() const {
376
return myWasInformed;
377
}
378
379
380
/****************************************************************************/
381
382