Logger.cpp

00001 /***************************************************************************
00002   tag: Peter Soetens  Mon Jan 10 15:59:15 CET 2005  Logger.cxx 
00003 
00004                         Logger.cxx -  description
00005                            -------------------
00006     begin                : Mon January 10 2005
00007     copyright            : (C) 2005 Peter Soetens
00008     email                : peter.soetens@mech.kuleuven.ac.be
00009  
00010  ***************************************************************************
00011  *   This library is free software; you can redistribute it and/or         *
00012  *   modify it under the terms of the GNU General Public                   *
00013  *   License as published by the Free Software Foundation;                 *
00014  *   version 2 of the License.                                             *
00015  *                                                                         *
00016  *   As a special exception, you may use this file as part of a free       *
00017  *   software library without restriction.  Specifically, if other files   *
00018  *   instantiate templates or use macros or inline functions from this     *
00019  *   file, or you compile this file and link it with other files to        *
00020  *   produce an executable, this file does not by itself cause the         *
00021  *   resulting executable to be covered by the GNU General Public          *
00022  *   License.  This exception does not however invalidate any other        *
00023  *   reasons why the executable file might be covered by the GNU General   *
00024  *   Public License.                                                       *
00025  *                                                                         *
00026  *   This library is distributed in the hope that it will be useful,       *
00027  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00028  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00029  *   Lesser General Public License for more details.                       *
00030  *                                                                         *
00031  *   You should have received a copy of the GNU General Public             *
00032  *   License along with this library; if not, write to the Free Software   *
00033  *   Foundation, Inc., 59 Temple Place,                                    *
00034  *   Suite 330, Boston, MA  02111-1307  USA                                *
00035  *                                                                         *
00036  ***************************************************************************/
00037  
00038 // to retrieve RTAI version, if any.
00039 //#define OROBLD_OS_LXRT_INTERNAL 
00040 #include "os/StartStopManager.hpp"
00041 #include "os/MutexLock.hpp"
00042 #include "os/Mutex.hpp"
00043 #include "TimeService.hpp"
00044 
00045 #include "Logger.hpp"
00046 #include <iomanip>
00047 
00048 #ifdef OROSEM_PRINTF_LOGGING
00049 #  include <stdio.h>
00050 #else
00051 #  include <iostream>
00052 #  include <ostream>
00053 #  ifdef OROSEM_FILE_LOGGING
00054 #   include <fstream>
00055 #  endif
00056 #  ifdef OROSEM_REMOTE_LOGGING
00057 #   include <sstream>
00058 #  endif
00059 #endif
00060 
00061 #include <stdlib.h>
00062 #include "rtt-config.h"
00063 
00064 namespace RTT 
00065 {
00066     using namespace std;
00067 
00068     Logger* Logger::_instance = 0;
00069 
00070     Logger* Logger::Instance() {
00071         if (_instance == 0) {
00072             _instance =  new Logger();
00073         }
00074         return _instance;
00075     }
00076 
00077     void Logger::Release() {
00078       if (_instance) {
00079         _instance->shutdown();
00080         delete _instance;
00081         _instance = 0;
00082       }
00083     }
00084 
00085 #ifndef OROBLD_DISABLE_LOGGING
00086 
00087     Logger& Logger::log() {
00088         return *Instance();
00089     }
00090 
00091     Logger& Logger::log(LogLevel ll) {
00092         return Instance()->operator<<( ll );
00093     }
00094 
00098     struct Logger::D
00099     {
00100         D() :
00101 #ifndef OROSEM_PRINTF_LOGGING
00102               stdoutput(&std::cerr),
00103 #endif
00104 #ifdef OROSEM_REMOTE_LOGGING
00105               messagecnt(0),
00106 #endif
00107 #if defined(OROSEM_FILE_LOGGING) && !defined(OROSEM_PRINTF_LOGGING)
00108               logfile("orocos.log"),
00109 #endif
00110               inloglevel(Info),
00111               outloglevel(Warning),
00112               timestamp(0),
00113               started(false), showtime(true), allowRT(false), 
00114               loggermodule("Logger"), moduleptr(loggermodule)
00115         {
00116 #if defined(OROSEM_FILE_LOGGING) && defined(OROSEM_PRINTF_LOGGING)
00117             logfile = fopen("orocos.log","w");
00118 #endif
00119         }
00120 
00121         bool maylog() const {
00122             if (!started || (outloglevel == RealTime && allowRT == false))
00123                 return false;
00124             return true;
00125         }
00126 
00127         bool maylogStdOut() const {
00128             if ( inloglevel <= outloglevel && outloglevel != Never && inloglevel != Never ) 
00129                 return true;
00130             return false;
00131         }
00132 
00133         bool maylogFile() const {
00134             if ( inloglevel <= Info || inloglevel <= outloglevel )
00135                 return true;
00136             return false;
00137         }
00138 
00144         void logit(std::ostream& (*pf)(std::ostream&))
00145         {
00146             // only on Logger::nl or Logger::endl, a time+log-line is written.
00147             OS::MutexLock lock( inpguard );
00148             std:: string res = showTime() +" " + showLevel(inloglevel) + showModule() + " ";
00149 
00150             // do not log if not wanted.
00151             if ( maylogStdOut() ) {
00152 #ifndef OROSEM_PRINTF_LOGGING
00153                 *stdoutput << res << logline.str() << pf;
00154 #else
00155                 printf("%s%s\n", res.c_str(), logline.str().c_str() );
00156 #endif
00157                 logline.str("");   // clear stringstream.
00158             }
00159 
00160             if ( maylogFile() ) {
00161 #ifdef OROSEM_FILE_LOGGING
00162 #ifndef OROSEM_PRINTF_LOGGING
00163                 logfile << res << fileline.str() << pf;
00164 #else
00165                 fprintf( logfile, "%s%s\n", res.c_str(), fileline.str().c_str() );
00166 #endif
00167 #ifdef OROSEM_REMOTE_LOGGING
00168                 // detect buffer 'overflow'
00169                 if ( messagecnt >= ORONUM_LOGGING_BUFSIZE ) {
00170                     std::string dummy;
00171                     remotestream >> dummy; // FIFO principle: read 1 line
00172                     --messagecnt;
00173                 }
00174                 remotestream << res << fileline.str() << pf;
00175                 ++messagecnt;
00176 #endif
00177 #if defined(OROSEM_FILE_LOGGING) || defined(OROSEM_REMOTE_LOGGING)
00178                 fileline.str("");
00179 #endif
00180 #endif
00181             }
00182         }
00183 
00184 #ifndef OROSEM_PRINTF_LOGGING
00185         std::ostream* stdoutput;
00186 #endif
00187         std::stringstream logline;
00188 #if defined(OROSEM_FILE_LOGGING) || defined(OROSEM_REMOTE_LOGGING)
00189         std::stringstream fileline;
00190 #endif
00191 #if defined(OROSEM_REMOTE_LOGGING)
00192         std::stringstream remotestream;
00193         unsigned int messagecnt;
00194 #endif
00195 #if defined(OROSEM_FILE_LOGGING)
00196 # ifndef OROSEM_PRINTF_LOGGING
00197         std::ofstream logfile;
00198 # else
00199         FILE* logfile;
00200 # endif
00201 #endif
00202         LogLevel inloglevel, outloglevel;
00203 
00204         TimeService::ticks timestamp;
00205 
00206         Logger::LogLevel intToLogLevel(int ll) {
00207             switch (ll)
00208                 {
00209                 case -1:
00210                 case 0:
00211                     return Never;
00212                 case 1:
00213                     return Fatal;
00214                 case 2:
00215                     return Critical;
00216                 case 3:
00217                     return Error;
00218                 case 4:
00219                     return Warning;
00220                 case 5:
00221                     return Info;
00222                 case 6:
00223                     return Debug;
00224                 }
00225             return Debug; // > 6
00226         }
00227 
00228 
00229         std::string showTime() const
00230         {
00231             std::stringstream time;
00232             if ( showtime )
00233                 time <<fixed<< showpoint << setprecision(3) << TimeService::Instance()->secondsSince(timestamp);
00234             return time.str();
00235         }
00236 
00240         std::string showLevel( LogLevel ll) const {
00241             std::string prefix;
00242             switch (ll)
00243                 {
00244                 case Fatal:
00245                     prefix="[ FATAL  ]";
00246                     break;
00247                 case Critical:
00248                     prefix="[CRITICAL]";
00249                     break;
00250                 case Error:
00251                     prefix="[ ERROR  ]";
00252                     break;
00253                 case Warning:
00254                     prefix="[ Warning]";
00255                     break;
00256                 case Info:
00257                     prefix="[ Info   ]";
00258                     break;
00259                 case Debug:
00260                     prefix="[ Debug  ]";
00261                     break;
00262                 case RealTime:
00263                     prefix="[RealTime]";
00264                     break;
00265                 case Never:
00266                     break;
00267                 }
00268             return prefix;
00269         }
00270 
00271 
00272 
00273         std::string showModule() const
00274         {
00275             return "["+std::string(moduleptr)+"]";
00276         }
00277 
00278         bool started;
00279 
00280         bool showtime;
00281 
00282         bool allowRT;
00283 
00284         const char* loggermodule;
00285         const char* moduleptr;
00286 
00287         OS::Mutex inpguard;
00288         OS::Mutex startguard;
00289     };
00290 
00291     Logger::Logger()
00292         :d ( new Logger::D() )
00293     {
00294       this->startup();
00295     }
00296 
00297     Logger::~Logger()
00298     {
00299         delete d;
00300     }
00301 
00302     bool Logger::mayLog() const {
00303         return d->maylog();
00304     }
00305 
00306     void Logger::allowRealTime() {
00307         *this << Logger::Warning << "Enabling Real-Time Logging !" <<Logger::endl;
00308         d->allowRT = true;
00309     }
00310     void Logger::disallowRealTime() {
00311         *this << Logger::Warning << "Disabling Real-Time Logging !" <<Logger::endl;
00312         d->allowRT = false;
00313     }
00314 
00315     std::ostream&
00316     Logger::nl(std::ostream& __os)
00317     {
00318 #ifndef OROSEM_PRINTF_LOGGING
00319         return __os.put(__os.widen('\n'));
00320 #else
00321         return __os;
00322 #endif
00323     }
00324 
00325     std::ostream&
00326     Logger::endl(std::ostream& __os)
00327     {
00328 #ifndef OROSEM_PRINTF_LOGGING
00329         return flush(__os.put(__os.widen('\n')));
00330 #else
00331         return __os;
00332 #endif
00333     }
00334 
00335     std::ostream&
00336     Logger::flush(std::ostream& __os)
00337     {
00338 #ifndef OROSEM_PRINTF_LOGGING
00339         return __os.flush();
00340 #else
00341         return __os;
00342 #endif
00343     }
00344 
00345 
00346     Logger::In::In(const char* modname)
00347         : oldmod( Logger::log().getLogModule() )
00348     {
00349         Logger::log().in(modname);
00350     }
00351 
00352     Logger::In::~In() 
00353     {
00354         Logger::log().out();
00355     }
00356 
00357     Logger& Logger::in(const char* modname) 
00358     {
00359         d->moduleptr = modname;
00360         return *this;
00361     }
00362 
00363     Logger& Logger::out()
00364     {
00365         d->moduleptr = d->loggermodule;
00366         return *this;
00367     }
00368 
00369     const char* Logger::getLogModule() const {
00370         return d->moduleptr;
00371     }
00372 
00373 
00374 #define ORO_xstr(s) ORO_str(s)
00375 #define ORO_str(s) #s        
00376 
00377     void Logger::startup() {
00378         if (d->started)
00379             return;
00380 #ifndef OROBLD_DISABLE_LOGGING
00381         std::string xtramsg = "No ORO_LOGLEVEL environment variable set.";
00382         *this << Logger::Info; // default log to Info
00383 
00384         int wantedlevel=4; // default log level is 4.
00385 
00386         if ( getenv( "ORO_LOGLEVEL" ) != 0 ) {
00387             std::stringstream conv;
00388             conv.str( std::string( getenv( "ORO_LOGLEVEL" ) ) );
00389             conv >> wantedlevel;
00390             if ( conv.fail() ) {
00391                 xtramsg = std::string( "Failed to extract loglevel from environment variable ORO_LOGLEVEL.")
00392                     + " It contained the string '"+conv.str()+"', while it should contain an integer value.";
00393                 *this<<Logger::Error;
00394             }
00395             else {
00396                 d->outloglevel = d->intToLogLevel(wantedlevel);
00397                 xtramsg = "Successfully extracted environment variable ORO_LOGLEVEL";
00398             }
00399         }
00400 
00401         // Completely disable logging on negative values.
00402         if ( wantedlevel < 0 )
00403             return;
00404         d->started = true;
00405             
00406         d->timestamp = TimeService::Instance()->getTicks();
00407         *this<<xtramsg<<Logger::nl;
00408         *this<< " OROCOS version '" ORO_xstr(RTT_VERSION) "'";
00409 #ifdef __GNUC__
00410         *this << " compiled with GCC " ORO_xstr(__GNUC__) "." ORO_xstr(__GNUC_MINOR__) "." ORO_xstr(__GNUC_PATCHLEVEL__) ".";
00411 #endif
00412 #ifdef OROPKG_OS_LXRT
00413         *this<<" Running in LXRT/RTAI."<< Logger::nl;
00414 #endif
00415 #ifdef OROPKG_OS_GNULINUX
00416         *this<<" Running in GNU/Linux."<< Logger::nl;
00417 #endif
00418 #ifdef OROPKG_OS_XENOMAI
00419         *this<<" Running in Xenomai."<< Logger::nl;
00420 #endif
00421         *this<<"Orocos Logging Activated at level : " << d->showLevel( d->outloglevel ) << " ( "<<int(d->outloglevel)<<" ) "<< Logger::nl;
00422         *this<<"Reference System Time is : " << d->timestamp << " ticks ( "<< Seconds(TimeService::ticks2nsecs(d->timestamp))/NSECS_IN_SECS <<" seconds )." << Logger::nl;
00423         *this<<"Logging is relative to this time." <<Logger::endl;
00424 #endif
00425     }
00426 
00427     void Logger::shutdown() {
00428         if (!d->started)
00429             return;
00430         *this<<Logger::Info<<"Orocos Logging Deactivated." << Logger::endl;
00431         this->logflush();
00432         d->started = false;
00433     }
00434 
00435     std::string Logger::getLogLine() {
00436 #ifdef OROSEM_REMOTE_LOGGING
00437         if (!d->started)
00438             return "";
00439         std::string line;
00440         {
00441             OS::MutexLock lock( d->inpguard );
00442             getline( d->remotestream, line );
00443             if ( !d->remotestream )
00444                 d->remotestream.clear();
00445         }
00446         if ( !line.empty() )
00447             --d->messagecnt;
00448         return line;
00449 #else
00450         return "";
00451 #endif
00452     }
00453 
00454     void Logger::setStdStream( std::ostream& stdos ) {
00455 #ifndef OROSEM_PRINTF_LOGGING
00456         d->stdoutput = &stdos;
00457 #endif
00458     }
00459 
00460     Logger& Logger::operator<<( const char* t ) {
00461         if ( !d->maylog() )
00462             return *this;
00463         
00464         OS::MutexLock lock( d->inpguard );
00465         if ( d->maylogStdOut() )
00466             d->logline << t;
00467 
00468 #if defined(OROSEM_FILE_LOGGING) || defined(OROSEM_REMOTE_LOGGING)
00469         // log Info or better to log file, even if not started.
00470         if ( d->maylogFile() )
00471             d->fileline << t;
00472 #endif
00473         return *this;
00474     }
00475 
00476     Logger& Logger::operator<<( const std::string& t ) {
00477         return this->operator<<( t.c_str() );
00478     }
00479 
00480     Logger& Logger::operator<<(LogLevel ll) {
00481         if ( !d->maylog() )
00482             return *this;
00483         d->inloglevel = ll;
00484         return *this;
00485     }
00486 
00487     Logger& Logger::operator<<(std::ostream& (*pf)(std::ostream&))
00488     {
00489         if ( !d->maylog() )
00490             return *this;
00491         if ( pf == Logger::endl )
00492             this->logendl();
00493         else if ( pf == Logger::nl )
00494             this->lognl();
00495         else if ( pf == Logger::flush )
00496             this->logflush();
00497         else {
00498             OS::MutexLock lock( d->inpguard );
00499             if ( d->maylogStdOut() )
00500                 d->logline << pf; // normal std operator in stream.
00501 #if defined(OROSEM_FILE_LOGGING) || defined(OROSEM_REMOTE_LOGGING)
00502             if ( d->maylogFile() )
00503                 d->fileline << pf;
00504 #endif
00505         }
00506         return *this;
00507     }
00508 
00509     void Logger::logflush() {
00510         if (!d->maylog())
00511             return;
00512         {
00513             // just flush all buffers, do not produce a new logline
00514             OS::MutexLock lock( d->inpguard );
00515             if ( d->maylogStdOut() ) {
00516 #ifndef OROSEM_PRINTF_LOGGING
00517                 d->stdoutput->flush();
00518 #endif
00519 #if defined(OROSEM_REMOTE_LOGGING)
00520                 d->remotestream.flush();
00521 #endif
00522             }
00523 #if defined(OROSEM_FILE_LOGGING)
00524             if ( d->maylogFile() ) {
00525 #ifndef OROSEM_PRINTF_LOGGING
00526                 d->logfile.flush();
00527 #endif
00528             }
00529 #endif
00530         }
00531      }
00532 
00533     void Logger::lognl() {
00534         if (!d->maylog())
00535             return;
00536         d->logit( Logger::nl );
00537      }
00538 
00539     void Logger::logendl() {
00540         if (!d->maylog())
00541             return;
00542         d->logit( Logger::endl );
00543      }
00544 
00545     void Logger::setLogLevel( LogLevel ll ) {
00546         d->outloglevel = ll;
00547     }
00548 
00549     Logger::LogLevel Logger::getLogLevel() const {
00550         return d->outloglevel ;
00551     }
00552 
00553 
00554 #else // OROBLD_DISABLE_LOGGING
00555 
00556     Logger::Logger()
00557         : d(0)
00558     {
00559     }
00560 
00561     Logger::~Logger()
00562     {
00563     }
00564 
00565 #endif
00566 }

Generated on Tue Mar 25 17:41:47 2008 for OrocosReal-TimeToolkit by  doxygen 1.5.3