GraphChi  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Macros
logger.hpp
Go to the documentation of this file.
1 
49 #ifndef GRAPHCHI_LOG_LOG_HPP
50 #define GRAPHCHI_LOG_LOG_HPP
51 #include <fstream>
52 #include <sstream>
53 #include <cstdlib>
54 #include <iostream>
55 #include <cassert>
56 #include <cstring>
57 #include <cstdarg>
58 #include <pthread.h>
71 #define LOG_NONE 5
72 #define LOG_FATAL 4
73 #define LOG_ERROR 3
74 #define LOG_WARNING 2
75 #define LOG_INFO 1
76 #define LOG_DEBUG 0
77 
85 #ifndef OUTPUTLEVEL
86 #define OUTPUTLEVEL LOG_DEBUG
87 #endif
88 
89 #define COLOROUTPUT
90 
91 
100 #if OUTPUTLEVEL == LOG_NONE
101 // totally disable logging
102 #define logger(lvl,fmt,...)
103 #define logbuf(lvl,fmt,...)
104 #define logstream
105 #else
106 
107 #define logger(lvl,fmt,...) \
108  (log_dispatch<(lvl >= OUTPUTLEVEL)>::exec(lvl,__FILE__, __func__ ,__LINE__,fmt,##__VA_ARGS__))
109 
110 
111 #define logbuf(lvl,buf,len) \
112  (log_dispatch<(lvl >= OUTPUTLEVEL)>::exec(lvl,__FILE__, \
113  __func__ ,__LINE__,buf,len))
114 
115 #define logstream(lvl) \
116  (log_stream_dispatch<(lvl >= OUTPUTLEVEL)>::exec(lvl,__FILE__, __func__ ,__LINE__) )
117 #endif
118 
119 static const char* messages[] = { "DEBUG: ",
120  "INFO: ",
121  "WARNING: ",
122  "ERROR: ",
123  "FATAL: "};
124 
125 namespace logger_impl {
127  std::stringstream streambuffer;
128  bool streamactive;
129 };
130 }
131 
132 
138  public:
139 
140 
141 
149 
150  void set_log_to_console(bool consolelog) {
151  log_to_console = consolelog;
152  }
153 
155  std::string get_log_file(void) {
156  return log_file;
157  }
158 
161  return log_to_console;
162  }
163 
166  return log_level;
167  }
168 
169 
170  template <typename T>
171  file_logger& operator<<(T a) {
172  // get the stream buffer
173  logger_impl::streambuff_tls_entry* streambufentry = reinterpret_cast<logger_impl::streambuff_tls_entry*>(
174  pthread_getspecific(streambuffkey));
175  if (streambufentry != NULL) {
176  std::stringstream& streambuffer = streambufentry->streambuffer;
177  bool& streamactive = streambufentry->streamactive;
178 
179  if (streamactive) streambuffer << a;
180  }
181  return *this;
182  }
183 
184  file_logger& operator<<(const char* a) {
185  // get the stream buffer
186  logger_impl::streambuff_tls_entry* streambufentry = reinterpret_cast<logger_impl::streambuff_tls_entry*>(
187  pthread_getspecific(streambuffkey));
188  if (streambufentry != NULL) {
189  std::stringstream& streambuffer = streambufentry->streambuffer;
190  bool& streamactive = streambufentry->streamactive;
191 
192  if (streamactive) {
193  streambuffer << a;
194  if (a[strlen(a)-1] == '\n') {
195  stream_flush();
196  }
197  }
198  }
199  return *this;
200  }
201 
202  file_logger& operator<<(std::ostream& (*f)(std::ostream&)){
203  // get the stream buffer
204  logger_impl::streambuff_tls_entry* streambufentry = reinterpret_cast<logger_impl::streambuff_tls_entry*>(
205  pthread_getspecific(streambuffkey));
206  if (streambufentry != NULL) {
207  std::stringstream& streambuffer = streambufentry->streambuffer;
208  bool& streamactive = streambufentry->streamactive;
209 
210  typedef std::ostream& (*endltype)(std::ostream&);
211  if (streamactive) {
212  if (endltype(f) == endltype(std::endl)) {
213  streambuffer << "\n";
214  stream_flush();
215  if(streamloglevel == LOG_FATAL) {
216  throw "log fatal";
217  // exit(EXIT_FAILURE);
218  }
219  }
220  }
221  }
222  return *this;
223  }
224 
225 
226 
229  void set_log_level(int new_log_level) {
230  log_level = new_log_level;
231  }
232 
233 
234 
235 
236 
237 
238 
239  static void streambuffdestructor(void* v){
241  reinterpret_cast<logger_impl::streambuff_tls_entry*>(v);
242  delete t;
243  }
244 
245 
246 
251  log_file = "";
252  log_to_console = true;
253  log_level = LOG_DEBUG;
254  pthread_mutex_init(&mut, NULL);
255  pthread_key_create(&streambuffkey, streambuffdestructor);
256  }
257 
258  ~file_logger() {
259  if (fout.good()) {
260  fout.flush();
261  fout.close();
262  }
263 
264  pthread_mutex_destroy(&mut);
265  }
266 
267  bool set_log_file(std::string file) {
268  // close the file if it is open
269  if (fout.good()) {
270  fout.flush();
271  fout.close();
272  log_file = "";
273  }
274  // if file is not an empty string, open the new file
275  if (file.length() > 0) {
276  fout.open(file.c_str());
277  if (fout.fail()) return false;
278  log_file = file;
279  }
280  return true;
281  }
282 
283 
284 
285 #define RESET 0
286 #define BRIGHT 1
287 #define DIM 2
288 #define UNDERLINE 3
289 #define BLINK 4
290 #define REVERSE 7
291 #define HIDDEN 8
292 
293 #define BLACK 0
294 #define RED 1
295 #define GREEN 2
296 #define YELLOW 3
297 #define BLUE 4
298 #define MAGENTA 5
299 #define CYAN 6
300 #define WHITE 7
301 
302  void textcolor(FILE* handle, int attr, int fg)
303  {
304  char command[13];
305  /* Command is the control command to the terminal */
306  sprintf(command, "%c[%d;%dm", 0x1B, attr, fg + 30);
307  fprintf(handle, "%s", command);
308  }
309 
310  void reset_color(FILE* handle)
311  {
312  char command[20];
313  /* Command is the control command to the terminal */
314  sprintf(command, "%c[0m", 0x1B);
315  fprintf(handle, "%s", command);
316  }
317 
318 
319 
320  void _log(int lineloglevel,const char* file,const char* function,
321  int line,const char* fmt, va_list ap ){
322  // if the logger level fits
323  if (lineloglevel >= 0 && lineloglevel <= 3 && lineloglevel >= log_level){
324  // get just the filename. this line found on a forum on line.
325  // claims to be from google.
326  file = ((strrchr(file, '/') ? : file- 1) + 1);
327 
328  char str[1024];
329 
330  // write the actual header
331  int byteswritten = snprintf(str,1024, "%s%s(%s:%d): ",
332  messages[lineloglevel],file,function,line);
333  // write the actual logger
334 
335  byteswritten += vsnprintf(str + byteswritten,1024 - byteswritten,fmt,ap);
336 
337  str[byteswritten] = '\n';
338  str[byteswritten+1] = 0;
339  // write the output
340  if (fout.good()) {
341  pthread_mutex_lock(&mut);
342  fout << str;;
343  pthread_mutex_unlock(&mut);
344  }
345  if (log_to_console) {
346 #ifdef COLOROUTPUT
347  if (lineloglevel == LOG_FATAL) {
348  textcolor(stderr, BRIGHT, RED);
349  }
350  else if (lineloglevel == LOG_ERROR) {
351  textcolor(stderr, BRIGHT, RED);
352  }
353  else if (lineloglevel == LOG_WARNING) {
354  textcolor(stderr, BRIGHT, GREEN);
355  }
356 #endif
357  std::cerr << str;;
358 #ifdef COLOROUTPUT
359  reset_color(stderr);
360 #endif
361  }
362  }
363  }
364 
365 
366 
367  void _logbuf(int lineloglevel,const char* file,const char* function,
368  int line,const char* buf, int len) {
369  // if the logger level fits
370  if (lineloglevel >= 0 && lineloglevel <= 3 && lineloglevel >= log_level){
371  // get just the filename. this line found on a forum on line.
372  // claims to be from google.
373  file = ((strrchr(file, '/') ? : file- 1) + 1);
374 
375  // length of the 'head' of the string
376  size_t headerlen = snprintf(NULL,0,"%s%s(%s:%d): ",
377  messages[lineloglevel],file,function,line);
378 
379  if (headerlen> 2047) {
380  std::cerr << "Header length exceed buffer length!";
381  }
382  else {
383  char str[2048];
384  const char *newline="\n";
385  // write the actual header
386  int byteswritten = snprintf(str,2047,"%s%s(%s:%d): ",
387  messages[lineloglevel],file,function,line);
388  _lograw(lineloglevel,str, byteswritten);
389  _lograw(lineloglevel,buf, len);
390  _lograw(lineloglevel,newline, (int)strlen(newline));
391  }
392  }
393  }
394 
395  void _lograw(int lineloglevel, const char* buf, int len) {
396  if (fout.good()) {
397  pthread_mutex_lock(&mut);
398  fout.write(buf,len);
399  pthread_mutex_unlock(&mut);
400  }
401  if (log_to_console) {
402 #ifdef COLOROUTPUT
403  if (lineloglevel == LOG_FATAL) {
404  textcolor(stderr, BRIGHT, RED);
405  }
406  else if (lineloglevel == LOG_ERROR) {
407  textcolor(stderr, BRIGHT, RED);
408  }
409  else if (lineloglevel == LOG_WARNING) {
410  textcolor(stderr, BRIGHT, GREEN);
411  }
412  else if (lineloglevel == LOG_DEBUG) {
413  textcolor(stderr, BRIGHT, YELLOW);
414  }
415 
416 #endif
417  std::cerr.write(buf,len);
418 #ifdef COLOROUTPUT
419  reset_color(stderr);
420 #endif
421  }
422  }
423 
424  file_logger& start_stream(int lineloglevel,const char* file,const char* function, int line) {
425  // get the stream buffer
426  logger_impl::streambuff_tls_entry* streambufentry = reinterpret_cast<logger_impl::streambuff_tls_entry*>(
427  pthread_getspecific(streambuffkey));
428  // create the key if it doesn't exist
429  if (streambufentry == NULL) {
430  streambufentry = new logger_impl::streambuff_tls_entry;
431  pthread_setspecific(streambuffkey, streambufentry);
432  }
433  std::stringstream& streambuffer = streambufentry->streambuffer;
434  bool& streamactive = streambufentry->streamactive;
435 
436  file = ((strrchr(file, '/') ? : file- 1) + 1);
437 
438  if (lineloglevel >= log_level){
439  if (streambuffer.str().length() == 0) {
440  streambuffer << messages[lineloglevel] << file
441  << "(" << function << ":" <<line<<"): ";
442  }
443  streamactive = true;
444  streamloglevel = lineloglevel;
445  }
446  else {
447  streamactive = false;
448  }
449  return *this;
450  }
451 
452 
453 
454  void stream_flush() {
455  // get the stream buffer
456  logger_impl::streambuff_tls_entry* streambufentry = reinterpret_cast<logger_impl::streambuff_tls_entry*>(
457  pthread_getspecific(streambuffkey));
458  if (streambufentry != NULL) {
459  std::stringstream& streambuffer = streambufentry->streambuffer;
460 
461  streambuffer.flush();
462  _lograw(streamloglevel,
463  streambuffer.str().c_str(),
464  (int)(streambuffer.str().length()));
465  streambuffer.str("");
466  }
467  }
468  private:
469  std::ofstream fout;
470  std::string log_file;
471 
472  pthread_key_t streambuffkey;
473 
474  int streamloglevel;
475  pthread_mutex_t mut;
476 
477  bool log_to_console;
478  int log_level;
479 
480 };
481 
482 
483 static file_logger& global_logger();
484 
488 template <bool dostuff>
489 struct log_dispatch {};
490 
491 template <>
492 struct log_dispatch<true> {
493  inline static void exec(int loglevel,const char* file,const char* function,
494  int line,const char* fmt, ... ) {
495  va_list argp;
496  va_start(argp, fmt);
497  global_logger()._log(loglevel, file, function, line, fmt, argp);
498  va_end(argp);
499  }
500 };
501 
502 template <>
503 struct log_dispatch<false> {
504  inline static void exec(int loglevel,const char* file,const char* function,
505  int line,const char* fmt, ... ) {}
506 };
507 
508 
509 struct null_stream {
510  template<typename T>
511  inline null_stream operator<<(T t) { return null_stream(); }
512  inline null_stream operator<<(const char* a) { return null_stream(); }
513  inline null_stream operator<<(std::ostream& (*f)(std::ostream&)) { return null_stream(); }
514 };
515 
516 
517 template <bool dostuff>
519 
520 template <>
521 struct log_stream_dispatch<true> {
522  inline static file_logger& exec(int lineloglevel,const char* file,const char* function, int line) {
523  return global_logger().start_stream(lineloglevel, file, function, line);
524  }
525 };
526 
527 template <>
528 struct log_stream_dispatch<false> {
529  inline static null_stream exec(int lineloglevel,const char* file,const char* function, int line) {
530  return null_stream();
531  }
532 };
533 
534 void textcolor(FILE* handle, int attr, int fg);
535 void reset_color(FILE* handle);
536 
537 static file_logger& global_logger() {
538  static file_logger l;
539  return l;
540 }
541 
542 
543 #endif
544