GCC Code Coverage Report


Directory: ./
File: lib/geogram/basic/logger.cpp
Date: 2026-09-07 02:37:58
Exec Total Coverage
Lines: 246 406 60.6%
Functions: 42 60 70.0%
Branches: 161 515 31.3%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2000-2022 Inria
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * * Neither the name of the ALICE Project-Team nor the names of its
14 * contributors may be used to endorse or promote products derived from this
15 * software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 *
29 * Contact: Bruno Levy
30 *
31 * https://www.inria.fr/fr/bruno-levy
32 *
33 * Inria,
34 * Domaine de Voluceau,
35 * 78150 Le Chesnay - Rocquencourt
36 * FRANCE
37 *
38 */
39
40 #include <geogram/basic/logger.h>
41 #include <geogram/basic/assert.h>
42 #include <geogram/basic/command_line.h>
43 #include <geogram/basic/argused.h>
44 #include <geogram/basic/file_system.h>
45 #include <geogram/basic/process.h>
46
47
48 #include <stdlib.h>
49 #include <stdarg.h>
50
51 /*
52 Disables the warning caused by passing 'this' as an argument while
53 construction is not finished (in LoggerStream ctor).
54 As LoggerStreamBuf only stores the pointer for later use, so we can
55 ignore the fact that 'this' is not completely formed yet.
56 */
57 #ifdef GEO_OS_WINDOWS
58 #pragma warning(disable:4355)
59 #endif
60
61
62 namespace {
63 using namespace GEO;
64
65 /**
66 * \brief The output stream returned by Logger::err_console()
67 * \details It has a locking mechanism that avoids messages sent by different
68 * threads to be mixed.
69 * \see Logger::err_console(), Logger::out(), Logger::err(), Logger::warn(),
70 * Logger::status()
71 */
72 class CERRStream : public std::ostream {
73 public:
74 251 CERRStream() :
75
4/10
✓ Branch 2 taken 251 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 251 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 251 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 251 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
251 std::ostream(new CERRStreamBuff(this)),lock_(GEOGRAM_SPINLOCK_INIT) {
76 251 }
77 1004 ~CERRStream() override{
78 1004 }
79 6639 void lock() {
80 6639 Process::acquire_spinlock(lock_);
81 6639 }
82 6639 void unlock() {
83 6639 Process::release_spinlock(lock_);
84 6639 }
85 private:
86 Process::spinlock lock_;
87 class CERRStreamBuff : public std::stringbuf {
88 public:
89 251 CERRStreamBuff(CERRStream* stream) : stream_(stream) {
90 251 }
91 6639 int sync() override {
92
2/4
✓ Branch 1 taken 6639 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6639 times.
✗ Branch 5 not taken.
6639 std::cerr << this->str();
93
2/4
✓ Branch 1 taken 6639 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6639 times.
✗ Branch 5 not taken.
13278 this->str("");
94 6639 stream_->unlock();
95 6639 return 0;
96 }
97 private:
98 CERRStream* stream_;
99 };
100 };
101 }
102
103 namespace GEO {
104
105 /************************************************************************/
106
107 5824 int LoggerStreamBuf::sync() {
108
1/2
✓ Branch 1 taken 5824 times.
✗ Branch 2 not taken.
5824 std::string str(this->str());
109
1/2
✓ Branch 1 taken 5824 times.
✗ Branch 2 not taken.
5824 loggerStream_->notify(str);
110
2/4
✓ Branch 1 taken 5824 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5824 times.
✗ Branch 5 not taken.
11648 this->str("");
111 5824 return 0;
112 5824 }
113
114 /************************************************************************/
115
116 2008 LoggerStream::LoggerStream(Logger* logger) :
117 std::ostream(new LoggerStreamBuf(this)),
118
4/11
✓ Branch 2 taken 1004 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1004 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 1004 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 1004 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
2008 logger_(logger) {
119 2008 }
120
121 2008 LoggerStream::~LoggerStream() {
122 2008 std::streambuf* buf = rdbuf();
123
1/2
✓ Branch 0 taken 1004 times.
✗ Branch 1 not taken.
2008 delete buf;
124 2008 }
125
126 5824 void LoggerStream::notify(const std::string& str) {
127 5824 logger_->notify(this, str);
128 5824 }
129
130 /************************************************************************/
131
132 502 LoggerClient::~LoggerClient() {
133 502 }
134
135 /************************************************************************/
136
137 251 ConsoleLogger::ConsoleLogger() {
138 251 }
139
140 1004 ConsoleLogger::~ConsoleLogger() {
141 1004 }
142
143 293 void ConsoleLogger::div(const std::string& title) {
144
2/4
✓ Branch 1 taken 293 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 293 times.
✗ Branch 5 not taken.
293 CmdLine::ui_separator(title);
145 293 }
146
147 5768 void ConsoleLogger::out(const std::string& str) {
148 5768 CmdLine::ui_message(str);
149 5768 }
150
151 13 void ConsoleLogger::warn(const std::string& str) {
152 13 CmdLine::ui_message(str);
153 13 }
154
155 43 void ConsoleLogger::err(const std::string& str) {
156 43 CmdLine::ui_message(str);
157 43 }
158
159 56 void ConsoleLogger::status(const std::string& str) {
160 56 geo_argused(str);
161 56 }
162
163 /************************************************************************/
164
165 FileLogger::FileLogger() :
166 log_file_(nullptr) {
167 }
168
169 FileLogger::FileLogger(const std::string& file_name) :
170 log_file_(nullptr)
171 {
172 set_file_name(file_name);
173 }
174
175 FileLogger::~FileLogger() {
176 delete log_file_;
177 log_file_ = nullptr;
178 }
179
180 void FileLogger::set_file_name(const std::string& file_name) {
181 log_file_name_ = file_name;
182 if(log_file_ != nullptr) {
183 delete log_file_;
184 log_file_ = nullptr;
185 }
186 if(log_file_name_.length() != 0) {
187 log_file_ = new std::ofstream(log_file_name_.c_str());
188 }
189 }
190
191 void FileLogger::div(const std::string& title) {
192 if(log_file_ != nullptr) {
193 *log_file_
194 << "\n====[" << title << "]====\n"
195 << std::flush;
196 }
197 }
198
199 void FileLogger::out(const std::string& str) {
200 if(log_file_ != nullptr) {
201 *log_file_ << str << std::flush;
202 }
203 }
204
205 void FileLogger::warn(const std::string& str) {
206 if(log_file_ != nullptr) {
207 *log_file_ << str << std::flush;
208 }
209 }
210
211 void FileLogger::err(const std::string& str) {
212 if(log_file_ != nullptr) {
213 *log_file_ << str << std::flush;
214 }
215 }
216
217 void FileLogger::status(const std::string& str) {
218 geo_argused(str);
219 }
220
221 /************************************************************************/
222
223 SmartPointer<Logger> Logger::instance_;
224
225 251 void Logger::initialize() {
226
3/8
✓ Branch 2 taken 251 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 251 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 251 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
251 instance_ = new Logger();
227 251 Environment::instance()->add_environment(instance_);
228 251 }
229
230 251 void Logger::terminate() {
231 251 instance_.reset();
232 251 }
233
234 12505 bool Logger::is_initialized() {
235 12505 return (instance_ != nullptr);
236 }
237
238 13632 bool Logger::set_local_value(
239 const std::string& name, const std::string& value
240 ) {
241
242
2/2
✓ Branch 1 taken 251 times.
✓ Branch 2 taken 13381 times.
13632 if(name == "log:quiet") {
243 251 set_quiet(String::to_bool(value));
244 251 return true;
245 }
246
247
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 13381 times.
13381 if(name == "log:minimal") {
248 set_minimal(String::to_bool(value));
249 return true;
250 }
251
252
2/2
✓ Branch 1 taken 251 times.
✓ Branch 2 taken 13130 times.
13381 if(name == "log:pretty") {
253 251 set_pretty(String::to_bool(value));
254 251 return true;
255 }
256
257
2/2
✓ Branch 1 taken 251 times.
✓ Branch 2 taken 12879 times.
13130 if(name == "log:file_name") {
258 251 log_file_name_ = value;
259
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 251 times.
251 if(!log_file_name_.empty()) {
260 register_client(new FileLogger(log_file_name_));
261 }
262 251 return true;
263 }
264
265
2/2
✓ Branch 1 taken 251 times.
✓ Branch 2 taken 12628 times.
12879 if(name == "log:features") {
266 251 std::vector<std::string> features;
267
1/2
✓ Branch 1 taken 251 times.
✗ Branch 2 not taken.
251 String::split_string(value, ';', features);
268 251 log_features_.clear();
269
4/8
✓ Branch 1 taken 251 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 251 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 251 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 251 times.
✗ Branch 10 not taken.
251 if(features.size() == 1 && features[0] == "*") {
270 251 log_everything_ = true;
271 } else {
272 log_everything_ = false;
273 for(size_t i = 0; i < features.size(); i++) {
274 log_features_.insert(features[i]);
275 }
276 }
277
1/2
✓ Branch 1 taken 251 times.
✗ Branch 2 not taken.
251 notify_observers(name);
278 251 return true;
279 251 }
280
281
2/2
✓ Branch 1 taken 251 times.
✓ Branch 2 taken 12377 times.
12628 if(name == "log:features_exclude") {
282 251 std::vector<std::string> features;
283
1/2
✓ Branch 1 taken 251 times.
✗ Branch 2 not taken.
251 String::split_string(value, ';', features);
284 251 log_features_exclude_.clear();
285
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 251 times.
251 for(size_t i = 0; i < features.size(); i++) {
286 log_features_exclude_.insert(features[i]);
287 }
288
1/2
✓ Branch 1 taken 251 times.
✗ Branch 2 not taken.
251 notify_observers(name);
289 251 return true;
290 251 }
291
292 12377 return false;
293 }
294
295 1984 bool Logger::get_local_value(
296 const std::string& name, std::string& value
297 ) const {
298
299
2/2
✓ Branch 1 taken 105 times.
✓ Branch 2 taken 1879 times.
1984 if(name == "log:quiet") {
300
1/2
✓ Branch 2 taken 105 times.
✗ Branch 3 not taken.
105 value = String::to_string(is_quiet());
301 105 return true;
302 }
303
304
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1879 times.
1879 if(name == "log:minimal") {
305 value = String::to_string(is_minimal());
306 return true;
307 }
308
309
2/2
✓ Branch 1 taken 109 times.
✓ Branch 2 taken 1770 times.
1879 if(name == "log:pretty") {
310
1/2
✓ Branch 2 taken 109 times.
✗ Branch 3 not taken.
109 value = String::to_string(is_pretty());
311 109 return true;
312 }
313
314
2/2
✓ Branch 1 taken 105 times.
✓ Branch 2 taken 1665 times.
1770 if(name == "log:file_name") {
315 105 value = log_file_name_;
316 105 return true;
317 }
318
319
2/2
✓ Branch 1 taken 356 times.
✓ Branch 2 taken 1309 times.
1665 if(name == "log:features") {
320
1/2
✓ Branch 0 taken 356 times.
✗ Branch 1 not taken.
356 if(log_everything_) {
321 356 value = "*";
322 } else {
323 value = "";
324 for(auto& it : log_features_) {
325 if(value.length() != 0) {
326 value += ';';
327 }
328 value += it;
329 }
330 }
331 356 return true;
332 }
333
334
2/2
✓ Branch 1 taken 356 times.
✓ Branch 2 taken 953 times.
1309 if(name == "log:features_exclude") {
335 356 value = "";
336
1/2
✗ Branch 5 not taken.
✓ Branch 6 taken 356 times.
356 for(auto& it : log_features_exclude_) {
337 if(value.length() != 0) {
338 value += ';';
339 }
340 value += it;
341 }
342 356 return true;
343 }
344
345 953 return false;
346 }
347
348 251 void Logger::register_client(LoggerClient* c) {
349
1/2
✓ Branch 2 taken 251 times.
✗ Branch 3 not taken.
251 clients_.insert(c);
350 251 }
351
352 void Logger::unregister_client(LoggerClient* c) {
353 geo_debug_assert(clients_.find(c) != clients_.end());
354 clients_.erase(c);
355 }
356
357 void Logger::unregister_all_clients() {
358 clients_.clear();
359 }
360
361 bool Logger::is_client(LoggerClient* c) const {
362 return clients_.find(c) != clients_.end();
363 }
364
365 295 void Logger::set_quiet(bool flag) {
366 295 quiet_ = flag;
367 295 }
368
369 void Logger::set_minimal(bool flag) {
370 minimal_ = flag;
371 }
372
373 251 void Logger::set_pretty(bool flag) {
374 251 pretty_ = flag;
375 251 }
376
377
378 251 Logger::Logger() :
379 251 out_(this),
380
1/2
✓ Branch 1 taken 251 times.
✗ Branch 2 not taken.
251 warn_(this),
381
1/2
✓ Branch 1 taken 251 times.
✗ Branch 2 not taken.
251 err_(this),
382
1/2
✓ Branch 1 taken 251 times.
✗ Branch 2 not taken.
251 status_(this),
383 251 log_everything_(true),
384 251 current_feature_changed_(false),
385 251 quiet_(true),
386 251 pretty_(true),
387 251 minimal_(false),
388 251 notifying_error_(false),
389
1/2
✓ Branch 2 taken 251 times.
✗ Branch 3 not taken.
502 indent_(0)
390 {
391 // Add a default client printing stuff to std::cout
392
4/10
✓ Branch 1 taken 251 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 251 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 251 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 251 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
251 register_client(new ConsoleLogger());
393 #ifdef GEO_DEBUG
394 251 quiet_ = false;
395 #endif
396
3/8
✓ Branch 1 taken 251 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 251 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 251 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
251 err_console_ = new CERRStream;
397 251 }
398
399 1004 Logger::~Logger() {
400
1/2
✓ Branch 0 taken 251 times.
✗ Branch 1 not taken.
502 delete err_console_;
401 502 err_console_ = nullptr;
402 1004 }
403
404 26809 Logger* Logger::instance() {
405 // Do not use geo_assert here:
406 // if the instance is nullptr, geo_assert will
407 // call the Logger to print the assertion failure, thus ending in a
408 // infinite loop.
409
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 26809 times.
26809 if(instance_ == nullptr) {
410 std::cerr
411 << "CRITICAL: Accessing uninitialized Logger instance"
412 << std::endl;
413 geo_abort();
414 }
415 26809 return instance_;
416 }
417
418 6639 std::ostream& Logger::err_console() {
419 6639 static_cast<CERRStream*>(err_console_)->lock();
420 6639 return *err_console_;
421 }
422
423 293 std::ostream& Logger::div(const std::string& title) {
424 std::ostream& result =
425
2/4
✓ Branch 1 taken 293 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 293 times.
✗ Branch 5 not taken.
293 (is_initialized() && !Process::is_running_threads()) ?
426 293 instance()->div_stream(title) :
427 293 (instance()->err_console() << "=====" << title << std::endl);
428 293 return result;
429 }
430
431 12156 std::ostream& Logger::out(const std::string& feature) {
432 std::ostream& result =
433
4/6
✓ Branch 0 taken 12156 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 12156 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 5517 times.
✓ Branch 6 taken 6639 times.
12156 (is_initialized() && !Process::is_running_threads()) ?
434
2/4
✓ Branch 1 taken 5517 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5517 times.
✗ Branch 5 not taken.
5517 instance()->out_stream(feature) :
435
2/4
✓ Branch 1 taken 6639 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6639 times.
✗ Branch 5 not taken.
6639 (instance()->err_console() << " >>"
436
6/12
✓ Branch 1 taken 12156 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6639 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 6639 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 6639 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 6639 times.
✓ Branch 13 taken 5517 times.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
24312 << CmdLine::ui_feature(feature));
437
2/2
✓ Branch 1 taken 11548 times.
✓ Branch 2 taken 12156 times.
23704 for(index_t i=0; i<instance_->indent_; ++i) {
438 11548 result << "| ";
439 }
440 12156 return result;
441 }
442
443 43 std::ostream& Logger::err(const std::string& feature) {
444 std::ostream& result =
445
2/4
✓ Branch 1 taken 43 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 43 times.
✗ Branch 5 not taken.
43 (is_initialized() && !Process::is_running_threads()) ?
446 43 instance()->err_stream(feature) :
447 43 (instance()->err_console() << "(E)-[" << feature << "] ");
448 43 return result;
449 }
450
451 13 std::ostream& Logger::warn(const std::string& feature) {
452 std::ostream& result =
453
2/4
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
13 (is_initialized() && !Process::is_running_threads()) ?
454 13 instance()->warn_stream(feature) :
455 13 (instance()->err_console() << "(W)-[" << feature << "] ");
456 13 return result;
457 }
458
459 std::ostream& Logger::status() {
460 std::ostream& result =
461 (is_initialized() && !Process::is_running_threads()) ?
462 instance()->status_stream() :
463 (instance()->err_console() << "[status] ");
464 return result;
465 }
466
467 293 std::ostream& Logger::div_stream(const std::string& title) {
468
1/2
✓ Branch 0 taken 293 times.
✗ Branch 1 not taken.
293 if(!quiet_) {
469 293 current_feature_changed_ = true;
470 293 current_feature_.clear();
471
1/2
✓ Branch 1 taken 293 times.
✗ Branch 2 not taken.
293 LoggerClients clients = clients_; // clients_ may be modified !
472
3/4
✓ Branch 4 taken 293 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 293 times.
✓ Branch 9 taken 293 times.
586 for(auto it : clients) {
473
2/4
✓ Branch 1 taken 293 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 293 times.
✗ Branch 5 not taken.
293 it->div(title);
474 293 }
475 293 }
476 293 return out_;
477 }
478
479 5517 std::ostream& Logger::out_stream(const std::string& feature) {
480
6/8
✓ Branch 0 taken 5517 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5517 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2766 times.
✓ Branch 6 taken 2751 times.
✓ Branch 7 taken 2766 times.
✓ Branch 8 taken 2751 times.
5517 if(!quiet_ && !minimal_ && current_feature_ != feature) {
481 2766 current_feature_changed_ = true;
482 2766 current_feature_ = feature;
483 }
484 5517 return out_;
485 }
486
487 43 std::ostream& Logger::err_stream(const std::string& feature) {
488
5/6
✓ Branch 0 taken 43 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 38 times.
✓ Branch 5 taken 5 times.
✓ Branch 6 taken 38 times.
43 if(!quiet_ && current_feature_ != feature) {
489 5 current_feature_changed_ = true;
490 5 current_feature_ = feature;
491 }
492 43 return err_;
493 }
494
495 13 std::ostream& Logger::warn_stream(const std::string& feature) {
496
5/6
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 9 times.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 9 times.
13 if(!quiet_ && current_feature_ != feature) {
497 4 current_feature_changed_ = true;
498 4 current_feature_ = feature;
499 }
500 13 return warn_;
501 }
502
503 std::ostream& Logger::status_stream() {
504 return status_;
505 }
506
507 5768 void Logger::notify_out(const std::string& message) {
508 5768 if(
509
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5768 times.
5768 (log_everything_ &&
510
1/2
✓ Branch 1 taken 5768 times.
✗ Branch 2 not taken.
5768 log_features_exclude_.find(current_feature_) ==
511 5768 log_features_exclude_.end())
512
2/8
✓ Branch 0 taken 5768 times.
✗ Branch 1 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 5768 times.
✗ Branch 10 not taken.
11536 || (log_features_.find(current_feature_) != log_features_.end())
513 ) {
514 std::string feat_msg =
515
1/2
✓ Branch 1 taken 5768 times.
✗ Branch 2 not taken.
11536 CmdLine::ui_feature(current_feature_, current_feature_changed_)
516
1/2
✓ Branch 1 taken 5768 times.
✗ Branch 2 not taken.
5768 + message;
517
518
1/2
✓ Branch 1 taken 5768 times.
✗ Branch 2 not taken.
5768 LoggerClients clients = clients_; // clients_ may be modified !
519
3/4
✓ Branch 4 taken 5768 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 5768 times.
✓ Branch 9 taken 5768 times.
11536 for(auto it : clients) {
520
2/4
✓ Branch 1 taken 5768 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5768 times.
✗ Branch 5 not taken.
5768 it->out(feat_msg);
521 5768 }
522
523 // There is a mechanism for not repeating feature when it is
524 // the same as in previous message, but finally I systematically
525 // display feature (else the log is not super easy to read,
526 // especially when there are nested Stopwatches).
527 5768 current_feature_changed_ = true;
528 5768 }
529 5768 }
530
531 13 void Logger::notify_warn(const std::string& message) {
532
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 std::string msg = "Warning: " + message;
533 std::string feat_msg =
534
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
26 CmdLine::ui_feature(current_feature_, current_feature_changed_)
535
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 + msg;
536
537
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 LoggerClients clients = clients_; // clients_ may be modified !
538
3/4
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 13 times.
✓ Branch 9 taken 13 times.
26 for(auto it : clients) {
539
2/4
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
13 it->warn(feat_msg);
540
2/4
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
13 it->status(msg);
541 13 }
542
543 13 current_feature_changed_ = false;
544 13 }
545
546 43 void Logger::notify_err(const std::string& message) {
547
1/2
✓ Branch 1 taken 43 times.
✗ Branch 2 not taken.
43 std::string msg = "Error: " + message;
548 std::string feat_msg =
549
1/2
✓ Branch 1 taken 43 times.
✗ Branch 2 not taken.
86 CmdLine::ui_feature(current_feature_, current_feature_changed_)
550
1/2
✓ Branch 1 taken 43 times.
✗ Branch 2 not taken.
43 + msg;
551
552
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 43 times.
43 if(notifying_error_) {
553 std::cerr << "Error while displaying error (!):"
554 << feat_msg << std::endl;
555 } else {
556 43 notifying_error_ = true;
557
1/2
✓ Branch 1 taken 43 times.
✗ Branch 2 not taken.
43 LoggerClients clients = clients_; // clients_ may be modified !
558
3/4
✓ Branch 4 taken 43 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 43 times.
✓ Branch 9 taken 43 times.
86 for(auto it : clients) {
559
2/4
✓ Branch 1 taken 43 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 43 times.
✗ Branch 5 not taken.
43 it->err(feat_msg);
560
2/4
✓ Branch 1 taken 43 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 43 times.
✗ Branch 5 not taken.
43 it->status(msg);
561 43 }
562 43 notifying_error_ = false;
563 43 }
564
565 43 current_feature_changed_ = false;
566 43 }
567
568 void Logger::notify_status(const std::string& message) {
569 LoggerClients clients = clients_; // clients_ may be modified !
570 for(auto it : clients) {
571 it->status(message);
572 }
573
574 current_feature_changed_ = false;
575 }
576
577 5824 void Logger::notify(LoggerStream* s, const std::string& message) {
578
579
4/10
✓ Branch 0 taken 5824 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5824 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 5824 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 5824 times.
5824 if(quiet_ || (minimal_ && s == &out_) || clients_.empty()) {
580 return;
581 }
582
583
2/2
✓ Branch 0 taken 5768 times.
✓ Branch 1 taken 56 times.
5824 if(s == &out_) {
584 5768 notify_out(message);
585
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 43 times.
56 } else if(s == &warn_) {
586 13 notify_warn(message);
587
1/2
✓ Branch 0 taken 43 times.
✗ Branch 1 not taken.
43 } else if(s == &err_) {
588 43 notify_err(message);
589 } else if(s == &status_) {
590 notify_status(message);
591 } else {
592 geo_assert_not_reached;
593 }
594 }
595
596 /************************************************************************/
597
598 }
599
600 extern "C" {
601
602 int geogram_printf(const char* format, ...) {
603
604 static std::string last_string;
605
606 va_list args;
607
608 // Get the number of characters to be printed.
609 va_start(args, format);
610 int nb = vsnprintf(nullptr, 0, format, args)+1; // +1, I don't know why.
611 va_end(args);
612
613 // Generate the output string
614 GEO::vector<char> buffer(GEO::index_t(nb+1));
615 va_start(args, format);
616 vsnprintf(buffer.data(),buffer.size()-1, format, args);
617 va_end(args);
618
619 // Find the lines in the generated string
620 GEO::vector<char*> lines;
621 lines.push_back(buffer.data());
622 char last_char = '\n';
623 for(char* ptr = buffer.data(); *ptr; ptr++) {
624 if(*ptr != '\0') {
625 last_char = *ptr;
626 }
627 if(*ptr == '\n') {
628 *ptr = '\0';
629 ptr++;
630 if(*ptr != '\0') {
631 lines.push_back(ptr);
632 }
633 }
634 }
635
636 // If last character is not a carriage return,
637 // memorize the last line for later.
638 if(last_char != '\n') {
639 last_string += *lines.rbegin();
640 lines.pop_back();
641 }
642
643 // Output all the lines.
644 // Prepend the optionally memorized previous strings to the
645 // first one.
646 for(GEO::index_t i=0; i<lines.size(); ++i) {
647 if(i == 0) {
648 GEO::Logger::out("") << last_string << lines[i] << std::endl;
649 last_string.clear();
650 } else {
651 GEO::Logger::out("") << lines[i] << std::endl;
652 }
653 }
654
655 return nb;
656 }
657
658 int geogram_fprintf(FILE* out, const char* format, ...) {
659
660
661 static std::string last_string;
662
663 va_list args;
664
665 // Get the number of characters to be printed.
666 va_start(args, format);
667 int nb = vsnprintf(nullptr, 0, format, args)+1; // +1, I don't know why...
668 va_end(args);
669
670 // Generate the output string
671 GEO::vector<char> buffer(GEO::index_t(nb+1));
672 va_start(args, format);
673 vsnprintf(buffer.data(),buffer.size()-1, format, args);
674 va_end(args);
675
676 // Find the lines in the generated string
677 GEO::vector<char*> lines;
678 lines.push_back(buffer.data());
679 char last_char = '\n';
680 for(char* ptr = buffer.data(); *ptr; ptr++) {
681 if(*ptr != '\0') {
682 last_char = *ptr;
683 }
684 if(*ptr == '\n') {
685 *ptr = '\0';
686 ptr++;
687 if(*ptr != '\0') {
688 lines.push_back(ptr);
689 }
690 }
691 }
692
693 // If last character is not a carriage return,
694 // memorize the last line for later.
695 if(last_char != '\n') {
696 last_string += *lines.rbegin();
697 lines.pop_back();
698 }
699
700 // Output all the lines.
701 // Prepend the optionally memorized previous strings to the
702 // first one.
703 for(GEO::index_t i=0; i<lines.size(); ++i) {
704 if(i == 0) {
705 if(out == stdout) {
706 GEO::Logger::out("") << last_string << lines[i] << std::endl;
707 } else if(out == stderr) {
708 GEO::Logger::err("") << last_string << lines[i] << std::endl;
709 } else {
710 fprintf(out, "%s%s", last_string.c_str(), lines[i]);
711 }
712 last_string.clear();
713 } else {
714 if(out == stdout) {
715 GEO::Logger::out("") << lines[i] << std::endl;
716 } else if(out == stderr) {
717 GEO::Logger::err("") << lines[i] << std::endl;
718 } else {
719 fprintf(out, "%s", lines[i]);
720 }
721 }
722 }
723
724 return nb;
725 }
726 }
727