A library for working with phylogenetic and population genetic data.
v0.27.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-2020 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 <memory>
42 #include <sstream>
43 #include <string>
44 #include <vector>
45 
46 namespace genesis {
47 namespace utils {
48 
49 // =============================================================================
50 // Macro definitions
51 // =============================================================================
52 
53 // TODO add TIME1..4 (or TMR maybe) for indented timing logs
54 // TODO change macros for timing to be out of usual log levels
55 // TODO define a function that logs the detail column headers (difficult because
56 // of length difference for file name log detail)
57 // TODO offer csv as output format
58 // TODO offer remote streams
59 
60 #ifndef LOG_LEVEL_MAX
61 
66 # define LOG_LEVEL_MAX genesis::utils::Logging::kDebug4
67 #endif
68 
69 // TODO make DEBUG a special macro with proper usage makefile etc,
70 // also add maybe stuff like RELEASE TEST etc, prepend ENV_ or so!
71 // TODO do an undefine first
72 
73 // override this setting when debugging is turned on (eg by makefile)
74 #ifdef DEBUG
75 # define LOG_LEVEL_MAX genesis::utils::Logging::kDebug4
76 #endif
77 
78 // define the actual log macro, so that the compiler can prune calls
79 // to a log with levels above the static max log level
80 #define GENESIS_LOG(level) \
81  if (level > LOG_LEVEL_MAX) ; \
82  else if (level > genesis::utils::Logging::max_level()) ; \
83  else genesis::utils::Logging().get(__FILE__, __LINE__, GENESIS_FUNC, level)
84 
85 // define a similar log macro, this time changing the details of the message
86 #define GENESIS_LOG_DETAILS(level, ...) \
87  if (level > LOG_LEVEL_MAX) ; \
88  else if (level > genesis::utils::Logging::max_level()) ; \
89  else genesis::utils::Logging().get(__FILE__, __LINE__, GENESIS_FUNC, level, {__VA_ARGS__})
90 
91 // define standard logging types as macro shortcuts:
92 
94 #define LOG_ERR GENESIS_LOG(genesis::utils::Logging::kError)
95 
97 #define LOG_WARN GENESIS_LOG(genesis::utils::Logging::kWarning)
98 
100 #define LOG_INFO GENESIS_LOG(genesis::utils::Logging::kInfo)
101 
103 #define LOG_MSG GENESIS_LOG(genesis::utils::Logging::kMessage)
104 
106 #define LOG_MSG1 GENESIS_LOG(genesis::utils::Logging::kMessage1)
107 
109 #define LOG_MSG2 GENESIS_LOG(genesis::utils::Logging::kMessage2)
110 
112 #define LOG_MSG3 GENESIS_LOG(genesis::utils::Logging::kMessage3)
113 
115 #define LOG_MSG4 GENESIS_LOG(genesis::utils::Logging::kMessage4)
116 
118 #define LOG_DBG GENESIS_LOG(genesis::utils::Logging::kDebug)
119 
121 #define LOG_DBG1 GENESIS_LOG(genesis::utils::Logging::kDebug1)
122 
124 #define LOG_DBG2 GENESIS_LOG(genesis::utils::Logging::kDebug2)
125 
127 #define LOG_DBG3 GENESIS_LOG(genesis::utils::Logging::kDebug3)
128 
130 #define LOG_DBG4 GENESIS_LOG(genesis::utils::Logging::kDebug4)
131 
132 // define special log shortcuts: the list of bools represent
133 // the members of struct LogDetails and indicate which parts shall be included.
134 
143 #define LOG_BOLD GENESIS_LOG_DETAILS(genesis::utils::Logging::kNone, \
144  false, false, false, false, false, false, false, false, false)
145 
154 #define LOG_TIME GENESIS_LOG_DETAILS(genesis::utils::Logging::kDebug, \
155  false, false, false, false , true, false, false, false, false)
156 
165 #define LOG_SCOPE_LEVEL(level) \
166  genesis::utils::LoggingScopeLevel genesis_logging_scope_level_temp_object(level);
167 
179 inline long logging_progress_value (long value = -1)
180 {
181  static long v = -1;
182  if (value > -1) {
183  v = value;
184  }
185  return v;
186 }
187 
232 #define LOG_PROG( value, quantity ) \
233  if( genesis::utils::Logging::kProgress > LOG_LEVEL_MAX ) ; \
234  else if( genesis::utils::Logging::kProgress > genesis::utils::Logging::max_level() ) ; \
235  else if( (long) genesis::utils::logging_progress_value(value) % \
236  (((long) (quantity) * genesis::utils::Logging::report_percentage() / 100) > 0 ? \
237  ((long) (quantity) * genesis::utils::Logging::report_percentage() / 100) : 1) != 0 ) ; \
238  else genesis::utils::Logging().get(__FILE__, __LINE__, GENESIS_FUNC, genesis::utils::Logging::kProgress) << \
239  (int) round(100.0 * (double) genesis::utils::logging_progress_value() / ((quantity) > 0 ? (quantity) : 1)) << "% "
240 
241 // =============================================================================
242 // Logging Details
243 // =============================================================================
244 
268 
269  LoggingDetails() = default;
270 
272  bool v_count, bool v_date, bool v_time, bool v_runtime, bool v_rundiff,
273  bool v_file, bool v_line, bool v_function, bool v_level
274  )
275  : count( v_count )
276  , date( v_date )
277  , time( v_time )
278  , runtime( v_runtime )
279  , rundiff( v_rundiff )
280  , file( v_file )
281  , line( v_line )
282  , function( v_function )
283  , level( v_level )
284  {}
285 
287  bool count = false;
288 
290  bool date = false;
291 
293  bool time = false;
294 
296  bool runtime = false;
297 
305  bool rundiff = false;
306 
308  bool file = false;
309 
314  bool line = false;
315 
321  bool function = false;
322 
324  bool level = false;
325 };
326 
327 // =============================================================================
328 // Logging
329 // =============================================================================
330 
386 class Logging
387 {
388 public:
389 
390  // -------------------------------------------------------------------
391  // Class Functions
392  // -------------------------------------------------------------------
393 
407  kNone = 0,
408 
411 
414 
417 
420 
423 
426 
429 
432 
435 
438 
441 
444 
447 
450  };
451 
452  Logging() {}
453  ~Logging();
454 
455  // Logging is kind of singleton, its instances are only provided via the
456  // get functions. do not allow other instances by blocking the copy
457  // constructors and copy assignment
458  Logging (const Logging&) {}
459  Logging& operator = (const Logging&) = delete;
460 
461  // getter for the singleton instance of log, is called by the macros
462  std::ostringstream& get (
463  const std::string& file, const int line, const std::string& function,
464  const LoggingLevel level
465  );
466  std::ostringstream& get (
467  const std::string& file, const int line, const std::string& function,
468  const LoggingLevel level, const LoggingDetails dets
469  );
470 
471  // -------------------------------------------------------------------
472  // Logging Settings
473  // -------------------------------------------------------------------
474 
475  // TODO make logging accept one file, and a setter for cout and for cerr
476  // TODO allow different levels to be logged to different streams?!
477 
478  // methods to handle the output streams to write the log messages to
479  static void log_to_stdout ();
480  static void log_to_stream (std::ostream& os);
481  static void log_to_file (const std::string& fn);
482  static void clear();
483 
489 
491  static inline LoggingLevel max_level ()
492  {
493  return max_level_;
494  }
495  static void max_level (const LoggingLevel level);
496 
498  static inline int report_percentage ()
499  {
500  return report_percentage_;
501  }
502  static void report_percentage (const int percentage);
503 
504  // return a string representation for a log level
505  static std::string level_to_string (const LoggingLevel level);
506 
508  static std::string debug_indent;
509 
510  // -------------------------------------------------------------------
511  // Static Wrappers
512  // -------------------------------------------------------------------
513 
514  static inline void log_error (const std::string& msg)
515  {
516  LOG_ERR << msg;
517  }
518 
519  static inline void log_warning (const std::string& msg)
520  {
521  LOG_WARN << msg;
522  }
523 
524  static inline void log_info (const std::string& msg)
525  {
526  LOG_INFO << msg;
527  }
528 
529  static inline void log_message (const std::string& msg)
530  {
531  LOG_MSG << msg;
532  }
533 
534  static inline void log_message_1 (const std::string& msg)
535  {
536  LOG_MSG1 << msg;
537  }
538 
539  static inline void log_message_2 (const std::string& msg)
540  {
541  LOG_MSG2 << msg;
542  }
543 
544  static inline void log_message_3 (const std::string& msg)
545  {
546  LOG_MSG3 << msg;
547  }
548 
549  static inline void log_message_4 (const std::string& msg)
550  {
551  LOG_MSG4 << msg;
552  }
553 
554  static inline void log_debug (const std::string& msg)
555  {
556  LOG_DBG << msg;
557  }
558 
559  static inline void log_debug_1 (const std::string& msg)
560  {
561  LOG_DBG1 << msg;
562  }
563 
564  static inline void log_debug_2 (const std::string& msg)
565  {
566  LOG_DBG2 << msg;
567  }
568 
569  static inline void log_debug_3 (const std::string& msg)
570  {
571  LOG_DBG3 << msg;
572  }
573 
574  static inline void log_debug_4 (const std::string& msg)
575  {
576  LOG_DBG4 << msg;
577  }
578 
579  // -------------------------------------------------------------------
580  // Internal Data Members
581  // -------------------------------------------------------------------
582 
583 protected:
584  // storage for information needed during one invocation of a log
585  std::ostringstream buff_;
586  std::string file_;
587  int line_ = 0;
588  std::string function_;
591 
592  // dynamic log level limit
594 
595  // how often to report progress messages
596  static int report_percentage_;
597 
598  // how many log calls were made so far
599  static long count_;
600 
601  // when was the last call to logging (used for time measurements)
602  static clock_t last_clock_;
603 
604  // Arrays of streams that are used for output.
605  // We separate normal output streams from file streams, so that the latter can be closed
606  // properly. That is, we take normal ostream by reference, and hence do not manage them here,
607  // but open/close/manage the lifetimes of file streams ourselves. Users can of course also
608  // provide their own file streams and add them via log_to_stream, but we don't manage those then.
609  static std::vector<std::ostream*> ostreams_;
610  static std::vector<std::unique_ptr<std::ofstream>> fstreams_;
611 };
612 
613 // =============================================================================
614 // Logging Scope Level
615 // =============================================================================
616 
622 {
623 public:
624  explicit LoggingScopeLevel( Logging::LoggingLevel scope_level )
625  {
626  previous_level = Logging::max_level();
627  Logging::max_level(scope_level);
628  }
629 
631  {
632  Logging::max_level(previous_level);
633  }
634 
635 private:
636  Logging::LoggingLevel previous_level;
637 };
638 
639 // =============================================================================
640 // Logging Progress
641 // =============================================================================
642 
643 /*
644  * This was a test to make LOG_PROG work with incrementing counters like
645  *
646  * LOG_PROG(++progress, total) << "of something";
647  *
648  * but it is slow and dirty. If used, Logging().get(...) has to be expanded by a
649  * std::string init parameters, that is used to initialize buff_.str(init).
650  *
651  * Also, the definition of LOG_PROG that was used for this is:
652  *
653  * #define LOG_PROG(value, quantity) \
654  * if (genesis::utils::Logging::kProgress > LOG_LEVEL_MAX) ; \
655  * else if (genesis::utils::Logging::kProgress > genesis::utils::Logging::max_level()) ; \
656  * else LOG_PROG_FUNC(value, quantity, __FILE__, __LINE__, GENESIS_FUNC)
657  * %
658 inline std::ostringstream& LOG_PROG_FUNC (const int value, const int quantity, const std::string& file, const int line, const std::string& function)
659 {
660  static std::ostringstream trash;
661  int base = quantity * Logging::report_percentage() / 100;
662  if (value % (base > 0 ? base : 1) != 0) {
663  trash.str("");
664  return trash;
665  } else {
666  std::string init = std::to_string((int) round(100.0 * (double) value / quantity)) + "% ";
667  return Logging().get(file, line, function, Logging::kProgress, Logging::details, init);
668  }
669 }
670 */
671 
672 } // namespace utils
673 } // namespace genesis
674 
675 #endif // include guard
LOG_INFO
#define LOG_INFO
Log an info message. See genesis::utils::LoggingLevel.
Definition: logging.hpp:100
genesis::utils::Logging::log_message_2
static void log_message_2(const std::string &msg)
Definition: logging.hpp:539
genesis::utils::LoggingDetails
POD stuct containing the settings for which information is included with each logging message.
Definition: logging.hpp:267
LOG_MSG
#define LOG_MSG
Log an info message. See genesis::utils::LoggingLevel.
Definition: logging.hpp:103
LOG_MSG1
#define LOG_MSG1
Log an info message. See genesis::utils::LoggingLevel.
Definition: logging.hpp:106
genesis::utils::Logging::fstreams_
static std::vector< std::unique_ptr< std::ofstream > > fstreams_
Definition: logging.hpp:610
genesis::utils::Logging::log_warning
static void log_warning(const std::string &msg)
Definition: logging.hpp:519
genesis::utils::Logging::kWarning
@ kWarning
Warnings if somthing went wront, but program can continue. See LOG_WARN.
Definition: logging.hpp:413
genesis::utils::Logging::report_percentage_
static int report_percentage_
Definition: logging.hpp:596
genesis::utils::Logging::log_message_4
static void log_message_4(const std::string &msg)
Definition: logging.hpp:549
genesis::utils::Logging::~Logging
~Logging()
Destructor that is invoked at the end of each log line and does the actual output.
Definition: logging.cpp:184
genesis::utils::LoggingDetails::date
bool date
Include the current date.
Definition: logging.hpp:290
genesis::utils::Logging::count_
static long count_
Definition: logging.hpp:599
LOG_MSG2
#define LOG_MSG2
Log an info message. See genesis::utils::LoggingLevel.
Definition: logging.hpp:109
genesis::utils::Logging::get
std::ostringstream & get(const std::string &file, const int line, const std::string &function, const LoggingLevel level)
Getter for the singleton instance of log, is called by the standard macros.
Definition: logging.cpp:279
genesis::utils::Logging::log_message_1
static void log_message_1(const std::string &msg)
Definition: logging.hpp:534
genesis::utils::Logging::ostreams_
static std::vector< std::ostream * > ostreams_
Definition: logging.hpp:609
genesis::utils::Logging::log_message
static void log_message(const std::string &msg)
Definition: logging.hpp:529
genesis::utils::Logging::clear
static void clear()
Remove all output streams, so that nothing is logged any more.
Definition: logging.cpp:170
genesis::utils::LoggingDetails::count
bool count
Include a counter of how many messages have been logged so far.
Definition: logging.hpp:287
genesis::utils::Logging::kInfo
@ kInfo
Infos, for example when a file was written. See LOG_INFO.
Definition: logging.hpp:416
genesis::utils::Logging::log_message_3
static void log_message_3(const std::string &msg)
Definition: logging.hpp:544
genesis::utils::Logging::kMessage1
@ kMessage1
Message with level 1. See LOG_MSG1.
Definition: logging.hpp:425
genesis::utils::LoggingDetails::level
bool level
Include the level (e.g. Info, Debug) of the message.
Definition: logging.hpp:324
genesis::utils::LoggingDetails::LoggingDetails
LoggingDetails()=default
genesis::utils::Logging::last_clock_
static clock_t last_clock_
Definition: logging.hpp:602
genesis::utils::Logging::kProgress
@ kProgress
Progess, used in long executing functions. See LOG_PROG.
Definition: logging.hpp:419
genesis::utils::LoggingDetails::file
bool file
Include the filename where the log message was generated.
Definition: logging.hpp:308
std.hpp
Provides some valuable additions to STD.
genesis::utils::logging_progress_value
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:179
genesis::utils::Logging::details
static LoggingDetails details
Settings for which information is included with each log message. See LoggingDetails for usage.
Definition: logging.hpp:488
LOG_DBG2
#define LOG_DBG2
Log a debug message. See genesis::utils::LoggingLevel.
Definition: logging.hpp:124
genesis::utils::LoggingDetails::function
bool function
Include the function name where the log message was generated.
Definition: logging.hpp:321
genesis::utils::Logging::kDebug4
@ kDebug4
Debugging message with indent level 4. See LOG_DBG4.
Definition: logging.hpp:449
genesis::utils::LoggingScopeLevel::LoggingScopeLevel
LoggingScopeLevel(Logging::LoggingLevel scope_level)
Definition: logging.hpp:624
genesis::utils::Logging::LoggingLevel
LoggingLevel
Levels of severity used for logging.
Definition: logging.hpp:405
genesis::utils::Logging::max_level
static LoggingLevel max_level()
Get the highest log level that is reported.
Definition: logging.hpp:491
genesis::utils::Logging::kDebug3
@ kDebug3
Debugging message with indent level 3. See LOG_DBG3.
Definition: logging.hpp:446
LOG_WARN
#define LOG_WARN
Log a warning. See genesis::utils::LoggingLevel.
Definition: logging.hpp:97
LOG_ERR
#define LOG_ERR
Log an error. See genesis::utils::LoggingLevel.
Definition: logging.hpp:94
genesis::utils::Logging::level_to_string
static std::string level_to_string(const LoggingLevel level)
Return a string representation of a log level.
Definition: logging.cpp:116
genesis::utils::Logging::level_
LoggingLevel level_
Definition: logging.hpp:589
LOG_MSG3
#define LOG_MSG3
Log an info message. See genesis::utils::LoggingLevel.
Definition: logging.hpp:112
genesis::utils::LoggingScopeLevel
Class that sets the Logging Level to a value von construction and set it back on destruction....
Definition: logging.hpp:621
genesis::utils::Logging::log_debug_2
static void log_debug_2(const std::string &msg)
Definition: logging.hpp:564
genesis::utils::Logging::line_
int line_
Definition: logging.hpp:587
genesis::utils::Logging::report_percentage
static int report_percentage()
Get the current percentage for reporting LOG_PROG messages.
Definition: logging.hpp:498
genesis
Container namespace for all symbols of genesis in order to keep them separate when used as a library.
Definition: placement/formats/edge_color.cpp:42
genesis::utils::Logging::kDebug2
@ kDebug2
Debugging message with indent level 2. See LOG_DBG2.
Definition: logging.hpp:443
genesis::utils::LoggingDetails::line
bool line
Include the line of the file where the log message was generated.
Definition: logging.hpp:314
genesis::utils::Logging::kMessage2
@ kMessage2
Message with level 2. See LOG_MSG2.
Definition: logging.hpp:428
genesis::utils::LoggingDetails::runtime
bool runtime
Include the current run time of the program in sec.
Definition: logging.hpp:296
genesis::utils::Logging::log_to_file
static void log_to_file(const std::string &fn)
Add an output file to which log messages are written.
Definition: logging.cpp:155
genesis::utils::Logging::log_to_stream
static void log_to_stream(std::ostream &os)
Add an output stream to which log messages are written.
Definition: logging.cpp:145
LOG_DBG1
#define LOG_DBG1
Log a debug message. See genesis::utils::LoggingLevel.
Definition: logging.hpp:121
genesis::utils::LoggingDetails::time
bool time
Include the current time.
Definition: logging.hpp:293
genesis::utils::Logging::Logging
Logging(const Logging &)
Definition: logging.hpp:458
genesis::utils::Logging::kMessage
@ kMessage
Basic message. See LOG_MSG.
Definition: logging.hpp:422
genesis::utils::Logging::max_level_
static LoggingLevel max_level_
Definition: logging.hpp:593
genesis::utils::Logging
Logging class with easy and fast usage.
Definition: logging.hpp:386
genesis::utils::Logging::log_info
static void log_info(const std::string &msg)
Definition: logging.hpp:524
genesis::utils::Logging::log_debug_1
static void log_debug_1(const std::string &msg)
Definition: logging.hpp:559
genesis::utils::Logging::kMessage3
@ kMessage3
Message with level 3. See LOG_MSG3.
Definition: logging.hpp:431
genesis::utils::Logging::Logging
Logging()
Definition: logging.hpp:452
genesis::utils::Logging::log_to_stdout
static void log_to_stdout()
Add stdout as output stream to which log messages are written.
Definition: logging.cpp:129
LOG_MSG4
#define LOG_MSG4
Log an info message. See genesis::utils::LoggingLevel.
Definition: logging.hpp:115
genesis::utils::Logging::kNone
@ kNone
Special messages that are always logged, e.g. program header.
Definition: logging.hpp:407
genesis::utils::Logging::kError
@ kError
Errors, usually non-recoverable. See LOG_ERR.
Definition: logging.hpp:410
genesis::utils::Logging::log_debug_4
static void log_debug_4(const std::string &msg)
Definition: logging.hpp:574
genesis::utils::Logging::file_
std::string file_
Definition: logging.hpp:586
genesis::utils::Logging::kDebug
@ kDebug
Basic debugging message. See LOG_DBG.
Definition: logging.hpp:437
genesis::utils::LoggingScopeLevel::~LoggingScopeLevel
~LoggingScopeLevel()
Definition: logging.hpp:630
LOG_DBG3
#define LOG_DBG3
Log a debug message. See genesis::utils::LoggingLevel.
Definition: logging.hpp:127
LOG_DBG
#define LOG_DBG
Log a debug message. See genesis::utils::LoggingLevel.
Definition: logging.hpp:118
genesis::utils::Logging::log_debug_3
static void log_debug_3(const std::string &msg)
Definition: logging.hpp:569
genesis::utils::Logging::log_error
static void log_error(const std::string &msg)
Definition: logging.hpp:514
genesis::utils::Logging::debug_indent
static std::string debug_indent
Indention string for Debug Levels 1-4.
Definition: logging.hpp:508
genesis::utils::Logging::buff_
std::ostringstream buff_
Definition: logging.hpp:585
LOG_DBG4
#define LOG_DBG4
Log a debug message. See genesis::utils::LoggingLevel.
Definition: logging.hpp:130
genesis::utils::Logging::operator=
Logging & operator=(const Logging &)=delete
genesis::utils::Logging::kDebug1
@ kDebug1
Debugging message with indent level 1 (e.g. for loops). See LOG_DBG1.
Definition: logging.hpp:440
genesis::utils::LoggingDetails::rundiff
bool rundiff
Include the run time difference to the last log message in sec.
Definition: logging.hpp:305
genesis::utils::Logging::log_debug
static void log_debug(const std::string &msg)
Definition: logging.hpp:554
genesis::utils::Logging::kMessage4
@ kMessage4
Message with level 4. See LOG_MSG4.
Definition: logging.hpp:434
genesis::utils::LoggingDetails::LoggingDetails
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:271
genesis::utils::Logging::details_
LoggingDetails details_
Definition: logging.hpp:590
genesis::utils::Logging::function_
std::string function_
Definition: logging.hpp:588