A toolkit for working with phylogenetic data.
v0.19.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
logging.cpp
Go to the documentation of this file.
1 /*
2  Genesis - A toolkit for working with phylogenetic data.
3  Copyright (C) 2014-2017 Lucas Czech
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
61 LoggingDetails Logging::details = {
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_;
77 std::string Logging::debug_indent = " ";
78 
86 void Logging::max_level (const LoggingLevel level)
87 {
88  if (level > LOG_LEVEL_MAX) {
89  LOG_WARN << "Logging max level set to " << level << ", but compile "
90  << "time max level is " << LOG_LEVEL_MAX << ", so that "
91  << "everything above that will not be logged.";
92  }
93  max_level_ = level;
94 }
95 
99 void Logging::report_percentage (const int percentage)
100 {
101  if (percentage <= 0) {
102  LOG_WARN << "Logging report percentage less than 1% not possible.";
103  report_percentage_ = 1;
104  return;
105  }
106  if (percentage > 100) {
107  LOG_WARN << "Logging report percentage greater than 100% not meaningful.";
108  report_percentage_ = 100;
109  return;
110  }
111  report_percentage_ = percentage;
112 }
113 
117 std::string Logging::level_to_string(const LoggingLevel level)
118 {
119  static const char* const buffer[] = {
120  "NONE", "ERR ", "WARN", "INFO", "PROG", "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  // TODO the log file stream is never deleted. this is not a big leak,
157  // as commonly only one file is used for logging, but still is a smell.
158  // use uniqute stored statically in the log class instead!
159 
160  std::ofstream* file_stream = new std::ofstream();
161  utils::file_output_stream( filename, *file_stream );
162  ostreams_.push_back( file_stream );
163 }
164 
165 // =============================================================================
166 // Destructor (does the actual work)
167 // =============================================================================
168 
174 {
175  // build the details for the log message into a buffer
176  clock_t now_clock = clock();
177  std::ostringstream det_buff;
178  det_buff.str("");
179  if (details_.count) {
180  det_buff.fill('0');
181  det_buff.width(4);
182  det_buff << count_ << " ";
183  }
184  if (details_.date) {
185  det_buff << current_date() << " ";
186  }
187  if (details_.time) {
188  det_buff << current_time() << " ";
189  }
190  if (details_.runtime) {
191  det_buff << std::fixed
192  << std::setprecision(6)
193  << double(now_clock) / CLOCKS_PER_SEC
194  << " ";
195  }
196  if (details_.rundiff) {
197  double val = 0.0;
198  if (last_clock_ > 0) {
199  val = (double) (now_clock - last_clock_) / CLOCKS_PER_SEC;
200  }
201  det_buff << std::fixed
202  << std::setprecision(6)
203  << val
204  << " ";
205  last_clock_ = now_clock;
206  }
207  if (details_.file) {
208  det_buff << file_ << (details_.line ? "" : " ");
209  }
210  if (details_.line) {
211  det_buff << ":" << line_ << " ";
212  }
213  if (details_.function) {
214  det_buff << "(" << function_ << ") ";
215  }
216  if (details_.level) {
217  det_buff << level_to_string(level_) << " ";
218  }
219 
220  // add spaces for nested debug levels
221  if (level_ > kDebug) {
222  for (int i = 0; i < level_ - kDebug; i++) {
223  det_buff << debug_indent;
224  }
225  }
226 
227  // make multi line log messages align to the length of the detail header,
228  // and trim trailing whitespace, as we only want one newline at the end
229  std::string msg = det_buff.str();
230  if (msg.length() > 0) {
231  msg += utils::replace_all(
232  buff_.str(), "\n", "\n" + std::string(msg.length(), ' ')
233  );
234  } else {
235  msg += buff_.str();
236  }
237  msg = utils::trim_right(msg);
238 
239  // output the message to every stream, thread safe!
240 # ifdef GENESIS_PTHREADS
241  log_mutex.lock();
242 # endif
243  for (std::ostream* out : ostreams_) {
244  (*out) << msg << std::endl << std::flush;
245  }
246 # ifdef GENESIS_PTHREADS
247  log_mutex.unlock();
248 # endif
249 
250  // inc log message counter
251  count_++;
252 }
253 
254 // =============================================================================
255 // Singleton accessors
256 // =============================================================================
257 
263 std::ostringstream& Logging::get(
264  const std::string& file, const int line, const std::string& function,
265  const LoggingLevel level
266 )
267 {
268  return get(file, line, function, level, details);
269 }
270 
278 std::ostringstream& Logging::get(
279  const std::string& file, const int line, const std::string& function,
280  const LoggingLevel level, const LoggingDetails dets
281 )
282 {
283  // save the information given when called from the macros
284  file_ = file;
285  line_ = line;
286  function_ = function;
287  level_ = level;
288  details_ = dets;
289  buff_.str("");
290  return buff_;
291 }
292 
293 } // namespace utils
294 } // namespace genesis
static std::string debug_indent
Indention string for Debug Levels 1-4.
Definition: logging.hpp:457
static int report_percentage_
Definition: logging.hpp:520
std::string current_date()
Returns the current date as a string in the format "2014-12-31".
Definition: date_time.cpp:39
static LoggingDetails details
Settings for which information is included with each log message. See LoggingDetails for usage...
Definition: logging.hpp:437
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:529
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:263
std::ostringstream buff_
Definition: logging.hpp:509
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:287
#define LOG_WARN
Log a warning. See genesis::utils::LoggingLevel.
Definition: logging.hpp:95
bool count
Include a counter of how many messages have been logged so far.
Definition: logging.hpp:252
LoggingLevel level_
Definition: logging.hpp:513
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:239
static clock_t last_clock_
Definition: logging.hpp:526
static std::string level_to_string(const LoggingLevel level)
Return a string representation of a log level.
Definition: logging.cpp:117
~Logging()
Destructor that is invoked at the end of each log line and does the actual output.
Definition: logging.cpp:173
static LoggingLevel max_level()
Get the highest log level that is reported.
Definition: logging.hpp:440
bool line
Include the line of the file where the log message was generated.
Definition: logging.hpp:279
#define LOG_LEVEL_MAX
Static maximal logging level.
Definition: logging.hpp:64
bool function
Include the function name where the log message was generated.
Definition: logging.hpp:286
std::string current_time()
Returns the current time as a string in the format "13:37:42".
Definition: date_time.cpp:51
bool rundiff
Include the run time difference to the last log message in sec.
Definition: logging.hpp:270
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:447
LoggingLevel
Levels of severity used for logging.
Definition: logging.hpp:370
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:255
bool file
Include the filename where the log message was generated.
Definition: logging.hpp:273
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:261
LoggingDetails details_
Definition: logging.hpp:514
std::string function_
Definition: logging.hpp:512
POD stuct containing the settings for which information is included with each logging message...
Definition: logging.hpp:250
bool level
Include the level (e.g. Info, Debug) of the message.
Definition: logging.hpp:289
Basic debugging message. See LOG_DBG.
Definition: logging.hpp:387
static LoggingLevel max_level_
Definition: logging.hpp:517
bool time
Include the current time.
Definition: logging.hpp:258