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 # 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
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
00183 os::MutexLock lock( inpguard );
00184 std:: string res = showTime() +" " + showLevel(inloglevel) + showModule() + " ";
00185
00186
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("");
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
00207 if ( messagecnt >= ORONUM_LOGGING_BUFSIZE ) {
00208 std::string dummy;
00209 remotestream >> dummy;
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;
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
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;
00451
00452 int wantedlevel=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
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
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;
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
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 }