A toolkit for working with phylogenetic data.
v0.24.0
logging.hpp
Go to the documentation of this file.
1 #ifndef GENESIS_UTILS_CORE_LOGGING_H_
2 #define GENESIS_UTILS_CORE_LOGGING_H_
3 
4 /*
5  Genesis - A toolkit for working with phylogenetic data.
6  Copyright (C) 2014-2019 Lucas Czech and HITS gGmbH
7 
8  This program is free software: you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation, either version 3 of the License, or
11  (at your option) any later version.
12 
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program. If not, see <http://www.gnu.org/licenses/>.
20 
21  Contact:
22  Lucas Czech <lucas.czech@h-its.org>
23  Exelixis Lab, Heidelberg Institute for Theoretical Studies
24  Schloss-Wolfsbrunnenweg 35, D-69118 Heidelberg, Germany
25 */
26 
38 
39 #include <cmath>
40 #include <iosfwd>
41 #include <sstream>
42 #include <string>
43 #include <vector>
44 
45 namespace genesis {
46 namespace utils {
47 
48 // =============================================================================
49 // Macro definitions
50 // =============================================================================
51 
52 // TODO add TIME1..4 (or TMR maybe) for indented timing logs
53 // TODO change macros for timing to be out of usual log levels
54 // TODO define a function that logs the detail column headers (difficult because
55 // of length difference for file name log detail)
56 // TODO offer csv as output format
57 // TODO offer remote streams
58 
59 #ifndef LOG_LEVEL_MAX
60 
65 # define LOG_LEVEL_MAX genesis::utils::Logging::kDebug4
66 #endif
67 
68 // TODO make DEBUG a special macro with proper usage makefile etc,
69 // also add maybe stuff like RELEASE TEST etc, prepend ENV_ or so!
70 // TODO do an undefine first
71 
72 // override this setting when debugging is turned on (eg by makefile)
73 #ifdef DEBUG
74 # define LOG_LEVEL_MAX genesis::utils::Logging::kDebug4
75 #endif
76 
77 // define the actual log macro, so that the compiler can prune calls
78 // to a log with levels above the static max log level
79 #define GENESIS_LOG(level) \
80  if (level > LOG_LEVEL_MAX) ; \
81  else if (level > genesis::utils::Logging::max_level()) ; \
82  else genesis::utils::Logging().get(__FILE__, __LINE__, GENESIS_FUNC, level)
83 
84 // define a similar log macro, this time changing the details of the message
85 #define GENESIS_LOG_DETAILS(level, ...) \
86  if (level > LOG_LEVEL_MAX) ; \
87  else if (level > genesis::utils::Logging::max_level()) ; \
88  else genesis::utils::Logging().get(__FILE__, __LINE__, GENESIS_FUNC, level, {__VA_ARGS__})
89 
90 // define standard logging types as macro shortcuts:
91 
93 #define LOG_ERR GENESIS_LOG(genesis::utils::Logging::kError)
94 
96 #define LOG_WARN GENESIS_LOG(genesis::utils::Logging::kWarning)
97 
99 #define LOG_INFO GENESIS_LOG(genesis::utils::Logging::kInfo)
100 
102 #define LOG_MSG GENESIS_LOG(genesis::utils::Logging::kMessage)
103 
105 #define LOG_MSG1 GENESIS_LOG(genesis::utils::Logging::kMessage1)
106 
108 #define LOG_MSG2 GENESIS_LOG(genesis::utils::Logging::kMessage2)
109 
111 #define LOG_MSG3 GENESIS_LOG(genesis::utils::Logging::kMessage3)
112 
114 #define LOG_MSG4 GENESIS_LOG(genesis::utils::Logging::kMessage4)
115 
117 #define LOG_DBG GENESIS_LOG(genesis::utils::Logging::kDebug)
118 
120 #define LOG_DBG1 GENESIS_LOG(genesis::utils::Logging::kDebug1)
121 
123 #define LOG_DBG2 GENESIS_LOG(genesis::utils::Logging::kDebug2)
124 
126 #define LOG_DBG3 GENESIS_LOG(genesis::utils::Logging::kDebug3)
127 
129 #define LOG_DBG4 GENESIS_LOG(genesis::utils::Logging::kDebug4)
130 
131 // define special log shortcuts: the list of bools represent
132 // the members of struct LogDetails and indicate which parts shall be included.
133 
142 #define LOG_BOLD GENESIS_LOG_DETAILS(genesis::utils::Logging::kNone, \
143  false, false, false, false, false, false, false, false, false)
144 
153 #define LOG_TIME GENESIS_LOG_DETAILS(genesis::utils::Logging::kDebug, \
154  false, false, false, false , true, false, false, false, false)
155 
164 #define LOG_SCOPE_LEVEL(level) \
165  genesis::utils::LoggingScopeLevel genesis_logging_scope_level_temp_object(level);
166 
178 inline long logging_progress_value (long value = -1)
179 {
180  static long v = -1;
181  if (value > -1) {
182  v = value;
183  }
184  return v;
185 }
186 
231 #define LOG_PROG( value, quantity ) \
232  if( genesis::utils::Logging::kProgress > LOG_LEVEL_MAX ) ; \
233  else if( genesis::utils::Logging::kProgress > genesis::utils::Logging::max_level() ) ; \
234  else if( (long) genesis::utils::logging_progress_value(value) % \
235  (((long) (quantity) * genesis::utils::Logging::report_percentage() / 100) > 0 ? \
236  ((long) (quantity) * genesis::utils::Logging::report_percentage() / 100) : 1) != 0 ) ; \
237  else genesis::utils::Logging().get(__FILE__, __LINE__, GENESIS_FUNC, genesis::utils::Logging::kProgress) << \
238  (int) round(100.0 * (double) genesis::utils::logging_progress_value() / ((quantity) > 0 ? (quantity) : 1)) << "% "
239 
240 // =============================================================================
241 // Logging Details
242 // =============================================================================
243 
267 
268  LoggingDetails() = default;
269 
271  bool v_count, bool v_date, bool v_time, bool v_runtime, bool v_rundiff,
272  bool v_file, bool v_line, bool v_function, bool v_level
273  )
274  : count( v_count )
275  , date( v_date )
276  , time( v_time )
277  , runtime( v_runtime )
278  , rundiff( v_rundiff )
279  , file( v_file )
280  , line( v_line )
281  , function( v_function )
282  , level( v_level )
283  {}
284 
286  bool count = false;
287 
289  bool date = false;
290 
292  bool time = false;
293 
295  bool runtime = false;
296 
304  bool rundiff = false;
305 
307  bool file = false;
308 
313  bool line = false;
314 
320  bool function = false;
321 
323  bool level = false;
324 };
325 
326 // =============================================================================
327 // Logging
328 // =============================================================================
329 
385 class Logging
386 {
387 public:
388 
389  // -------------------------------------------------------------------
390  // Class Functions
391  // -------------------------------------------------------------------
392 
406  kNone = 0,
407 
410 
413 
416 
419 
422 
425 
428 
431 
434 
437 
440 
443 
446 
448  kDebug4
449  };
450 
451  Logging() {}
452  ~Logging();
453 
454  // Logging is kind of singleton, its instances are only provided via the
455  // get functions. do not allow other instances by blocking the copy
456  // constructors and copy assignment
457  Logging (const Logging&) {}
458  Logging& operator = (const Logging&) = delete;
459 
460  // getter for the singleton instance of log, is called by the macros
461  std::ostringstream& get (
462  const std::string& file, const int line, const std::string& function,
463  const LoggingLevel level
464  );
465  std::ostringstream& get (
466  const std::string& file, const int line, const std::string& function,
467  const LoggingLevel level, const LoggingDetails dets
468  );
469 
470  // -------------------------------------------------------------------
471  // Logging Settings
472  // -------------------------------------------------------------------
473 
474  // TODO make logging accept one file, and a setter for cout and for cerr
475  // TODO allow different levels to be logged to different streams?!
476 
477  // methods to handle the output streams to write the log messages to
478  static void log_to_stdout ();
479  static void log_to_stream (std::ostream& os);
480  static void log_to_file (const std::string& fn);
481  static void clear();
482 
488 
490  static inline LoggingLevel max_level ()
491  {
492  return max_level_;
493  }
494  static void max_level (const LoggingLevel level);
495 
497  static inline int report_percentage ()
498  {
499  return report_percentage_;
500  }
501  static void report_percentage (const int percentage);
502 
503  // return a string representation for a log level
504  static std::string level_to_string (const LoggingLevel level);
505 
507  static std::string debug_indent;
508 
509  // -------------------------------------------------------------------
510  // Static Wrappers
511  // -------------------------------------------------------------------
512 
513  static inline void log_error (const std::string& msg)
514  {
515  LOG_ERR << msg;
516  }
517 
518  static inline void log_warning (const std::string& msg)
519  {
520  LOG_WARN << msg;
521  }
522 
523  static inline void log_info (const std::string& msg)
524  {
525  LOG_INFO << msg;
526  }
527 
528  static inline void log_message (const std::string& msg)
529  {
530  LOG_MSG << msg;
531  }
532 
533  static inline void log_message_1 (const std::string& msg)
534  {
535  LOG_MSG1 << msg;
536  }
537 
538  static inline void log_message_2 (const std::string& msg)
539  {
540  LOG_MSG2 << msg;
541  }
542 
543  static inline void log_message_3 (const std::string& msg)
544  {
545  LOG_MSG3 << msg;
546  }
547 
548  static inline void log_message_4 (const std::string& msg)
549  {
550  LOG_MSG4 << msg;
551  }
552 
553  static inline void log_debug (const std::string& msg)
554  {
555  LOG_DBG << msg;
556  }
557 
558  static inline void log_debug_1 (const std::string& msg)
559  {
560  LOG_DBG1 << msg;
561  }
562 
563  static inline void log_debug_2 (const std::string& msg)
564  {
565  LOG_DBG2 << msg;
566  }
567 
568  static inline void log_debug_3 (const std::string& msg)
569  {
570  LOG_DBG3 << msg;
571  }
572 
573  static inline void log_debug_4 (const std::string& msg)
574  {
575  LOG_DBG4 << msg;
576  }
577 
578  // -------------------------------------------------------------------
579  // Internal Data Members
580  // -------------------------------------------------------------------
581 
582 protected:
583  // storage for information needed during one invocation of a log
584  std::ostringstream buff_;
585  std::string file_;
586  int line_ = 0;
587  std::string function_;
588  LoggingLevel level_ = {};
589  LoggingDetails details_ = {};
590 
591  // dynamic log level limit
593 
594  // how often to report progress messages
595  static int report_percentage_;
596 
597  // how many log calls were made so far
598  static long count_;
599 
600  // when was the last call to logging (used for time measurements)
601  static clock_t last_clock_;
602 
603  // Arrays of streams that are used for output.
604  // We separate normal output streams from file streams, so that the latter can be closes properly.
605  static std::vector<std::ostream*> ostreams_;
606  static std::vector<std::ofstream*> fstreams_;
607 };
608 
609 // =============================================================================
610 // Logging Scope Level
611 // =============================================================================
612 
618 {
619 public:
620  explicit LoggingScopeLevel( Logging::LoggingLevel scope_level )
621  {
622  previous_level = Logging::max_level();
623  Logging::max_level(scope_level);
624  }
625 
627  {
628  Logging::max_level(previous_level);
629  }
630 
631 private:
632  Logging::LoggingLevel previous_level;
633 };
634 
635 // =============================================================================
636 // Logging Progress
637 // =============================================================================
638 
639 /*
640  * This was a test to make LOG_PROG work with incrementing counters like
641  *
642  * LOG_PROG(++progress, total) << "of something";
643  *
644  * but it is slow and dirty. If used, Logging().get(...) has to be expanded by a
645  * std::string init parameters, that is used to initialize buff_.str(init).
646  *
647  * Also, the definition of LOG_PROG that was used for this is:
648  *
649  * #define LOG_PROG(value, quantity) \
650  * if (genesis::utils::Logging::kProgress > LOG_LEVEL_MAX) ; \
651  * else if (genesis::utils::Logging::kProgress > genesis::utils::Logging::max_level()) ; \
652  * else LOG_PROG_FUNC(value, quantity, __FILE__, __LINE__, GENESIS_FUNC)
653  * %
654 inline std::ostringstream& LOG_PROG_FUNC (const int value, const int quantity, const std::string& file, const int line, const std::string& function)
655 {
656  static std::ostringstream trash;
657  int base = quantity * Logging::report_percentage() / 100;
658  if (value % (base > 0 ? base : 1) != 0) {
659  trash.str("");
660  return trash;
661  } else {
662  std::string init = std::to_string((int) round(100.0 * (double) value / quantity)) + "% ";
663  return Logging().get(file, line, function, Logging::kProgress, Logging::details, init);
664  }
665 }
666 */
667 
668 } // namespace utils
669 } // namespace genesis
670 
671 #endif // include guard
Skip no whitespace. Thus, immediately treat the current input char.
static void log_debug_3(const std::string &msg)
Definition: logging.hpp:568
static std::string debug_indent
Indention string for Debug Levels 1-4.
Definition: logging.hpp:507
#define LOG_ERR
Log an error. See genesis::utils::LoggingLevel.
Definition: logging.hpp:93
static int report_percentage_
Definition: logging.hpp:595
#define LOG_DBG
Log a debug message. See genesis::utils::LoggingLevel.
Definition: logging.hpp:117
Debugging message with indent level 2. See LOG_DBG2.
Definition: logging.hpp:442
static LoggingDetails details
Settings for which information is included with each log message. See LoggingDetails for usage...
Definition: logging.hpp:487
static void log_warning(const std::string &msg)
Definition: logging.hpp:518
Errors, usually non-recoverable. See LOG_ERR.
Definition: logging.hpp:409
static void log_debug(const std::string &msg)
Definition: logging.hpp:553
static std::vector< std::ostream * > ostreams_
Definition: logging.hpp:605
#define LOG_MSG4
Log an info message. See genesis::utils::LoggingLevel.
Definition: logging.hpp:114
#define LOG_DBG4
Log a debug message. See genesis::utils::LoggingLevel.
Definition: logging.hpp:129
std::ostringstream buff_
Definition: logging.hpp:584
#define LOG_DBG1
Log a debug message. See genesis::utils::LoggingLevel.
Definition: logging.hpp:120
#define LOG_WARN
Log a warning. See genesis::utils::LoggingLevel.
Definition: logging.hpp:96
Warnings if somthing went wront, but program can continue. See LOG_WARN.
Definition: logging.hpp:412
bool count
Include a counter of how many messages have been logged so far.
Definition: logging.hpp:286
static void log_message_2(const std::string &msg)
Definition: logging.hpp:538
static clock_t last_clock_
Definition: logging.hpp:601
Container namespace for all symbols of genesis in order to keep them separate when used as a library...
Logging class with easy and fast usage.
Definition: logging.hpp:385
Provides some valuable additions to STD.
static LoggingLevel max_level()
Get the highest log level that is reported.
Definition: logging.hpp:490
Logging(const Logging &)
Definition: logging.hpp:457
static void log_debug_2(const std::string &msg)
Definition: logging.hpp:563
LoggingDetails(bool v_count, bool v_date, bool v_time, bool v_runtime, bool v_rundiff, bool v_file, bool v_line, bool v_function, bool v_level)
Definition: logging.hpp:270
static void log_message_3(const std::string &msg)
Definition: logging.hpp:543
static std::vector< std::ofstream * > fstreams_
Definition: logging.hpp:606
Debugging message with indent level 3. See LOG_DBG3.
Definition: logging.hpp:445
bool line
Include the line of the file where the log message was generated.
Definition: logging.hpp:313
Message with level 4. See LOG_MSG4.
Definition: logging.hpp:433
bool function
Include the function name where the log message was generated.
Definition: logging.hpp:320
bool rundiff
Include the run time difference to the last log message in sec.
Definition: logging.hpp:304
static void log_info(const std::string &msg)
Definition: logging.hpp:523
Message with level 1. See LOG_MSG1.
Definition: logging.hpp:424
#define LOG_MSG
Log an info message. See genesis::utils::LoggingLevel.
Definition: logging.hpp:102
#define LOG_MSG1
Log an info message. See genesis::utils::LoggingLevel.
Definition: logging.hpp:105
static int report_percentage()
Get the current percentage for reporting LOG_PROG messages.
Definition: logging.hpp:497
#define LOG_DBG3
Log a debug message. See genesis::utils::LoggingLevel.
Definition: logging.hpp:126
Infos, for example when a file was written. See LOG_INFO.
Definition: logging.hpp:415
LoggingLevel
Levels of severity used for logging.
Definition: logging.hpp:404
long logging_progress_value(long value=-1)
Hack function to make sure that the value arugment in LOG_PROG is only evaluated once.
Definition: logging.hpp:178
static void log_error(const std::string &msg)
Definition: logging.hpp:513
bool date
Include the current date.
Definition: logging.hpp:289
bool file
Include the filename where the log message was generated.
Definition: logging.hpp:307
Class that sets the Logging Level to a value von construction and set it back on destruction. This is used by the log scope level macro.
Definition: logging.hpp:617
static void log_debug_1(const std::string &msg)
Definition: logging.hpp:558
bool runtime
Include the current run time of the program in sec.
Definition: logging.hpp:295
#define LOG_DBG2
Log a debug message. See genesis::utils::LoggingLevel.
Definition: logging.hpp:123
#define LOG_MSG2
Log an info message. See genesis::utils::LoggingLevel.
Definition: logging.hpp:108
Debugging message with indent level 1 (e.g. for loops). See LOG_DBG1.
Definition: logging.hpp:439
Progess, used in long executing functions. See LOG_PROG.
Definition: logging.hpp:418
Basic message. See LOG_MSG.
Definition: logging.hpp:421
static void log_message_4(const std::string &msg)
Definition: logging.hpp:548
std::string function_
Definition: logging.hpp:587
POD stuct containing the settings for which information is included with each logging message...
Definition: logging.hpp:266
bool level
Include the level (e.g. Info, Debug) of the message.
Definition: logging.hpp:323
Message with level 3. See LOG_MSG3.
Definition: logging.hpp:430
static void log_debug_4(const std::string &msg)
Definition: logging.hpp:573
Basic debugging message. See LOG_DBG.
Definition: logging.hpp:436
static void log_message_1(const std::string &msg)
Definition: logging.hpp:533
Message with level 2. See LOG_MSG2.
Definition: logging.hpp:427
static void log_message(const std::string &msg)
Definition: logging.hpp:528
static LoggingLevel max_level_
Definition: logging.hpp:592
LoggingScopeLevel(Logging::LoggingLevel scope_level)
Definition: logging.hpp:620
#define LOG_MSG3
Log an info message. See genesis::utils::LoggingLevel.
Definition: logging.hpp:111
#define LOG_INFO
Log an info message. See genesis::utils::LoggingLevel.
Definition: logging.hpp:99
bool time
Include the current time.
Definition: logging.hpp:292