Logger.cpp
Go to the documentation of this file.
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 "os/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 #   ifdef  OROSEM_LOG4CPP_LOGGING
00056 #    include <log4cpp/Category.hh>
00057 #   endif
00058 #  endif
00059 #  ifdef OROSEM_REMOTE_LOGGING
00060 #   include <sstream>
00061 #  endif
00062 #endif
00063 
00064 #include <stdlib.h>
00065 #include "rtt-config.h"
00066 #include "rtt-fwd.hpp"
00067 
00068 namespace RTT
00069 {
00070     using namespace std;
00071     using namespace detail;
00072 
00073     Logger* Logger::_instance = 0;
00074 
00075     Logger* Logger::Instance(std::ostream& str) {
00076         if (_instance == 0) {
00077             _instance =  new Logger(str);
00078         }
00079         return _instance;
00080     }
00081 
00082     void Logger::Release() {
00083       if (_instance) {
00084         _instance->shutdown();
00085         delete _instance;
00086         _instance = 0;
00087       }
00088     }
00089 
00090 #ifndef OROBLD_DISABLE_LOGGING
00091 
00092 #ifdef  OROSEM_LOG4CPP_LOGGING
00093 
00094     const std::string Logger::log4cppCategoryName = "org.orocos.rtt";
00095 
00096     log4cpp::Priority::Value level2Priority(const int logLevel)
00097     {
00098         log4cpp::Priority::Value value = log4cpp::Priority::NOTSET;
00099         switch (logLevel)
00100         {
00101             case Never:     value = log4cpp::Priority::NOTSET; break;
00102             case Fatal:     value = log4cpp::Priority::FATAL;  break;
00103             case Critical:  value = log4cpp::Priority::CRIT;   break;
00104             case Error:     value = log4cpp::Priority::ERROR;  break;
00105             case Warning:   value = log4cpp::Priority::WARN;   break;
00106             case Info:      value = log4cpp::Priority::INFO;   break;
00107             case Debug:     value = log4cpp::Priority::DEBUG;  break;
00108                 // best we can do!?
00109             case RealTime:  value = log4cpp::Priority::DEBUG;  break;
00110             default:        value = log4cpp::Priority::NOTSET; break;
00111         }
00112         return value;
00113     }
00114 
00115 #endif
00116 
00117     Logger& Logger::log() {
00118         return *Instance();
00119     }
00120 
00121     Logger& Logger::log(LogLevel ll) {
00122         return Instance()->operator<<( ll );
00123     }
00124 
00128     struct Logger::D
00129     {
00130     public:
00131         D(std::ostream& str, char const* logfile_name) :
00132 #ifndef OROSEM_PRINTF_LOGGING
00133               stdoutput( &str ),
00134 #endif
00135 #ifdef OROSEM_REMOTE_LOGGING
00136               messagecnt(0),
00137 #endif
00138 #if     defined(OROSEM_FILE_LOGGING)
00139 #if     defined(OROSEM_LOG4CPP_LOGGING)
00140               category(log4cpp::Category::getInstance(RTT::Logger::log4cppCategoryName)),
00141 #elif   !defined(OROSEM_PRINTF_LOGGING)
00142               logfile(logfile_name ? logfile_name : "orocos.log"),
00143 #endif
00144 #endif
00145               inloglevel(Info),
00146               outloglevel(Warning),
00147               timestamp(0),
00148               started(false), showtime(true), allowRT(false),
00149               mlogStdOut(true), mlogFile(true),
00150               moduleptr("Logger")
00151         {
00152 #if defined(OROSEM_FILE_LOGGING) && !defined(OROSEM_LOG4CPP_LOGGING) && defined(OROSEM_PRINTF_LOGGING)
00153             logfile = fopen(logfile_name ? logfile_name : "orocos.log","w");
00154 #endif
00155         }
00156 
00157         bool maylog() const {
00158             if (!started || (outloglevel == RealTime && allowRT == false))
00159                 return false;
00160             return true;
00161         }
00162 
00163         bool maylogStdOut() const {
00164             if ( inloglevel <= outloglevel && outloglevel != Never && inloglevel != Never && mlogStdOut)
00165                 return true;
00166             return false;
00167         }
00168 
00169         bool maylogFile() const {
00170             if ( (inloglevel <= Info || inloglevel <= outloglevel)  && mlogFile)
00171                 return true;
00172             return false;
00173         }
00174 
00180         void logit(std::ostream& (*pf)(std::ostream&))
00181         {
00182             // only on Logger::nl or Logger::endl, a time+log-line is written.
00183             os::MutexLock lock( inpguard );
00184             std:: string res = showTime() +" " + showLevel(inloglevel) + showModule() + " ";
00185 
00186             // do not log if not wanted.
00187             if ( maylogStdOut() ) {
00188 #ifndef OROSEM_PRINTF_LOGGING
00189                 *stdoutput << res << logline.str() << pf;
00190 #else
00191                 printf("%s%s\n", res.c_str(), logline.str().c_str() );
00192 #endif
00193                 logline.str("");   // clear stringstream.
00194             }
00195 
00196             if ( maylogFile() ) {
00197 #ifdef OROSEM_FILE_LOGGING
00198 #if     defined(OROSEM_LOG4CPP_LOGGING)
00199                 category.log(level2Priority(inloglevel), fileline.str());
00200 #elif   !defined(OROSEM_PRINTF_LOGGING)
00201                 logfile << res << fileline.str() << pf;
00202 #else
00203                 fprintf( logfile, "%s%s\n", res.c_str(), fileline.str().c_str() );
00204 #endif
00205 #ifdef OROSEM_REMOTE_LOGGING
00206                 // detect buffer 'overflow'
00207                 if ( messagecnt >= ORONUM_LOGGING_BUFSIZE ) {
00208                     std::string dummy;
00209                     remotestream >> dummy; // FIFO principle: read 1 line
00210                     --messagecnt;
00211                 }
00212                 remotestream << res << fileline.str() << pf;
00213                 ++messagecnt;
00214 #endif
00215 #if defined(OROSEM_FILE_LOGGING) || defined(OROSEM_REMOTE_LOGGING)
00216                 fileline.str("");
00217 #endif
00218 #endif
00219             }
00220         }
00221 
00222 #ifndef OROSEM_PRINTF_LOGGING
00223         std::ostream* stdoutput;
00224 #endif
00225         std::stringstream logline;
00226 #if defined(OROSEM_FILE_LOGGING) || defined(OROSEM_REMOTE_LOGGING)
00227         std::stringstream fileline;
00228 #endif
00229 #if defined(OROSEM_REMOTE_LOGGING)
00230         std::stringstream remotestream;
00231         unsigned int messagecnt;
00232 #endif
00233 #if defined(OROSEM_FILE_LOGGING)
00234 #if     defined(OROSEM_LOG4CPP_LOGGING)
00235         log4cpp::Category&   category;
00236 #endif
00237 # ifndef OROSEM_PRINTF_LOGGING
00238         std::ofstream logfile;
00239 # else
00240         FILE* logfile;
00241 # endif
00242 #endif
00243         LogLevel inloglevel, outloglevel;
00244 
00245         TimeService::ticks timestamp;
00246 
00247         Logger::LogLevel intToLogLevel(int ll) {
00248             switch (ll)
00249                 {
00250                 case -1:
00251                 case 0:
00252                     return Never;
00253                 case 1:
00254                     return Fatal;
00255                 case 2:
00256                     return Critical;
00257                 case 3:
00258                     return Error;
00259                 case 4:
00260                     return Warning;
00261                 case 5:
00262                     return Info;
00263                 case 6:
00264                     return Debug;
00265                 }
00266             return Debug; // > 6
00267         }
00268 
00269 
00270         std::string showTime() const
00271         {
00272             std::stringstream time;
00273             if ( showtime )
00274                 time <<fixed<< showpoint << setprecision(3) << TimeService::Instance()->secondsSince(timestamp);
00275             return time.str();
00276         }
00277 
00281         std::string showLevel( LogLevel ll) const {
00282             std::string prefix;
00283             switch (ll)
00284                 {
00285                 case Fatal:
00286                     prefix="[ FATAL  ]";
00287                     break;
00288                 case Critical:
00289                     prefix="[CRITICAL]";
00290                     break;
00291                 case Error:
00292                     prefix="[ ERROR  ]";
00293                     break;
00294                 case Warning:
00295                     prefix="[ Warning]";
00296                     break;
00297                 case Info:
00298                     prefix="[ Info   ]";
00299                     break;
00300                 case Debug:
00301                     prefix="[ Debug  ]";
00302                     break;
00303                 case RealTime:
00304                     prefix="[RealTime]";
00305                     break;
00306                 case Never:
00307                     break;
00308                 }
00309             return prefix;
00310         }
00311 
00312 
00313 
00314         std::string showModule() const
00315         {
00316             // moduleptr is protected by lock in logIt()
00317             return "["+moduleptr+"]";
00318         }
00319 
00320         bool started;
00321 
00322         bool showtime;
00323 
00324         bool allowRT;
00325 
00326         bool mlogStdOut, mlogFile;
00327 
00328         std::string moduleptr;
00329 
00330         os::Mutex inpguard;
00331     };
00332 
00333     Logger::Logger(std::ostream& str)
00334         :d ( new Logger::D(str, getenv("ORO_LOGFILE")) ),
00335          inpguard(d->inpguard), logline(d->logline), fileline(d->fileline)
00336     {
00337       this->startup();
00338     }
00339 
00340     Logger::~Logger()
00341     {
00342         delete d;
00343     }
00344 
00345     bool Logger::mayLog() const {
00346         return d->maylog();
00347     }
00348 
00349     bool Logger::mayLogFile() const {
00350         return d->maylogFile();
00351     }
00352 
00353     bool Logger::mayLogStdOut() const {
00354         return d->maylogStdOut();
00355     }
00356 
00357     void Logger::mayLogStdOut(bool tf) {
00358         d->mlogStdOut = tf;
00359     }
00360 
00361     void Logger::mayLogFile(bool tf) {
00362         d->mlogFile = tf;
00363     }
00364 
00365     void Logger::allowRealTime() {
00366         *this << Logger::Warning << "Enabling Real-Time Logging !" <<Logger::endl;
00367         d->allowRT = true;
00368     }
00369     void Logger::disallowRealTime() {
00370         *this << Logger::Warning << "Disabling Real-Time Logging !" <<Logger::endl;
00371         d->allowRT = false;
00372     }
00373 
00374     TimeService::ticks Logger::getReferenceTime()const
00375     {
00376         return d->timestamp;
00377     }
00378 
00379     std::ostream&
00380     Logger::nl(std::ostream& __os)
00381     {
00382 #ifndef OROSEM_PRINTF_LOGGING
00383         return __os.put(__os.widen('\n'));
00384 #else
00385         return __os;
00386 #endif
00387     }
00388 
00389     std::ostream&
00390     Logger::endl(std::ostream& __os)
00391     {
00392 #ifndef OROSEM_PRINTF_LOGGING
00393         return flush(__os.put(__os.widen('\n')));
00394 #else
00395         return __os;
00396 #endif
00397     }
00398 
00399     std::ostream&
00400     Logger::flush(std::ostream& __os)
00401     {
00402 #ifndef OROSEM_PRINTF_LOGGING
00403         return __os.flush();
00404 #else
00405         return __os;
00406 #endif
00407     }
00408 
00409 
00410     Logger::In::In(const std::string& modname)
00411         : oldmod( Logger::log().getLogModule() )
00412     {
00413         Logger::log().in(modname);
00414     }
00415 
00416     Logger::In::~In()
00417     {
00418         Logger::log().out(oldmod);
00419     }
00420 
00421     Logger& Logger::in(const std::string& modname)
00422     {
00423         os::MutexLock lock( d->inpguard );
00424         d->moduleptr = modname.c_str();
00425         return *this;
00426     }
00427 
00428     Logger& Logger::out(const std::string& oldmod)
00429     {
00430         os::MutexLock lock( d->inpguard );
00431         d->moduleptr = oldmod.c_str();
00432         return *this;
00433     }
00434 
00435     std::string Logger::getLogModule() const {
00436         os::MutexLock lock( d->inpguard );
00437         std::string ret = d->moduleptr.c_str();
00438         return ret;
00439     }
00440 
00441 
00442 #define ORO_xstr(s) ORO_str(s)
00443 #define ORO_str(s) #s
00444 
00445     void Logger::startup() {
00446         if (d->started)
00447             return;
00448 #ifndef OROBLD_DISABLE_LOGGING
00449         std::string xtramsg = "No ORO_LOGLEVEL environment variable set.";
00450         *this << Logger::Info; // default log to Info
00451 
00452         int wantedlevel=4; // default log level is 4.
00453 
00454         if ( getenv( "ORO_LOGLEVEL" ) != 0 ) {
00455             std::stringstream conv;
00456             conv.str( std::string( getenv( "ORO_LOGLEVEL" ) ) );
00457             conv >> wantedlevel;
00458             if ( conv.fail() ) {
00459                 xtramsg = std::string( "Failed to extract loglevel from environment variable ORO_LOGLEVEL.")
00460                     + " It contained the string '"+conv.str()+"', while it should contain an integer value.";
00461                 *this<<Logger::Error;
00462             }
00463             else {
00464                 d->outloglevel = d->intToLogLevel(wantedlevel);
00465                 xtramsg = "Successfully extracted environment variable ORO_LOGLEVEL";
00466             }
00467         }
00468 
00469         // Completely disable logging on negative values.
00470         if ( wantedlevel < 0 )
00471             return;
00472         d->started = true;
00473 
00474         d->timestamp = TimeService::Instance()->getTicks();
00475         *this<<xtramsg<<Logger::nl;
00476         *this<< " OROCOS version '" ORO_xstr(RTT_VERSION) "'";
00477 #ifdef __GNUC__
00478         *this << " compiled with GCC " ORO_xstr(__GNUC__) "." ORO_xstr(__GNUC_MINOR__) "." ORO_xstr(__GNUC_PATCHLEVEL__) ".";
00479 #endif
00480 #ifdef OROPKG_OS_LXRT
00481         *this<<" Running in LXRT/RTAI."<< Logger::nl;
00482 #endif
00483 #ifdef OROPKG_OS_GNULINUX
00484         *this<<" Running in GNU/Linux."<< Logger::nl;
00485 #endif
00486 #ifdef OROPKG_OS_XENOMAI
00487         *this<<" Running in Xenomai."<< Logger::nl;
00488 #endif
00489         *this<<"Orocos Logging Activated at level : " << d->showLevel( d->outloglevel ) << " ( "<<int(d->outloglevel)<<" ) "<< Logger::nl;
00490         *this<<"Reference System Time is : " << d->timestamp << " ticks ( "<< Seconds(TimeService::ticks2nsecs(d->timestamp))/NSECS_IN_SECS <<" seconds )." << Logger::nl;
00491         *this<<"Logging is relative to this time." <<Logger::endl;
00492 #endif
00493     }
00494 
00495     void Logger::shutdown() {
00496         if (!d->started)
00497             return;
00498         *this<<Logger::Info<<"Orocos Logging Deactivated." << Logger::endl;
00499         this->logflush();
00500         d->started = false;
00501     }
00502 
00503     std::string Logger::getLogLine() {
00504 #ifdef OROSEM_REMOTE_LOGGING
00505         if (!d->started)
00506             return "";
00507         std::string line;
00508         {
00509             os::MutexLock lock( d->inpguard );
00510             getline( d->remotestream, line );
00511             if ( !d->remotestream )
00512                 d->remotestream.clear();
00513         }
00514         if ( !line.empty() )
00515             --d->messagecnt;
00516         return line;
00517 #else
00518         return "";
00519 #endif
00520     }
00521 
00522     void Logger::setStdStream( std::ostream& stdos ) {
00523 #ifndef OROSEM_PRINTF_LOGGING
00524         d->stdoutput = &stdos;
00525 #endif
00526     }
00527 
00528     Logger& Logger::operator<<( const char* t ) {
00529         if ( !d->maylog() )
00530             return *this;
00531 
00532         os::MutexLock lock( d->inpguard );
00533         if ( d->maylogStdOut() )
00534             d->logline << t;
00535 
00536 #if defined(OROSEM_FILE_LOGGING) || defined(OROSEM_REMOTE_LOGGING)
00537         // log Info or better to log file, even if not started.
00538         if ( d->maylogFile() )
00539             d->fileline << t;
00540 #endif
00541         return *this;
00542     }
00543 
00544     Logger& Logger::operator<<( const std::string& t ) {
00545         return this->operator<<( t.c_str() );
00546     }
00547 
00548     Logger& Logger::operator<<(LogLevel ll) {
00549         if ( !d->maylog() )
00550             return *this;
00551         d->inloglevel = ll;
00552         return *this;
00553     }
00554 
00555     Logger& Logger::operator<<(std::ostream& (*pf)(std::ostream&))
00556     {
00557         if ( !d->maylog() )
00558             return *this;
00559         if ( pf == Logger::endl )
00560             this->logendl();
00561         else if ( pf == Logger::nl )
00562             this->lognl();
00563         else if ( pf == Logger::flush )
00564             this->logflush();
00565         else {
00566             os::MutexLock lock( d->inpguard );
00567             if ( d->maylogStdOut() )
00568                 d->logline << pf; // normal std operator in stream.
00569 #if defined(OROSEM_FILE_LOGGING) || defined(OROSEM_REMOTE_LOGGING)
00570             if ( d->maylogFile() )
00571                 d->fileline << pf;
00572 #endif
00573         }
00574         return *this;
00575     }
00576 
00577     void Logger::logflush() {
00578         if (!d->maylog())
00579             return;
00580         {
00581             // just flush all buffers, do not produce a new logline
00582             os::MutexLock lock( d->inpguard );
00583             if ( d->maylogStdOut() ) {
00584 #ifndef OROSEM_PRINTF_LOGGING
00585                 d->stdoutput->flush();
00586 #endif
00587 #if defined(OROSEM_REMOTE_LOGGING)
00588                 d->remotestream.flush();
00589 #endif
00590             }
00591 #if defined(OROSEM_FILE_LOGGING)
00592             if ( d->maylogFile() ) {
00593 #ifndef OROSEM_PRINTF_LOGGING
00594                 d->logfile.flush();
00595 #endif
00596             }
00597 #endif
00598         }
00599      }
00600 
00601     void Logger::lognl() {
00602         if (!d->maylog())
00603             return;
00604         d->logit( Logger::nl );
00605      }
00606 
00607     void Logger::logendl() {
00608         if (!d->maylog())
00609             return;
00610         d->logit( Logger::endl );
00611      }
00612 
00613     void Logger::setLogLevel( LogLevel ll ) {
00614         d->outloglevel = ll;
00615 #if defined(OROSEM_LOG4CPP_LOGGING)
00616         d->category.setPriority(level2Priority(ll));
00617 #endif
00618     }
00619 
00620     Logger::LogLevel Logger::getLogLevel() const {
00621         return d->outloglevel ;
00622     }
00623 
00624 
00625 #else // OROBLD_DISABLE_LOGGING
00626 
00627     Logger::Logger(std::ostream& )
00628         : d(0)
00629     {
00630     }
00631 
00632     Logger::~Logger()
00633     {
00634     }
00635 
00636 #endif
00637 }


rtt
Author(s): RTT Developers
autogenerated on Wed Aug 26 2015 16:15:49