b2api
B2000++ API Reference Manual, VERSION 4.6
 
Loading...
Searching...
No Matches
b2logging.H
Go to the documentation of this file.
1//------------------------------------------------------------------------
2// b2logging.H --
3//
4//
5// written by Mathias Doreille
6//
7// Copyright (c) 2004-2012,2017
8// SMR Engineering & Development SA
9// 2502 Bienne, Switzerland
10//
11// All Rights Reserved. Proprietary source code. The contents of
12// this file may not be disclosed to third parties, copied or
13// duplicated in any form, in whole or in part, without the prior
14// written permission of SMR.
15//------------------------------------------------------------------------
16
21#ifndef B2LOGGING_H_
22#define B2LOGGING_H_
23
24#include <algorithm>
25#include <complex>
26#include <fstream>
27#include <ios>
28#include <list>
29#include <map>
30#include <ostream>
31#include <sstream>
32#include <string>
33#include <vector>
34
35#include "b2ppconfig.h"
36#include "utils/b2csda.H"
37#include "utils/b2exception.H"
38#include "utils/b2object.H"
39#include "utils/b2path.H"
40#include "utils/b2time.H"
41#include "utils/b2util.H"
42
43#ifdef HAVE_LIB_TBB
44#include "tbb/spin_mutex.h"
45#define thread_local_storage __thread
46#else
47#define thread_local_storage
48#endif
49
147namespace b2000 { namespace logging {
148
149class Level {
150public:
151 Level() : value(0) {}
152
153 Level(const std::string& name) {
154 std::vector<std::string>::iterator i = std::find(list_name.begin(), list_name.end(), name);
155 if (i == list_name.end()) {
156 KeyError() << "The logging level id " << name << " is not defined." << THROW;
157 } else {
158 value = i - list_name.begin();
159 }
160 }
161
162 Level(const std::string& name_, int value_) : value(value_) {
163 list_name.resize(value + 1);
164 if (list_name[value].size() != 0) {
165 if (list_name[value] == name_) { return; }
166 KeyError() << "The logging level " << value
167 << " is already used by the logging level id " << list_name[value] << "."
168 << THROW;
169 }
170 list_name[value] = name_;
171 }
172
173 const std::string& get_name() const { return list_name[value]; }
174
175 int get_value() const { return value; }
176
177 bool operator<=(const Level l) const { return value <= l.value; }
178
179 bool operator<(const Level l) const { return value < l.value; }
180
181private:
182 static std::vector<std::string> list_name;
183 int value;
184};
185
186extern Level not_set;
187
190extern Level critical;
191
194extern Level error;
195
198extern Level warning;
199
201extern Level info;
202
204extern Level data;
205
208extern Level debug;
209
210extern Level max_level;
211
214class DBName : public std::string {
215public:
216 DBName() {}
217 template <typename T1>
218 DBName(const T1& t1) {
219 std::ostringstream o;
220 o << t1;
221 *this += o.str();
222 }
223 template <typename T1, typename T2>
224 DBName(const T1& t1, const T2& t2) {
225 std::ostringstream o;
226 o << t1 << "." << t2;
227 *this += o.str();
228 }
229 template <typename T1, typename T2, typename T3>
230 DBName(const T1& t1, const T2& t2, const T3& t3) {
231 std::ostringstream o;
232 o << t1 << "." << t2 << "." << t3;
233 *this += o.str();
234 }
235 template <typename T1, typename T2, typename T3, typename T4>
236 DBName(const T1& t1, const T2& t2, const T3& t3, const T4& t4) {
237 std::ostringstream o;
238 o << t1 << "." << t2 << "." << t3 << "." << t4;
239 *this += o.str();
240 }
241 template <typename T1, typename T2, typename T3, typename T4, typename T5>
242 DBName(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5) {
243 std::ostringstream o;
244 o << t1 << "." << t2 << "." << t3 << "." << t4 << "." << t5;
245 *this += o.str();
246 }
247 template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
248 DBName(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5, const T6& t6) {
249 std::ostringstream o;
250 o << t1 << "." << t2 << "." << t3 << "." << t4 << "." << t5 << "." << t6;
251 *this += o.str();
252 }
253};
254
255class DBObject {
256public:
257 typedef std::list<DBObject>::const_iterator iterator;
258
259 DBObject(
260 size_t pos_, const DBName& name_, const std::string& subname_, size_t ndim_,
261 const size_t dim_[][2], char type_, const void* value_)
262 : pos(pos_),
263 name(name_),
264 subname(subname_),
265 ndim(ndim_),
266 type(type_),
267 value(static_cast<const char*>(value_)) {
268 std::copy((size_t*)dim_, (size_t*)(dim_ + ndim_), (size_t*)dim);
269 }
270 size_t pos;
271 DBName name;
272 std::string subname;
273 size_t ndim;
274 size_t dim[2][2];
275 char type;
276 const char* value;
277};
278
279class Formatter {
280public:
281 virtual ~Formatter() {}
282
283 virtual std::string prefix(
284 const std::string name, const Level level, const char* file, int line) const = 0;
285
286 virtual void format(
287 std::ostream& out, const std::string& msg, DBObject::iterator begin,
288 DBObject::iterator end, bool with_dboject = true) const = 0;
289};
290
291class BasicFormatter : public Formatter {
292public:
293 BasicFormatter(const char* time_format_) : time_format(time_format_) {}
294
295 std::string prefix(
296 const std::string name, const Level level, const char* file, int line) const override {
297 return level.get_name() + ":" + name + ":" + Time().time_formats(time_format) + ":";
298 }
299
300 void format(
301 std::ostream& out, const std::string& msg, DBObject::iterator begin,
302 DBObject::iterator end, bool with_dboject = true) const override;
303
304protected:
305 const char* time_format;
306
307private:
308 template <typename T>
309 void write_dbobject(
310 std::ostream& out, size_t ndim, const size_t dim[][2], const T* value) const {
311 if (ndim == 1) {
312 out << "( ";
313 for (size_t i = 0; i != dim[0][0]; ++i, value += dim[0][1]) { out << *value << ", "; }
314 out << ")" << std::endl;
315 } else if (ndim == 2) {
316 out << "( ";
317 for (size_t i = 0; i != dim[0][0]; ++i, value += dim[0][1]) {
318 out << "( ";
319 const T* value1 = value;
320 for (size_t j = 0; j != dim[1][0]; ++j, value1 += dim[1][1]) {
321 out << *value1 << ", ";
322 }
323 out << ")," << std::endl;
324 }
325 out << ")" << std::endl;
326 } else {
328 }
329 }
330};
331
332class AllFormatter : public BasicFormatter {
333public:
334 AllFormatter(const char* time_format_) : BasicFormatter(time_format_) {}
335
336 std::string prefix(
337 const std::string name, const Level level, const char* file, int line) const override {
338 std::ostringstream s(BasicFormatter::prefix(name, level, file, line));
339 s << file << ':' << line << ':';
340 return s.str();
341 }
342};
343
352class ColorFormatter : public BasicFormatter {
353public:
354 ColorFormatter(const char* time_format_) : BasicFormatter(time_format_) {}
355
356 std::string prefix(
357 const std::string name, const Level level, const char* file, int line) const override;
358};
359
360class Handler {
361public:
362 Handler(const Formatter* formatter_) : formatter(formatter_) {}
363
364 virtual ~Handler() { delete formatter; }
365
366 void set_formatter(const Formatter* formatter_) {
367 delete formatter;
368 formatter = formatter_;
369 }
370
371 void handle(
372 const std::string name_, const Level level, const char* file, int line,
373 const std::string& msg, DBObject::iterator begin, DBObject::iterator end) {
374#ifdef HAVE_LIB_TBB
375 tbb::spin_mutex::scoped_lock lock(mutex);
376#endif
377 if (formatter) {
378 emit(formatter->prefix(name_, level, file, line), msg, begin, end);
379 } else {
380 emit("", msg, begin, end);
381 }
382 }
383
384protected:
385 virtual void emit(
386 const std::string& prefix, const std::string& msg, DBObject::iterator begin,
387 DBObject::iterator end) = 0;
388
389 const Formatter* formatter;
390
391private:
392 std::string name;
393#ifdef HAVE_LIB_TBB
394 tbb::spin_mutex mutex;
395#endif
396};
397
398class StreamHandler : public Handler {
399public:
400 StreamHandler(std::ostream& ostream_, const Formatter* formatter_)
401 : Handler(formatter_), ostream(ostream_) {}
402
403private:
404 void emit(
405 const std::string& prefix, const std::string& msg, DBObject::iterator begin,
406 DBObject::iterator end) override {
407 ostream << prefix << " ";
408 formatter->format(ostream, msg, begin, end);
409 }
410 std::ostream& ostream;
411};
412
413class ExceptionHandler : public Handler {
414public:
415 ExceptionHandler() : Handler(nullptr) {}
416
417private:
418 void emit(
419 const std::string& prefix, const std::string& msg, DBObject::iterator begin,
420 DBObject::iterator end) override {
421 LoggingError() << "This level of logging message is configured to raise an exception error."
422 << THROW;
423 }
424};
425
426class FileHandler : public Handler {
427public:
428 FileHandler(const char* filename, std::ios_base::openmode mode, const Formatter* formatter_)
429 : Handler(formatter_), ofstream(filename, mode) {}
430
431 void open(
432 const char* filename = "/dev/null", std::ios_base::openmode mode = std::ios_base::app) {
433 ofstream.close();
434 ofstream.open(filename, mode);
435 }
436
437protected:
438 void emit(
439 const std::string& prefix, const std::string& msg, DBObject::iterator begin,
440 DBObject::iterator end) override {
441 ofstream << prefix << " ";
442 formatter->format(ofstream, msg, begin, end);
443 Time t;
444 if ((t - last_sync) > 5) {
445 ofstream.flush();
446 last_sync = t;
447 }
448 }
449
450private:
451 std::ofstream ofstream;
452 Time last_sync;
453};
454
455class DBHandler : public Handler {
456public:
457 DBHandler(
458 const char* db_name, const char* memcom_db_name, const char* db_log_file,
459 std::ios_base::openmode mode, const Formatter* formatter_);
460
461 ~DBHandler() override;
462
463 void open(
464 const char* db_name = nullptr, const char* memcom_db_name = "log.mc",
465 const char* db_log_file = "log.txt", std::ios_base::openmode mode = std::ios_base::app);
466
467protected:
468 void emit(
469 const std::string& prefix, const std::string& msg, DBObject::iterator begin,
470 DBObject::iterator end) override;
471
472private:
473 static std::string get_name(const char* db_name, const char* suffix) {
474 std::string name(db_name);
475 name = path::abspath(name);
476 if (!path::isdir(name)) {
477 name += ".b2m";
478 if (!path::isdir(name)) {
479 Exception() << "Can not open the B2000 database \"" << name << "\"." << THROW;
480 }
481 }
482 return path::join(name, suffix);
483 }
484 std::ofstream ofstream;
485 int db_handler;
486 double time_sync;
487 Time last_sync;
488};
489
495class Logger {
496public:
497 Logger(const Logger& l)
498 : name(l.name),
499 parent(l.parent),
500 list_children(l.list_children),
501 list_handler(l.list_handler) {
502#ifdef HAVE_LIB_TBB
503 tbb::spin_mutex::scoped_lock lock(mutex);
504#endif
505 update();
506 }
507
508 struct Flush {
509 Flush(const char* file_ = nullptr, int line_ = -1) : file(file_), line(line_) {}
510 const char* file;
511 int line;
512 };
513
514#define LOGFLUSH Logger::Flush(__FILE__, __LINE__)
515
516 Logger& operator<<(const Level& level) {
517 if (!thread_local_data) { thread_local_data = new thread_local_data_t(); }
518 thread_local_data->current_level = level;
519 return *this;
520 }
521
522 Logger& operator<<(const std::string& a) {
523 if (thread_local_data->current_level <= real_max_logged_level) {
524 thread_local_data->current_msg << a;
525 }
526 return *this;
527 }
528
529 template <typename T>
530 Logger& operator<<(const T& n) {
531 if (thread_local_data->current_level <= real_max_logged_level) {
532 thread_local_data->current_msg << n;
533 }
534 return *this;
535 }
536
537 Logger& operator<<(const DBName& a) {
538 if (thread_local_data->current_level <= real_max_logged_level) {
539 thread_local_data->current_db_name = a;
540 }
541 return *this;
542 }
543
544 Logger& write(size_t size, const double* vector, size_t incr, const std::string& subname = "") {
545 if (thread_local_data->current_level <= real_max_logged_level) {
546 size_t dim[1][2] = {{size, incr}};
547 write_untyped(1, dim, 'd', vector, subname);
548 }
549 return *this;
550 }
551
552 Logger& write(
553 size_t size, const b2000::csda<double>* vector, size_t incr,
554 const std::string& subname = "") {
555 if (thread_local_data->current_level <= real_max_logged_level) {
556 size_t dim[1][2] = {{size, incr}};
557 write_untyped(1, dim, 'z', vector, subname);
558 }
559 return *this;
560 }
561
562 Logger& write(
563 size_t size, const std::complex<double>* vector, size_t incr,
564 const std::string& subname = "") {
565 if (thread_local_data->current_level <= real_max_logged_level) {
566 size_t dim[1][2] = {{size, incr}};
567 write_untyped(1, dim, 'z', vector, subname);
568 }
569 return *this;
570 }
571
572 Logger& write(size_t size, const float* vector, size_t incr, const std::string& subname = "") {
573 if (thread_local_data->current_level <= real_max_logged_level) {
574 size_t dim[1][2] = {{size, incr}};
575 write_untyped(1, dim, 'f', vector, subname);
576 }
577 return *this;
578 }
579
580 Logger& write(size_t size, const int* vector, size_t incr, const std::string& subname = "") {
581 if (thread_local_data->current_level <= real_max_logged_level) {
582 size_t dim[1][2] = {{size, incr}};
583 write_untyped(1, dim, 'i', vector, subname);
584 }
585 return *this;
586 }
587
588 Logger& write(
589 size_t size, const unsigned int* vector, size_t incr, const std::string& subname = "") {
590 if (thread_local_data->current_level <= real_max_logged_level) {
591 size_t dim[1][2] = {{size, incr}};
592 write_untyped(1, dim, 'j', vector, subname);
593 }
594 return *this;
595 }
596
597 Logger& write(size_t size, const long* vector, size_t incr, const std::string& subname = "") {
598 if (thread_local_data->current_level <= real_max_logged_level) {
599 size_t dim[1][2] = {{size, incr}};
600 write_untyped(1, dim, 'l', vector, subname);
601 }
602 return *this;
603 }
604
605 Logger& write(
606 size_t size, const unsigned long* vector, size_t incr, const std::string& subname = "") {
607 if (thread_local_data->current_level <= real_max_logged_level) {
608 size_t dim[1][2] = {{size, incr}};
609 write_untyped(1, dim, 'm', vector, subname);
610 }
611 return *this;
612 }
613
614 Logger& write(
615 size_t dim1, size_t dim2, const double* matrix, size_t ldv,
616 const std::string& subname = "") {
617 if (thread_local_data->current_level <= real_max_logged_level) {
618 size_t dim[2][2] = {{dim1, 1}, {dim2, ldv}};
619 write_untyped(2, dim, 'd', matrix, subname);
620 }
621 return *this;
622 }
623
624 Logger& write(
625 size_t dim1, size_t dim2, const b2000::csda<double>* matrix, size_t ldv,
626 const std::string& subname = "") {
627 if (thread_local_data->current_level <= real_max_logged_level) {
628 size_t dim[2][2] = {{dim1, 1}, {dim2, ldv}};
629 write_untyped(2, dim, 'z', matrix, subname);
630 }
631 return *this;
632 }
633
634 Logger& write(
635 size_t dim1, size_t dim2, const std::complex<double>* matrix, size_t ldv,
636 const std::string& subname = "") {
637 if (thread_local_data->current_level <= real_max_logged_level) {
638 size_t dim[2][2] = {{dim1, 1}, {dim2, ldv}};
639 write_untyped(2, dim, 'z', matrix, subname);
640 }
641 return *this;
642 }
643
644 Logger& write(
645 size_t dim1, size_t dim2, const float* matrix, size_t ldv,
646 const std::string& subname = "") {
647 if (thread_local_data->current_level <= real_max_logged_level) {
648 size_t dim[2][2] = {{dim1, 1}, {dim2, ldv}};
649 write_untyped(2, dim, 'f', matrix, subname);
650 }
651 return *this;
652 }
653
654 Logger& write(
655 size_t dim1, size_t dim2, const int* matrix, size_t ldv,
656 const std::string& subname = "") {
657 if (thread_local_data->current_level <= real_max_logged_level) {
658 size_t dim[2][2] = {{dim1, 1}, {dim2, ldv}};
659 write_untyped(2, dim, 'd', matrix, subname);
660 }
661 return *this;
662 }
663
664 Logger& write(
665 size_t dim1, size_t dim2, const long* matrix, size_t ldv,
666 const std::string& subname = "") {
667 if (thread_local_data->current_level <= real_max_logged_level) {
668 size_t dim[2][2] = {{dim1, 1}, {dim2, ldv}};
669 write_untyped(2, dim, 'd', matrix, subname);
670 }
671 return *this;
672 }
673
674 Logger& operator<<(const Flush& flush) {
675 for (real_list_handler_t::iterator i = real_list_handler_begin;
676 i != real_list_handler_end && thread_local_data->current_level <= i->second; ++i) {
677 if (thread_local_data->current_level <= i->second) {
678 i->first->handle(
679 get_name(), thread_local_data->current_level, flush.file, flush.line,
680 thread_local_data->current_msg.str(), thread_local_data->list_dbo.begin(),
681 thread_local_data->list_dbo.end());
682 }
683 }
684 thread_local_data->current_level = not_set;
685 thread_local_data->current_msg.str("");
686 thread_local_data->list_dbo.clear();
687 return *this;
688 }
689
690 void log(const Level level, const std::string& msg, const char* file = nullptr, int line = -1) {
691 if (!thread_local_data) { thread_local_data = new thread_local_data_t(); }
692 for (real_list_handler_t::iterator i = real_list_handler_begin;
693 i != real_list_handler_end && level <= i->second; ++i) {
694 i->first->handle(
695 get_name(), level, file, line, msg, thread_local_data->list_dbo.begin(),
696 thread_local_data->list_dbo.end());
697 }
698 }
699
700#define LOG(level, msg) log(level, msg, __FILE__, __LINE__)
701
702 bool is_enabled_for(const Level level) const { return level <= real_max_logged_level; }
703
704 const std::string get_name() const {
705 if (parent) {
706 if (parent != &root_logger) {
707 return parent->get_name() + "." + name;
708 } else {
709 return name;
710 }
711 } else {
712 return "all";
713 }
714 }
715
716 void add_handler(Handler* handler, Level& level) {
717 if (list_handler.count(handler)) {
718 if (list_handler[handler] < level) { list_handler[handler] = level; }
719 } else {
720 list_handler[handler] = level;
721 }
722#ifdef HAVE_LIB_TBB
723 tbb::spin_mutex::scoped_lock lock(mutex);
724#endif
725 update();
726 }
727
728 void remove_handler(Handler* handler) {
729 list_handler.erase(handler);
730#ifdef HAVE_LIB_TBB
731 tbb::spin_mutex::scoped_lock lock(mutex);
732#endif
733 update();
734 }
735
736 Logger& get_logger(const std::string& logger_name) {
737 int p = logger_name.find('.');
738 list_children_t::iterator i = list_children.find(logger_name.substr(0, p));
739 if (i == list_children.end()) {
740 i = list_children
741 .insert(list_children_t::value_type(
742 logger_name.substr(0, p), Logger(logger_name.substr(0, p), this)))
743 .first;
744 }
745 if (p == -1) {
746 return i->second;
747 } else {
748 return i->second.get_logger(logger_name.substr(p + 1));
749 }
750 }
751
752 template <typename Function>
753 void for_each(Function f) const {
754 f(*this);
755 for (list_children_t::const_iterator i = list_children.begin(); i != list_children.end();
756 ++i) {
757 i->second.for_each(f);
758 }
759 }
760
761 void print_list(std::ostream& out, const std::string& prefix = "") const {
762 for_each(PrintName(out, prefix));
763 }
764
765 static Logger root_logger;
766
767private:
768 void write_untyped(
769 size_t ndim, size_t dim[][2], char element_type, const void* value,
770 const std::string& subname = "") {
771 thread_local_data->list_dbo.push_back(DBObject(
772 thread_local_data->current_msg.str().size(), thread_local_data->current_db_name,
773 subname, ndim, dim, element_type, value));
774 }
775
776 Logger(const std::string& name_, Logger* parent_) : name(name_), parent(parent_) {
777#ifdef HAVE_LIB_TBB
778 tbb::spin_mutex::scoped_lock lock(mutex);
779#endif
780 update();
781 }
782
783 struct Comp {
784 bool operator()(
785 const std::pair<Handler* const, Level>& a,
786 const std::pair<Handler* const, Level>& b) const {
787 return b.second < a.second;
788 }
789 };
790
791 struct PrintName {
792 PrintName(std::ostream& out_, const std::string& prefix_) : out(out_), prefix(prefix_) {}
793 void operator()(const Logger& l) { out << prefix << l.get_name() << std::endl; }
794 std::ostream& out;
795 const std::string& prefix;
796 };
797
798 void update();
799
800 std::string name;
801 Logger* parent;
802 typedef std::map<std::string, Logger> list_children_t;
803 list_children_t list_children;
804 typedef std::map<Handler*, Level> list_handler_t;
805 list_handler_t list_handler;
806
807 Level real_max_logged_level;
808 typedef std::vector<std::pair<Handler*, Level> > real_list_handler_t;
809 real_list_handler_t real_list_handler;
810 real_list_handler_t::iterator real_list_handler_begin;
811 real_list_handler_t::iterator real_list_handler_end;
812
813 struct thread_local_data_t {
814 std::ostringstream current_msg;
815 Level current_level;
816 DBName current_db_name;
817 typedef std::list<DBObject> list_dbo_t;
818 list_dbo_t list_dbo;
819 };
820 static thread_local_storage thread_local_data_t* thread_local_data;
821
822#ifdef HAVE_LIB_TBB
823 static tbb::spin_mutex mutex;
824#endif
825};
826
829inline Logger& get_logger(const std::string& logger_name = "") {
830 if (logger_name.empty()) { return Logger::root_logger; }
831 return Logger::root_logger.get_logger(logger_name);
832}
833
839 const std::string& s, const std::string& db_name, const bool dry_run = false);
840
841}} // namespace b2000::logging
842
843#endif // B2LOGGING_H_
bool operator<=(const csda< T1 > &a, const csda< T2 > &b)
Comparison of two csda numbers is performed on the real part only.
Definition b2csda.H:298
bool operator<(const csda< T1 > &a, const csda< T2 > &b)
Comparison of two csda numbers is performed on the real part only.
Definition b2csda.H:262
#define THROW
Definition b2exception.H:198
Definition b2logging.H:214
Definition b2logging.H:495
void parse_on_logging_option(const std::string &s, const std::string &db_name, const bool dry_run=false)
Definition b2logging.C:84
Logger & get_logger(const std::string &logger_name="")
Definition b2logging.H:829
std::string join(const std::string &a, const std::string &b)
Definition b2path.C:165
std::string abspath(const std::string &path)
Definition b2path.C:99
bool isdir(const std::string &path)
Definition b2path.C:41
Contains the base classes for implementing Finite Elements.
Definition b2boundary_condition.H:32
GenericException< KeyError_name > KeyError
Definition b2exception.H:320
GenericException< SystemError_name > LoggingError
Definition b2exception.H:363
GenericException< UnimplementedError_name > UnimplementedError
Definition b2exception.H:314