Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | Related Pages | Examples

ArLog.cpp

00001 /*
00002 MobileRobots Advanced Robotics Interface for Applications (ARIA)
00003 Copyright (C) 2004, 2005 ActivMedia Robotics LLC
00004 Copyright (C) 2006, 2007 MobileRobots Inc.
00005 
00006      This program is free software; you can redistribute it and/or modify
00007      it under the terms of the GNU General Public License as published by
00008      the Free Software Foundation; either version 2 of the License, or
00009      (at your option) any later version.
00010 
00011      This program is distributed in the hope that it will be useful,
00012      but WITHOUT ANY WARRANTY; without even the implied warranty of
00013      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014      GNU General Public License for more details.
00015 
00016      You should have received a copy of the GNU General Public License
00017      along with this program; if not, write to the Free Software
00018      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 
00020 If you wish to redistribute ARIA under different terms, contact 
00021 MobileRobots for information about a commercial version of ARIA at 
00022 robots@mobilerobots.com or 
00023 MobileRobots Inc, 19 Columbia Drive, Amherst, NH 03031; 800-639-9481
00024 */
00025 
00026 #include "ArExport.h"
00027 #include "ariaOSDef.h"
00028 #include "ArLog.h"
00029 #include "ArConfig.h"
00030 #include <time.h>
00031 #include <stdarg.h>
00032 #include <ctype.h>
00033 
00034 
00035 /* VS Express 2005 doesn't have this, and it's only used for debug logging which I've never
00036    really seen work.   Maybe we could check  _MSC_VER and/or _ATL_VER?
00037 #if defined(_DEBUG) && defined(ARIA_MSVC)
00038 #include <atlbase.h>
00039 #endif
00040 */
00041 
00042 ArMutex ArLog::ourMutex;
00043 ArLog::LogType ArLog::ourType=StdOut;
00044 ArLog::LogLevel ArLog::ourLevel=ArLog::Normal;
00045 FILE * ArLog::ourFP=0;
00046 std::string ArLog::ourFileName;
00047 int ArLog::ourColbertStream = -1;
00048 bool ArLog::ourLoggingTime = false;
00049 bool ArLog::ourAlsoPrint = false;
00050 AREXPORT void (* ArLog::colbertPrint)(int i, const char *str);
00051 
00052 ArLog::LogType ArLog::ourConfigLogType = ArLog::StdOut;
00053 ArLog::LogLevel ArLog::ourConfigLogLevel = ArLog::Normal;
00054 char ArLog::ourConfigFileName[1024] = "log.txt";
00055 bool ArLog::ourConfigLogTime = false;
00056 bool ArLog::ourConfigAlsoPrint = false;
00057 ArGlobalRetFunctor<bool> ArLog::ourConfigProcessFileCB(&ArLog::processFile);
00058 
00059 AREXPORT void ArLog::logPlain(LogLevel level, const char *str)
00060 {
00061   log(level, str);
00062 }
00063 
00070 AREXPORT void ArLog::log(LogLevel level, const char *str, ...)
00071 {
00072   char buf[2048];
00073   char *bufPtr;
00074   char *timeStr;
00075   int timeLen = 20; // this is a value based on the standard length of
00076                        // ctime return
00077   time_t now;
00078 
00079 
00080   if (level <= ourLevel)
00081   {
00082     ourMutex.lock();
00083     // put our time in if we want it
00084     if (ourLoggingTime)
00085     {
00086       now = time(NULL);
00087       timeStr = ctime(&now);
00088       // get take just the portion of the time we want
00089       strncpy(buf, timeStr, timeLen);
00090       buf[timeLen] = '\0';
00091       bufPtr = &buf[timeLen];
00092     }
00093     else
00094       bufPtr = buf;
00095     va_list ptr;
00096     va_start(ptr, str);
00097     vsprintf(bufPtr, str, ptr);
00098     // can do whatever you want with the buf now
00099     if (ourType == Colbert)
00100     {
00101       if (colbertPrint)     // check if we have a print routine
00102     (*colbertPrint)(ourColbertStream, buf);
00103     }
00104     else if (ourFP)
00105     {
00106       fprintf(ourFP, "%s\n", buf);
00107       fflush(ourFP);
00108     }
00109     else if (ourType != None)
00110     {
00111       printf("%s\n", buf);
00112       fflush(stdout);
00113     }
00114     if (ourAlsoPrint)
00115       printf("%s\n", buf);
00116 
00117     /* rh: this does not build in VS Express 2005, and I don't think I've ever seen it actually 
00118            do anything, so removing it for now.
00119            We could also check _ATL_VER and/or _MSC_VER preprocessor symbols.
00120 // Also send it to the VC++ debug output window...
00121 #if defined(_DEBUG) && defined(_WIN32)
00122 ATLTRACE2("%s\n", buf);
00123 #endif
00124     */
00125 
00126     va_end(ptr);
00127     ourMutex.unlock();
00128   }
00129 
00130 }
00131 
00142 AREXPORT bool ArLog::init(LogType type, LogLevel level, const char *fileName,
00143               bool logTime, bool alsoPrint, bool printThisCall)
00144 {
00145   ourMutex.lock();
00146   
00147   // if we weren't or won't be doing a file then close any old file
00148   if (ourType != File || type != File)
00149   {
00150     close();
00151   }
00152   
00153   if (type == StdOut)
00154     ourFP=stdout;
00155   else if (type == StdErr)
00156     ourFP=stderr;
00157   else if (type == File)
00158   {
00159     if (fileName != NULL)
00160     {
00161       if (strcmp(ourFileName.c_str(), fileName) == 0)
00162       {
00163     ArLog::logNoLock(ArLog::Terse, "ArLog::init: Continuing to log to the same file.");
00164       }
00165       else
00166       {
00167     close();
00168     if ((ourFP = fopen(fileName, "w")) == NULL)
00169     {
00170       ArLog::logNoLock(ArLog::Terse, "ArLog::init: Could not open file %s for logging.", fileName);
00171       ourMutex.unlock();
00172       return(false);
00173     }
00174     ourFileName=fileName;
00175       }
00176     }
00177   }
00178   else if (type == Colbert)
00179   {
00180     colbertPrint = NULL;
00181     ourColbertStream = -1;  // use default stream
00182     if (fileName)
00183     {  // need to translate fileName to integer index
00184     }
00185   }
00186   else if (type == None)
00187   {
00188 
00189   }
00190   ourType=type;
00191   ourLevel=level;
00192 
00193   // environment variable overrides level
00194   {
00195     char* lev = getenv("ARLOG_LEVEL");
00196     if(lev)
00197     {
00198       switch(toupper(lev[0]))
00199       {
00200         case 'N':
00201           ourLevel = Normal;
00202           break;
00203         case 'T':
00204           ourLevel = Terse;
00205           break;
00206         case 'V':
00207           ourLevel = Verbose;
00208           break;
00209        }
00210     }
00211   }
00212 
00213   ourLoggingTime = logTime;
00214   ourAlsoPrint = alsoPrint;
00215 
00216   if (printThisCall)
00217   {
00218     printf("ArLog::init: ");
00219     
00220     if (ourType == StdOut)
00221       printf(" StdOut\t");
00222     else if (ourType == StdErr)
00223       printf(" StdErr\t");
00224     else if (ourType == File)
00225       printf(" File(%s)\t", ourFileName.c_str());
00226     else if (ourType == Colbert)
00227       printf(" Colbert\t");
00228     else if (ourType == None)
00229       printf(" None\t");
00230     else
00231       printf(" BadType\t");
00232     
00233     if (ourLevel == Terse)
00234       printf(" Terse\t");
00235     else if (ourLevel == Normal)
00236       printf(" Normal\t");
00237     else if (ourLevel == Verbose)
00238       printf(" Verbose\t");
00239     else
00240       printf(" BadLevel\t");
00241     
00242     if (ourLoggingTime)
00243       printf(" Logging Time\t");
00244     else
00245       printf(" Not logging time\t");
00246     
00247     if (ourAlsoPrint)
00248       printf(" Also printing\n");
00249     else
00250       printf(" Not also printing\n");
00251   }
00252   ourMutex.unlock();
00253   return(true);
00254 }
00255 
00256 AREXPORT void ArLog::close()
00257 {
00258   if (ourFP && (ourType == File))
00259   {
00260     fclose(ourFP);
00261     ourFP=0;
00262     ourFileName="";
00263   }
00264 }
00265 
00266 AREXPORT void ArLog::logNoLock(LogLevel level, const char *str, ...)
00267 {
00268   char buf[2048];
00269   char *bufPtr;
00270   char *timeStr;
00271   int timeLen = 20; // this is a value based on the standard length of
00272                        // ctime return
00273   time_t now;
00274 
00275   if (level <= ourLevel)
00276   {
00277     // put our time in if we want it
00278     if (ourLoggingTime)
00279     {
00280       now = time(NULL);
00281       timeStr = ctime(&now);
00282       // get take just the portion of the time we want
00283       strncpy(buf, timeStr, timeLen);
00284       buf[timeLen] = '\0';
00285       bufPtr = &buf[timeLen];
00286     }
00287     else
00288       bufPtr = buf;
00289     va_list ptr;
00290     va_start(ptr, str);
00291     vsprintf(bufPtr, str, ptr);
00292     // can do whatever you want with the buf now
00293     if (ourType == Colbert)
00294     {
00295       if (colbertPrint)     // check if we have a print routine
00296     (*colbertPrint)(ourColbertStream, buf);
00297     }
00298     else if (ourFP)
00299       fprintf(ourFP, "%s\n", buf);
00300     else if (ourType != None)
00301       printf("%s\n", buf);
00302     if (ourAlsoPrint)
00303       printf("%s\n", buf);
00304     va_end(ptr);
00305   }
00306 }
00307 
00308 AREXPORT void ArLog::addToConfig(ArConfig *config)
00309 {
00310   std::string section = "LogConfig";
00311   config->addParam(
00312       ArConfigArg("LogType", (int *)&ourConfigLogType,
00313               "The type of log we'll be using, 0 for StdOut, 1 for StdErr, 2 for File (and give it a file name), 3 for colbert (don't use that), and 4 for None", 
00314               ArLog::StdOut, ArLog::None), 
00315       section.c_str(), ArPriority::TRIVIAL);
00316   config->addParam(
00317       ArConfigArg("LogLevel", (int *)&ourConfigLogLevel,
00318               "The level of logging to do, 0 for Terse, 1 for Normal, and 2 for Verbose", 
00319               ArLog::Terse, ArLog::Verbose), 
00320       section.c_str(), ArPriority::TRIVIAL);
00321   config->addParam(
00322       ArConfigArg("LogFileName", ourConfigFileName,
00323               "File to log to", sizeof(ourConfigFileName)),
00324       section.c_str(), ArPriority::TRIVIAL);
00325   config->addParam(
00326       ArConfigArg("LogTime", &ourConfigLogTime,
00327               "True to prefix log messages with time and date, false not to"),
00328       section.c_str(), ArPriority::TRIVIAL);
00329   config->addParam(
00330       ArConfigArg("LogAlsoPrint", &ourConfigAlsoPrint,
00331               "True to also printf the message, false not to"),   
00332       section.c_str(), ArPriority::TRIVIAL);
00333   ourConfigProcessFileCB.setName("ArLog");
00334   config->addProcessFileCB(&ourConfigProcessFileCB, 200);
00335 }
00336 
00337 AREXPORT bool ArLog::processFile(void)
00338 {
00339   if (ourConfigLogType != ourType || ourConfigLogLevel != ourLevel ||
00340       strcmp(ourConfigFileName, ourFileName.c_str()) != 0 || 
00341       ourConfigLogTime != ourLoggingTime || ourConfigAlsoPrint != ourAlsoPrint)
00342   {
00343     ArLog::log(ArLog::Normal, "Initializing log from config");
00344     return ArLog::init(ourConfigLogType, ourConfigLogLevel, ourConfigFileName, 
00345                ourConfigLogTime, ourConfigAlsoPrint, true);
00346   }
00347   return true;
00348 }

Generated on Tue Feb 20 10:51:40 2007 for Aria by  doxygen 1.4.0