GraphChi 0.1

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

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 {
126 struct streambuff_tls_entry {
127 std::stringstream streambuffer;
128 bool streamactive;
129 };
130 }
131
132
137 class file_logger{
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
160 bool get_log_to_console() {
161 return log_to_console;
162 }
163
165 int get_log_level() {
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){
240 logger_impl::streambuff_tls_entry* t =
241 reinterpret_cast<logger_impl::streambuff_tls_entry*>(v);
242 delete t;
243 }
244
245
246
250 file_logger() {
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>
518 struct log_stream_dispatch {};
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