00001 /*!@file Util/log.C Interface to syslog */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00005 // University of Southern California (USC) and the iLab at USC. // 00006 // See http://iLab.usc.edu for information about this project. // 00007 // //////////////////////////////////////////////////////////////////// // 00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00010 // in Visual Environments, and Applications'' by Christof Koch and // 00011 // Laurent Itti, California Institute of Technology, 2001 (patent // 00012 // pending; application number 09/912,225 filed July 23, 2001; see // 00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00014 // //////////////////////////////////////////////////////////////////// // 00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00016 // // 00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00018 // redistribute it and/or modify it under the terms of the GNU General // 00019 // Public License as published by the Free Software Foundation; either // 00020 // version 2 of the License, or (at your option) any later version. // 00021 // // 00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00025 // PURPOSE. See the GNU General Public License for more details. // 00026 // // 00027 // You should have received a copy of the GNU General Public License // 00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00030 // Boston, MA 02111-1307 USA. // 00031 // //////////////////////////////////////////////////////////////////// // 00032 // 00033 // Primary maintainer for this file: Laurent Itti <itti@usc.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Util/log.C $ 00035 // $Id: log.C 11908 2009-11-01 19:34:27Z lior $ 00036 // 00037 00038 #include "Util/log.H" 00039 00040 #include "rutz/compat_snprintf.h" 00041 #include "rutz/demangle.h" 00042 #include "rutz/error_context.h" 00043 00044 #include <cerrno> 00045 #include <cstdarg> 00046 #include <cstdlib> 00047 #include <cstdio> 00048 #include <stdexcept> // for std::runtime_error 00049 #include <sys/types.h> 00050 #include <unistd.h> 00051 #include <cstring> 00052 00053 //! total max size of a log entry 00054 #define LBS 1024 00055 00056 int LOG_FLAGS = (LFATAL_THROWS 00057 | LFATAL_PRINTS_ABORT 00058 | LFATAL_XTRA_NOISY 00059 | LOG_FULLTRACE); 00060 int MYLOGVERB = LOG_INFO; 00061 00062 lfatal_exception::lfatal_exception() throw() {} 00063 00064 lfatal_exception::~lfatal_exception() throw() {} 00065 00066 const char* MYLOGPREFIX = 0; 00067 00068 namespace 00069 { 00070 /// Concrete type thrown from LFATAL 00071 class real_lfatal_exception : public lfatal_exception 00072 { 00073 public: 00074 real_lfatal_exception(const std::string& msg) 00075 : 00076 lfatal_exception(), 00077 m_msg(msg) 00078 {} 00079 00080 virtual ~real_lfatal_exception() throw() {} 00081 00082 virtual const char* what() const throw() 00083 { 00084 return m_msg.c_str(); 00085 } 00086 00087 std::string m_msg; 00088 }; 00089 00090 /// A little helper function for sendlog(). 00091 /** This avoids duplicating the flag-parsing logic between our two 00092 versions of sendlog(). */ 00093 void sendlog_aux(const char* raw_msg, const int level, const int flags) 00094 { 00095 const char* msg = raw_msg; 00096 00097 std::string full_msg; 00098 00099 if (level == LOG_CRIT) 00100 { 00101 // if we have an error context message, prepend it to the 00102 // actual error message: 00103 00104 full_msg = raw_msg; 00105 rutz::error_context::current().prepend_to(full_msg); 00106 msg = full_msg.c_str(); 00107 } 00108 00109 if (flags & LOG_FULLTRACE) 00110 { 00111 // if this was an LFATAL and we're going to throw an exception 00112 // object containing the logmsg, then don't print it to 00113 // stderr/syslog unless we also have LFATAL_XTRA_NOISY: 00114 const bool skip_printing = 00115 (level == LOG_CRIT 00116 && (flags & LFATAL_THROWS) 00117 && !(flags & LFATAL_XTRA_NOISY)); 00118 00119 if (!skip_printing) 00120 { 00121 if (MYLOGPREFIX != 0) 00122 fprintf(stderr, "[%s] %s\n", MYLOGPREFIX, msg); 00123 else 00124 fprintf(stderr, "%s\n", msg); 00125 fflush(stderr); 00126 } 00127 } 00128 else 00129 syslog(level, "%s", msg); 00130 00131 // special handling if this was an LFATAL: 00132 if (level == LOG_CRIT) 00133 { 00134 if (flags & LFATAL_PRINTS_ABORT) 00135 fprintf(stderr, "-- ABORT.\n"); 00136 00137 if (flags & LFATAL_THROWS) 00138 throw real_lfatal_exception(full_msg); 00139 00140 abort(); 00141 } 00142 } 00143 } 00144 00145 // ###################################################################### 00146 // for snprintf and vsnprintf, you need to define _GNU_SOURCE in your CFLAGS. 00147 // define fake snprintf and vsnprintf if they do not exist in the system: 00148 #ifndef _GNU_SOURCE 00149 int snprintf(char *str, size_t n, const char *format, ...) 00150 { va_list a; va_start(a, format); vsprintf(str, format, a); va_end(a); 00151 return strlen(str); } 00152 int vsnprintf(char *str, size_t n, const char *format, va_list ap) 00153 { vsprintf(str, format, ap); return strlen(str); } 00154 #endif 00155 00156 #ifdef __GNUC__ 00157 // ###################################################################### 00158 //! Send a log. GNUC, thread-safe version 00159 void sendlog(const int lev, const int line, const char *file, 00160 const char *func, const int idval, const bool useid, 00161 const bool usep, const char *msg, ...) 00162 { 00163 if (lev > MYLOGVERB) return; // ignore if insuffic priority 00164 00165 va_list args; int len, len2; va_start(args, msg); char logbuf[LBS]; 00166 00167 // remove filename extension, if any, to get class name: 00168 char fil[strlen(file) + 1]; strcpy(fil, file); 00169 for (int i = strlen(fil)-1; i >= 0; i--) 00170 if (fil[i] == '.') { fil[i] = '\0'; break; } 00171 00172 char* fil2 = fil; 00173 00174 // also skip any subdirectories that may be in the file name, but if 00175 // the first character is a '[' then it's not a filename but a 00176 // descriptiveName() from e.g. CLINFO(): 00177 if (fil2[0] != '[') 00178 { 00179 fil2 = strrchr(fil, '/'); 00180 if (fil2) ++fil2; // get to the next char after the last / 00181 else fil2 = fil; // there was no /, use whole file name 00182 } 00183 00184 // print first chunk: file and function 00185 len = snprintf(logbuf, LBS, "%s::%s", fil2, func); 00186 if (len == -1 || len >= LBS-1) goto done; // buffer is already full... 00187 00188 #ifdef DEBUG 00189 // if debug mode, add line number: 00190 len2 = snprintf(&(logbuf[len]), LBS-len, "(%d)", line); 00191 if (len2 == -1 || len2+len >= LBS-1) goto done; else len += len2; 00192 #endif 00193 logbuf[len++] = ':'; if (len >= LBS-1) goto done; 00194 00195 // if we use ID-logging, print the ID now: 00196 if (useid) { 00197 len2 = snprintf(&(logbuf[len]), LBS-len, "(%d)", idval); 00198 if (len2 == -1 || len2+len >= LBS-1) goto done; else len += len2; 00199 } 00200 00201 // if msg starts with opening bracket, do not add a space: 00202 if (msg[0] != '(' && msg[0] != '[' && msg[0] != '{') 00203 { logbuf[len++] = ' '; if (len >= LBS-1) goto done; } 00204 00205 // print the actual message: 00206 len2 = vsnprintf(&(logbuf[len]), LBS-len, msg, args); 00207 if (len2 == -1 || len2+len >= LBS-1) goto done; else len += len2; 00208 00209 // if doing P-logging, add errno in clear: 00210 if (usep) 00211 snprintf( &(logbuf[len]), LBS-len, " (errno=%d, %s)", 00212 errno, strerror(errno)); 00213 00214 // ready to send to syslog: 00215 done: 00216 va_end(args); 00217 00218 logbuf[LBS - 1] = '\0'; 00219 00220 sendlog_aux(logbuf, lev, LOG_FLAGS); 00221 } 00222 00223 // ###################################################################### 00224 void showmemory(const int lev, const int line, const char *file, 00225 const char *func, const int idval, const bool useid, 00226 const bool usep, const char *msg, ...) 00227 { 00228 if (lev > MYLOGVERB) return; // ignore if insufficient priority 00229 00230 // crunch the var args: 00231 va_list args; va_start(args, msg); char logbuf[LBS + 100]; 00232 vsnprintf(logbuf, LBS, msg, args); va_end(args); 00233 00234 // get the memory usage: 00235 int pid = int(getpid()); 00236 char xx[100]; snprintf(xx, 100, "/proc/%d/status", pid); 00237 FILE *f = fopen(xx, "r"); 00238 if (f == NULL) { LERROR("Cannot open %s -- IGNORED", xx); return; } 00239 while(fgets(xx, 100, f)) 00240 if (strncasecmp(xx, "VmSize", 6) == 0) 00241 { 00242 xx[strlen(xx) - 1] = '\0'; // eliminate trailing LF 00243 xx[7] = ' '; // replace TAB by a space 00244 strcat(logbuf, " ["); 00245 strncat(logbuf, xx, 97); 00246 strcat(logbuf, "]"); 00247 break; 00248 } 00249 fclose(f); 00250 sendlog(lev, line, file, func, idval, useid, usep, "%s", logbuf); 00251 } 00252 00253 #else 00254 // ###################################################################### 00255 //! Send a log. NON-GNUC, thread-unsafe version 00256 void sendlog(const char *msg, ...) 00257 { 00258 if (MYLOGLEV > MYLOGVERB) return; // ignore if insuffic priority 00259 00260 va_list args; int len, len2; va_start(args, msg); char logbuf[LBS]; 00261 00262 // make sure strncpy did not leave us with unterminated strings: 00263 MYLOGFUN[LBS2-1] = '\0'; MYLOGFIL[LBS2-1] = '\0'; 00264 00265 // remove filename extension, if any, to get class name: 00266 for (int i = strlen(MYLOGFIL)-1; i >= 0; i--) 00267 if (MYLOGFIL[i] == '.') { MYLOGFIL[i] = '\0'; break; } 00268 00269 // print first chunk: file and function 00270 len = snprintf(logbuf, LBS, "%s::%s", MYLOGFIL, MYLOGFUN); 00271 if (len == -1 || len >= LBS-1) goto done; // buffer is already full... 00272 00273 #ifdef DEBUG 00274 // if debug mode, add line number: 00275 len2 = snprintf(&(logbuf[len]), LBS-len, "(%d)", MYLOGLIN); 00276 if (len2 == -1 || len2+len >= LBS-1) goto done; else len += len2; 00277 #endif 00278 logbuf[len++] = ':'; if (len >= LBS-1) goto done; 00279 00280 // if we use ID-logging, print the ID now: 00281 if (MYLOG_USEID) { 00282 len2 = snprintf(&(logbuf[len]), LBS-len, "(%d)", MYLOGIDVAL); 00283 if (len2 == -1 || len2+len >= LBS-1) goto done; else len += len2; 00284 } 00285 00286 // if msg starts with opening bracket, do not add a space: 00287 if (msg[0] != '(' && msg[0] != '[' && msg[0] != '{') 00288 { logbuf[len++] = ' '; if (len >= LBS-1) goto done; } 00289 00290 // print the actual message: 00291 len2 = vsnprintf(&(logbuf[len]), LBS-len, msg, args); 00292 if (len2 == -1 || len2+len >= LBS-1) goto done; else len += len2; 00293 00294 // if doing P-logging, add errno in clear: 00295 if (MYLOG_USEP) 00296 snprintf( &(logbuf[len]), LBS-len, " (errno=%d, %s)", 00297 errno, strerror(errno)); 00298 00299 // ready to send to syslog: 00300 done: 00301 va_end(args); 00302 00303 logbuf[LBS - 1] = '\0'; 00304 00305 sendlog_aux(logbuf, MYLOGLEV, LOG_FLAGS); 00306 } 00307 00308 00309 char MYLOGFUN[LBS2], MYLOGFIL[LBS2]; 00310 int MYLOGLIN, MYLOGLEV, MYLOGIDVAL; 00311 bool MYLOG_USEP, MYLOG_USEID; 00312 00313 #endif 00314 00315 void report_current_exception(const int line, const char* file) throw() 00316 { 00317 // rethrow the exception so we can recatch it and see if it is of a 00318 // known type: 00319 try { throw; } 00320 catch (std::exception& e) 00321 { 00322 fprintf(stderr, "%s:%d: exception caught (%s) with what():\n%s\n", 00323 file, line, rutz::demangled_name(typeid(e)), e.what()); 00324 fflush(stderr); 00325 } 00326 catch (...) 00327 { 00328 fprintf(stderr, "%s:%d: caught an exception of unknown type\n", 00329 file, line); 00330 fflush(stderr); 00331 } 00332 } 00333 00334 // ###################################################################### 00335 /* So things look consistent in everyone's emacs... */ 00336 /* Local Variables: */ 00337 /* indent-tabs-mode: nil */ 00338 /* End: */