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 "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
00147 OS::MutexLock lock( inpguard );
00148 std:: string res = showTime() +" " + showLevel(inloglevel) + showModule() + " ";
00149
00150
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("");
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
00169 if ( messagecnt >= ORONUM_LOGGING_BUFSIZE ) {
00170 std::string dummy;
00171 remotestream >> dummy;
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;
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;
00383
00384 int wantedlevel=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
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
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;
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
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 }