GraphLab: Distributed Graph-Parallel API  2.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
logger.cpp
1 /**
2  * Copyright (c) 2009 Carnegie Mellon University.
3  * All rights reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing,
12  * software distributed under the License is distributed on an "AS
13  * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
14  * express or implied. See the License for the specific language
15  * governing permissions and limitations under the License.
16  *
17  * For more about this software visit:
18  *
19  * http://www.graphlab.ml.cmu.edu
20  *
21  */
22 
23 
25 #include <cstdarg>
26 #include <cstdio>
27 #include <cstring>
28 #include <fstream>
29 #include <iostream>
30 #include <pthread.h>
31 
32 file_logger& global_logger() {
33  static file_logger l;
34  return l;
35 }
36 
37 
38 
39 
40 void streambuffdestructor(void* v){
41  logger_impl::streambuff_tls_entry* t =
42  reinterpret_cast<logger_impl::streambuff_tls_entry*>(v);
43  delete t;
44 }
45 
46 const char* messages[] = { "DEBUG: ",
47  "INFO: ",
48  "INFO: ",
49  "WARNING: ",
50  "ERROR: ",
51  "FATAL: "};
52 
53 
55  log_file = "";
56  log_to_console = true;
57  log_level = LOG_EMPH;
58  pthread_mutex_init(&mut, NULL);
59  pthread_key_create(&streambuffkey, streambuffdestructor);
60 }
61 
62 file_logger::~file_logger() {
63  if (fout.good()) {
64  fout.flush();
65  fout.close();
66  }
67 
68  pthread_mutex_destroy(&mut);
69 }
70 
71 bool file_logger::set_log_file(std::string file) {
72  // close the file if it is open
73  if (fout.good()) {
74  fout.flush();
75  fout.close();
76  log_file = "";
77  }
78  // if file is not an empty string, open the new file
79  if (file.length() > 0) {
80  fout.open(file.c_str());
81  if (fout.fail()) return false;
82  log_file = file;
83  }
84  return true;
85 }
86 
87 
88 
89 #define RESET 0
90 #define BRIGHT 1
91 #define DIM 2
92 #define UNDERLINE 3
93 #define BLINK 4
94 #define REVERSE 7
95 #define HIDDEN 8
96 
97 #define BLACK 0
98 #define RED 1
99 #define GREEN 2
100 #define YELLOW 3
101 #define BLUE 4
102 #define MAGENTA 5
103 #define CYAN 6
104 #define WHITE 7
105 
106 void textcolor(FILE* handle, int attr, int fg)
107 {
108  char command[13];
109  /* Command is the control command to the terminal */
110  sprintf(command, "%c[%d;%dm", 0x1B, attr, fg + 30);
111  fprintf(handle, "%s", command);
112 }
113 
114 void reset_color(FILE* handle)
115 {
116  char command[20];
117  /* Command is the control command to the terminal */
118  sprintf(command, "%c[0m", 0x1B);
119  fprintf(handle, "%s", command);
120 }
121 
122 
123 
124 void file_logger::_log(int lineloglevel,const char* file,const char* function,
125  int line,const char* fmt, va_list ap ){
126  // if the logger level fits
127  if (lineloglevel >= 0 && lineloglevel >= log_level){
128  // get just the filename. this line found on a forum on line.
129  // claims to be from google.
130  file = ((strrchr(file, '/') ? : file- 1) + 1);
131 
132  char str[1024];
133 
134  // write the actual header
135  int byteswritten = snprintf(str,1024, "%s%s(%s:%d): ",
136  messages[lineloglevel],file,function,line);
137  // write the actual logger
138 
139  byteswritten += vsnprintf(str + byteswritten,1024 - byteswritten,fmt,ap);
140 
141  str[byteswritten] = '\n';
142  str[byteswritten+1] = 0;
143  // write the output
144  if (fout.good()) {
145  pthread_mutex_lock(&mut);
146  fout << str;;
147  pthread_mutex_unlock(&mut);
148  }
149  if (log_to_console) {
150 #ifdef COLOROUTPUT
151  if (lineloglevel == LOG_FATAL) {
152  textcolor(stderr, BRIGHT, RED);
153  }
154  else if (lineloglevel == LOG_ERROR) {
155  textcolor(stderr, BRIGHT, RED);
156  }
157  else if (lineloglevel == LOG_WARNING) {
158  textcolor(stderr, BRIGHT, MAGENTA);
159  }
160  else if (lineloglevel == LOG_EMPH) {
161  textcolor(stderr, BRIGHT, GREEN);
162  }
163 #endif
164  std::cerr << str;;
165 #ifdef COLOROUTPUT
166  reset_color(stderr);
167 #endif
168  }
169  }
170 }
171 
172 
173 
174 void file_logger::_logbuf(int lineloglevel,const char* file,const char* function,
175  int line,const char* buf, int len) {
176  // if the logger level fits
177  if (lineloglevel >= 0 && lineloglevel <= 3 && lineloglevel >= log_level){
178  // get just the filename. this line found on a forum on line.
179  // claims to be from google.
180  file = ((strrchr(file, '/') ? : file- 1) + 1);
181 
182  // length of the 'head' of the string
183  size_t headerlen = snprintf(NULL,0,"%s%s(%s:%d): ",
184  messages[lineloglevel],file,function,line);
185 
186  if (headerlen> 2047) {
187  std::cerr << "Header length exceed buffer length!";
188  }
189  else {
190  char str[2048];
191  const char *newline="\n";
192  // write the actual header
193  int byteswritten = snprintf(str,2047,"%s%s(%s:%d): ",
194  messages[lineloglevel],file,function,line);
195  _lograw(lineloglevel,str, byteswritten);
196  _lograw(lineloglevel,buf, len);
197  _lograw(lineloglevel,newline, (int)strlen(newline));
198  }
199  }
200 }
201 
202 void file_logger::_lograw(int lineloglevel, const char* buf, int len) {
203  if (fout.good()) {
204  pthread_mutex_lock(&mut);
205  fout.write(buf,len);
206  pthread_mutex_unlock(&mut);
207  }
208  if (log_to_console) {
209 #ifdef COLOROUTPUT
210  if (lineloglevel == LOG_FATAL) {
211  textcolor(stderr, BRIGHT, RED);
212  }
213  else if (lineloglevel == LOG_ERROR) {
214  textcolor(stderr, BRIGHT, RED);
215  }
216  else if (lineloglevel == LOG_WARNING) {
217  textcolor(stderr, BRIGHT, MAGENTA);
218  }
219  else if (lineloglevel == LOG_DEBUG) {
220  textcolor(stderr, BRIGHT, YELLOW);
221  }
222  else if (lineloglevel == LOG_EMPH) {
223  textcolor(stderr, BRIGHT, GREEN);
224  }
225 #endif
226  std::cerr.write(buf,len);
227 #ifdef COLOROUTPUT
228  reset_color(stderr);
229 #endif
230  }
231 }
232 
233 file_logger& file_logger::start_stream(int lineloglevel,const char* file,
234  const char* function, int line, bool do_start) {
235  // get the stream buffer
236  logger_impl::streambuff_tls_entry* streambufentry =
237  reinterpret_cast<logger_impl::streambuff_tls_entry*>(
238  pthread_getspecific(streambuffkey));
239  // create the key if it doesn't exist
240  if (streambufentry == NULL) {
241  streambufentry = new logger_impl::streambuff_tls_entry;
242  pthread_setspecific(streambuffkey, streambufentry);
243  }
244  std::stringstream& streambuffer = streambufentry->streambuffer;
245  bool& streamactive = streambufentry->streamactive;
246 
247  // if do not start the stream, just quit
248  if (do_start == false) {
249  streamactive = false;
250  return *this;
251  }
252 
253  file = ((strrchr(file, '/') ? : file- 1) + 1);
254 
255  if (lineloglevel >= log_level){
256  if (streambuffer.str().length() == 0) {
257  streambuffer << messages[lineloglevel] << file
258  << "(" << function << ":" <<line<<"): ";
259  }
260  streamactive = true;
261  streamloglevel = lineloglevel;
262  }
263  else {
264  streamactive = false;
265  }
266  return *this;
267 }
268