A toolkit for working with phylogenetic data.
v0.24.0
logging.cpp
Go to the documentation of this file.
1 /*
2  Genesis - A toolkit for working with phylogenetic data.
3  Copyright (C) 2014-2019 Lucas Czech and HITS gGmbH
4 
5  This program is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  Contact:
19  Lucas Czech <lucas.czech@h-its.org>
20  Exelixis Lab, Heidelberg Institute for Theoretical Studies
21  Schloss-Wolfsbrunnenweg 35, D-69118 Heidelberg, Germany
22 */
23 
32 
33 #include <fstream>
34 #include <iomanip>
35 #include <iostream>
36 #include <stdexcept>
37 #include <string>
38 
39 #ifdef GENESIS_PTHREADS
40 # include <mutex>
41 #endif
42 
46 
47 namespace genesis {
48 namespace utils {
49 
50 // =============================================================================
51 // Settings
52 // =============================================================================
53 
54 #ifdef GENESIS_PTHREADS
55  static std::mutex log_mutex;
56 #endif
57 
58 // TODO use different init for log details depending on DEBUG
59 
60 // init static members
62  false, // count
63  false, // date
64  false, // time
65  false, // runtime
66  false, // rundiff
67  false, // file
68  false, // line
69  false, // function
70  true // level
71 };
73 long Logging::count_ = 0;
74 clock_t Logging::last_clock_ = 0;
75 std::vector<std::ostream*> Logging::ostreams_;
76 std::vector<std::ofstream*> Logging::fstreams_;
78 std::string Logging::debug_indent = " ";
79 
87 void Logging::max_level (const LoggingLevel level)
88 {
89  if (level > LOG_LEVEL_MAX) {
90  throw std::runtime_error(
91  "Logging max level set to " + std::to_string( level ) + ", but compile time max level is " +
92  std::to_string( LOG_LEVEL_MAX ) + ", so that everything above that will not be logged."
93  );
94  }
95  max_level_ = level;
96 }
97 
101 void Logging::report_percentage (const int percentage)
102 {
103  if (percentage <= 0) {
104  throw std::runtime_error( "Logging report percentage less than 1% not possible." );
105  }
106  if (percentage > 100) {
107  throw std::runtime_error( "Logging report percentage greater than 100% not meaningful." );
108  }
109  report_percentage_ = percentage;
110 }
111 
115 std::string Logging::level_to_string(const LoggingLevel level)
116 {
117  static const char* const buffer[] = {
118  "NONE", "ERR ", "WARN", "INFO", "PROG",
119  "MSG ", "MSG1", "MSG2", "MSG3", "MSG4",
120  "DBG ", "DBG1", "DBG2", "DBG3", "DBG4"
121  };
122  return buffer[level];
123 }
124 
129 {
130  // check whether stdout was already added.
131  for (std::ostream* os : ostreams_) {
132  if (os == &std::cout) {
133  return;
134  }
135  }
136 
137  // if not, add it as output stream.
138  ostreams_.push_back( &std::cout );
139 }
140 
144 void Logging::log_to_stream (std::ostream& os)
145 {
146  ostreams_.push_back( &os );
147 }
148 
154 void Logging::log_to_file( std::string const& filename )
155 {
156  std::ofstream* file_stream = new std::ofstream();
157  utils::file_output_stream( filename, *file_stream );
158  fstreams_.push_back( file_stream );
159 }
160 
165 {
166  ostreams_.clear();
167 
168  for( auto ofs : fstreams_ ) {
169  ofs->close();
170  delete ofs;
171  }
172  fstreams_.clear();
173 }
174 
175 // =============================================================================
176 // Destructor (does the actual work)
177 // =============================================================================
178 
184 {
185  // build the details for the log message into a buffer
186  clock_t now_clock = clock();
187  std::ostringstream det_buff;
188  det_buff.str("");
189  if (details_.count) {
190  det_buff.fill('0');
191  det_buff.width(4);
192  det_buff << count_ << " ";
193  }
194  if (details_.date) {
195  det_buff << current_date() << " ";
196  }
197  if (details_.time) {
198  det_buff << current_time() << " ";
199  }
200  if (details_.runtime) {
201  det_buff << std::fixed
202  << std::setprecision(6)
203  << double(now_clock) / CLOCKS_PER_SEC
204  << " ";
205  }
206  if (details_.rundiff) {
207  double val = 0.0;
208  if (last_clock_ > 0) {
209  val = (double) (now_clock - last_clock_) / CLOCKS_PER_SEC;
210  }
211  det_buff << std::fixed
212  << std::setprecision(6)
213  << val
214  << " ";
215  last_clock_ = now_clock;
216  }
217  if (details_.file) {
218  det_buff << file_ << (details_.line ? "" : " ");
219  }
220  if (details_.line) {
221  det_buff << ":" << line_ << " ";
222  }
223  if (details_.function) {
224  det_buff << "(" << function_ << ") ";
225  }
226  if (details_.level) {
227  det_buff << level_to_string(level_) << " ";
228  }
229 
230  // add spaces for nested debug levels
231  if (level_ > kDebug) {
232  for (int i = 0; i < level_ - kDebug; i++) {
233  det_buff << debug_indent;
234  }
235  }
236 
237  // make multi line log messages align to the length of the detail header,
238  // and trim trailing whitespace, as we only want one newline at the end
239  std::string msg = det_buff.str();
240  if (msg.length() > 0) {
241  msg += utils::replace_all(
242  buff_.str(), "\n", "\n" + std::string(msg.length(), ' ')
243  );
244  } else {
245  msg += buff_.str();
246  }
247  msg = utils::trim_right(msg);
248 
249  // output the message to every stream, thread safe!
250 # ifdef GENESIS_PTHREADS
251  log_mutex.lock();
252 # endif
253 
254  for (std::ostream* out : ostreams_) {
255  (*out) << msg << std::endl << std::flush;
256  }
257  for (std::ostream* out : fstreams_) {
258  (*out) << msg << std::endl << std::flush;
259  }
260 
261 # ifdef GENESIS_PTHREADS
262  log_mutex.unlock();
263 # endif
264 
265  // inc log message counter
266  count_++;
267 }
268 
269 // =============================================================================
270 // Singleton accessors
271 // =============================================================================
272 
278 std::ostringstream& Logging::get(
279  const std::string& file, const int line, const std::string& function,
280  const LoggingLevel level
281 )
282 {
283  return get(file, line, function, level, details);
284 }
285 
293 std::ostringstream& Logging::get(
294  const std::string& file, const int line, const std::string& function,
295  const LoggingLevel level, const LoggingDetails dets
296 )
297 {
298  // save the information given when called from the macros
299  file_ = file;
300  line_ = line;
301  function_ = function;
302  level_ = level;
303  details_ = dets;
304  buff_.str("");
305  return buff_;
306 }
307 
308 } // namespace utils
309 } // namespace genesis
static std::string debug_indent
Indention string for Debug Levels 1-4.
Definition: logging.hpp:507
static std::mutex log_mutex
Definition: logging.cpp:55
static int report_percentage_
Definition: logging.hpp:595
std::string current_date()
Returns the current date as a string in the format "2014-12-31".
Definition: date_time.cpp:68
static LoggingDetails details
Settings for which information is included with each log message. See LoggingDetails for usage...
Definition: logging.hpp:487
void file_output_stream(std::string const &filename, std::ofstream &out_stream, std::ios_base::openmode mode=std::ios_base::out)
Helper function to obtain an output stream to a file.
static std::vector< std::ostream * > ostreams_
Definition: logging.hpp:605
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:278
std::ostringstream buff_
Definition: logging.hpp:584
bool count
Include a counter of how many messages have been logged so far.
Definition: logging.hpp:286
LoggingLevel level_
Definition: logging.hpp:588
static clock_t last_clock_
Definition: logging.hpp:601
static std::string level_to_string(const LoggingLevel level)
Return a string representation of a log level.
Definition: logging.cpp:115
Container namespace for all symbols of genesis in order to keep them separate when used as a library...
~Logging()
Destructor that is invoked at the end of each log line and does the actual output.
Definition: logging.cpp:183
static LoggingLevel max_level()
Get the highest log level that is reported.
Definition: logging.hpp:490
static std::vector< std::ofstream * > fstreams_
Definition: logging.hpp:606
std::string replace_all(std::string const &text, std::string const &search, std::string const &replace)
Return a copy of a string, where all occurrences of a search string are replaced by a replace string...
Definition: string.cpp:322
bool line
Include the line of the file where the log message was generated.
Definition: logging.hpp:313
#define LOG_LEVEL_MAX
Static maximal logging level.
Definition: logging.hpp:65
bool function
Include the function name where the log message was generated.
Definition: logging.hpp:320
std::string current_time()
Returns the current time as a string in the format "13:37:42".
Definition: date_time.cpp:88
std::string trim_right(std::string const &s, std::string const &delimiters)
Return a copy of the input string, with left trimmed white spaces.
Definition: string.cpp:370
bool rundiff
Include the run time difference to the last log message in sec.
Definition: logging.hpp:304
static void log_to_file(const std::string &fn)
Add an output file to which log messages are written.
Definition: logging.cpp:154
Provides some commonly used string utility functions.
static int report_percentage()
Get the current percentage for reporting LOG_PROG messages.
Definition: logging.hpp:497
LoggingLevel
Levels of severity used for logging.
Definition: logging.hpp:404
Provides functions for date and time access.
Provides easy and fast logging functionality.
static void log_to_stream(std::ostream &os)
Add an output stream to which log messages are written.
Definition: logging.cpp:144
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
static void log_to_stdout()
Add stdout as output stream to which log messages are written.
Definition: logging.cpp:128
bool runtime
Include the current run time of the program in sec.
Definition: logging.hpp:295
std::shared_ptr< BaseOutputTarget > to_string(std::string &target_string)
Obtain an output target for writing to a string.
LoggingDetails details_
Definition: logging.hpp:589
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
Basic debugging message. See LOG_DBG.
Definition: logging.hpp:436
static void clear()
Remove all output streams, so that nothing is logged any more.
Definition: logging.cpp:164
static LoggingLevel max_level_
Definition: logging.hpp:592
bool time
Include the current time.
Definition: logging.hpp:292