log.C

Go to the documentation of this file.
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: */
Generated on Sun May 8 08:42:26 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3