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