Orocos Real-Time Toolkit  2.9.0
Logger.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  tag: Peter Soetens Mon Jan 10 15:59:15 CET 2005 Logger.cxx
3 
4  Logger.cxx - description
5  -------------------
6  begin : Mon January 10 2005
7  copyright : (C) 2005 Peter Soetens
8  email : peter.soetens@mech.kuleuven.ac.be
9 
10  ***************************************************************************
11  * This library is free software; you can redistribute it and/or *
12  * modify it under the terms of the GNU General Public *
13  * License as published by the Free Software Foundation; *
14  * version 2 of the License. *
15  * *
16  * As a special exception, you may use this file as part of a free *
17  * software library without restriction. Specifically, if other files *
18  * instantiate templates or use macros or inline functions from this *
19  * file, or you compile this file and link it with other files to *
20  * produce an executable, this file does not by itself cause the *
21  * resulting executable to be covered by the GNU General Public *
22  * License. This exception does not however invalidate any other *
23  * reasons why the executable file might be covered by the GNU General *
24  * Public License. *
25  * *
26  * This library is distributed in the hope that it will be useful, *
27  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
28  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
29  * Lesser General Public License for more details. *
30  * *
31  * You should have received a copy of the GNU General Public *
32  * License along with this library; if not, write to the Free Software *
33  * Foundation, Inc., 59 Temple Place, *
34  * Suite 330, Boston, MA 02111-1307 USA *
35  * *
36  ***************************************************************************/
37 
38 // to retrieve RTAI version, if any.
39 //#define OROBLD_OS_LXRT_INTERNAL
40 #include "os/StartStopManager.hpp"
41 #include "os/MutexLock.hpp"
42 #include "os/Mutex.hpp"
43 #include "os/TimeService.hpp"
44 
45 #include "Logger.hpp"
46 #include <iomanip>
47 
48 #ifdef OROSEM_PRINTF_LOGGING
49 # include <stdio.h>
50 #else
51 # include <iostream>
52 # include <ostream>
53 # ifdef OROSEM_FILE_LOGGING
54 # include <fstream>
55 # ifdef OROSEM_LOG4CPP_LOGGING
56 # include <log4cpp/Category.hh>
57 # endif
58 # endif
59 # ifdef OROSEM_REMOTE_LOGGING
60 # include "base/BufferLockFree.hpp"
61 # endif
62 #endif
63 
64 #include <stdlib.h>
65 #include "rtt-config.h"
66 #include "rtt-fwd.hpp"
67 
68 namespace RTT
69 {
70  using namespace std;
71  using namespace detail;
72 
73  Logger* Logger::_instance = 0;
74 
75  Logger* Logger::Instance(std::ostream& str) {
76  if (_instance == 0) {
77  _instance = new Logger(str);
78  }
79  return _instance;
80  }
81 
82  void Logger::Release() {
83  if (_instance) {
84  _instance->shutdown();
85  delete _instance;
86  _instance = 0;
87  }
88  }
89 
90 #ifndef OROBLD_DISABLE_LOGGING
91 
92 #ifdef OROSEM_LOG4CPP_LOGGING
93 
94  const std::string Logger::log4cppCategoryName = "org.orocos.rtt";
95 
96  log4cpp::Priority::Value level2Priority(const int logLevel)
97  {
98  log4cpp::Priority::Value value = log4cpp::Priority::NOTSET;
99  switch (logLevel)
100  {
101  case Never: value = log4cpp::Priority::NOTSET; break;
102  case Fatal: value = log4cpp::Priority::FATAL; break;
103  case Critical: value = log4cpp::Priority::CRIT; break;
104  case Error: value = log4cpp::Priority::ERROR; break;
105  case Warning: value = log4cpp::Priority::WARN; break;
106  case Info: value = log4cpp::Priority::INFO; break;
107  case Debug: value = log4cpp::Priority::DEBUG; break;
108  // best we can do!?
109  case RealTime: value = log4cpp::Priority::DEBUG; break;
110  default: value = log4cpp::Priority::NOTSET; break;
111  }
112  return value;
113  }
114 
115 #endif
116 
118  return *Instance();
119  }
120 
122  return Instance()->operator<<( ll );
123  }
124 
128  struct Logger::D
129  {
130  public:
131  D(std::ostream& str, char const* logfile_name) :
132 #ifndef OROSEM_PRINTF_LOGGING
133  stdoutput( &str ),
134 #endif
136  remotestring(ORONUM_LOGGING_BUFSIZE,std::string(), true),
137 #endif
138 #if defined(OROSEM_FILE_LOGGING)
139 #if defined(OROSEM_LOG4CPP_LOGGING)
140  category(log4cpp::Category::getInstance(RTT::Logger::log4cppCategoryName)),
141 #elif !defined(OROSEM_PRINTF_LOGGING)
142  logfile(logfile_name ? logfile_name : "orocos.log"),
143 #endif
144 #endif
145  inloglevel(Info),
146  outloglevel(Warning),
147  timestamp(0),
148  started(false), showtime(true), allowRT(false),
149  mlogStdOut(true), mlogFile(true),
150  moduleptr("Logger")
151  {
152 #if defined(OROSEM_FILE_LOGGING) && !defined(OROSEM_LOG4CPP_LOGGING) && defined(OROSEM_PRINTF_LOGGING)
153  logfile = fopen(logfile_name ? logfile_name : "orocos.log","w");
154 #endif
155  }
156 
157  bool maylog() const {
158  if (!started || (outloglevel == RealTime && allowRT == false))
159  return false;
160  return true;
161  }
162 
163  bool maylogStdOut() const {
164  if ( inloglevel <= outloglevel && outloglevel != Never && inloglevel != Never && mlogStdOut)
165  return true;
166  return false;
167  }
168 
169  bool maylogFile() const {
170  if ( (inloglevel <= Info || inloglevel <= outloglevel) && mlogFile)
171  return true;
172  return false;
173  }
174 
180  void logit(std::ostream& (*pf)(std::ostream&))
181  {
182  // only on Logger::nl or Logger::endl, a time+log-line is written.
183  os::MutexLock lock( inpguard );
184  std:: string res = showTime() +" " + showLevel(inloglevel) + showModule() + " ";
185 
186  // do not log if not wanted.
187  if ( maylogStdOut() ) {
188 #ifndef OROSEM_PRINTF_LOGGING
189  *stdoutput << res << logline.str() << pf;
190 #else
191  printf("%s%s\n", res.c_str(), logline.str().c_str() );
192 #endif
193  logline.str(""); // clear stringstream.
194  }
195 
196  if ( maylogFile() ) {
197 #ifdef OROSEM_FILE_LOGGING
198 #if defined(OROSEM_LOG4CPP_LOGGING)
199  category.log(level2Priority(inloglevel), fileline.str());
200 #elif !defined(OROSEM_PRINTF_LOGGING)
201  logfile << res << fileline.str() << pf;
202 #else
203  fprintf( logfile, "%s%s\n", res.c_str(), fileline.str().c_str() );
204 #endif
205 #ifdef OROSEM_REMOTE_LOGGING
206  remotestring.Push(res+fileline.str()); // TODO, handle failure.
207 #endif
208 #if defined(OROSEM_FILE_LOGGING) || defined(OROSEM_REMOTE_LOGGING)
209  fileline.str("");
210 #endif
211 #endif
212  }
213  }
214 
215 #ifndef OROSEM_PRINTF_LOGGING
216  std::ostream* stdoutput;
217 #endif
218  std::stringstream logline;
219 #if defined(OROSEM_FILE_LOGGING) || defined(OROSEM_REMOTE_LOGGING)
220  std::stringstream fileline;
221 #endif
222 #if defined(OROSEM_REMOTE_LOGGING)
224 #endif
225 #if defined(OROSEM_FILE_LOGGING)
226 #if defined(OROSEM_LOG4CPP_LOGGING)
227  log4cpp::Category& category;
228 #endif
229 # ifndef OROSEM_PRINTF_LOGGING
230  std::ofstream logfile;
231 # else
232  FILE* logfile;
233 # endif
234 #endif
235  LogLevel inloglevel, outloglevel;
236 
238 
240  switch (ll)
241  {
242  case -1:
243  case 0:
244  return Never;
245  case 1:
246  return Fatal;
247  case 2:
248  return Critical;
249  case 3:
250  return Error;
251  case 4:
252  return Warning;
253  case 5:
254  return Info;
255  case 6:
256  return Debug;
257  }
258  return Debug; // > 6
259  }
260 
261 
262  std::string showTime() const
263  {
264  std::stringstream time;
265  if ( showtime )
266  time <<fixed<< showpoint << setprecision(3) << TimeService::Instance()->secondsSince(timestamp);
267  return time.str();
268  }
269 
273  std::string showLevel( LogLevel ll) const {
274  std::string prefix;
275  switch (ll)
276  {
277  case Fatal:
278  prefix="[ FATAL ]";
279  break;
280  case Critical:
281  prefix="[CRITICAL]";
282  break;
283  case Error:
284  prefix="[ ERROR ]";
285  break;
286  case Warning:
287  prefix="[ Warning]";
288  break;
289  case Info:
290  prefix="[ Info ]";
291  break;
292  case Debug:
293  prefix="[ Debug ]";
294  break;
295  case RealTime:
296  prefix="[RealTime]";
297  break;
298  case Never:
299  break;
300  }
301  return prefix;
302  }
303 
304 
305 
306  std::string showModule() const
307  {
308  // moduleptr is protected by lock in logIt()
309  return "["+moduleptr+"]";
310  }
311 
312  bool started;
313 
314  bool showtime;
315 
316  bool allowRT;
317 
318  bool mlogStdOut, mlogFile;
319 
320  std::string moduleptr;
321 
323  };
324 
325  Logger::Logger(std::ostream& str)
326  :d ( new Logger::D(str, getenv("ORO_LOGFILE")) ),
327  inpguard(d->inpguard), logline(d->logline), fileline(d->fileline)
328  {
329  this->startup();
330  }
331 
332  Logger::~Logger()
333  {
334  delete d;
335  }
336 
337  bool Logger::mayLog() const {
338  return d->maylog();
339  }
340 
341  bool Logger::mayLogFile() const {
342  return d->maylogFile();
343  }
344 
345  bool Logger::mayLogStdOut() const {
346  return d->maylogStdOut();
347  }
348 
349  void Logger::mayLogStdOut(bool tf) {
350  d->mlogStdOut = tf;
351  }
352 
353  void Logger::mayLogFile(bool tf) {
354  d->mlogFile = tf;
355  }
356 
358  // re-enable and then log, otherwise you might not get the log event!
359  d->allowRT = true;
360  *this << Logger::Warning << "Enabling Real-Time Logging !" <<Logger::endl;
361  }
363  *this << Logger::Warning << "Disabling Real-Time Logging !" <<Logger::endl;
364  d->allowRT = false;
365  }
366 
368  {
369  return d->timestamp;
370  }
371 
372  std::ostream&
373  Logger::nl(std::ostream& __os)
374  {
375 #ifndef OROSEM_PRINTF_LOGGING
376  return __os.put(__os.widen('\n'));
377 #else
378  return __os;
379 #endif
380  }
381 
382  std::ostream&
383  Logger::endl(std::ostream& __os)
384  {
385 #ifndef OROSEM_PRINTF_LOGGING
386  return flush(__os.put(__os.widen('\n')));
387 #else
388  return __os;
389 #endif
390  }
391 
392  std::ostream&
393  Logger::flush(std::ostream& __os)
394  {
395 #ifndef OROSEM_PRINTF_LOGGING
396  return __os.flush();
397 #else
398  return __os;
399 #endif
400  }
401 
402 
403  Logger::In::In(const std::string& modname)
404  : oldmod( Logger::log().getLogModule() )
405  {
406  Logger::log().in(modname);
407  }
408 
410  {
412  }
413 
414  Logger& Logger::in(const std::string& modname)
415  {
416  if ( !d->maylog() )
417  return *this;
418  os::MutexLock lock( d->inpguard );
419  d->moduleptr = modname.c_str();
420  return *this;
421  }
422 
423  Logger& Logger::out(const std::string& oldmod)
424  {
425  if ( !d->maylog() )
426  return *this;
427  os::MutexLock lock( d->inpguard );
428  d->moduleptr = oldmod.c_str();
429  return *this;
430  }
431 
432  std::string Logger::getLogModule() const {
433  if ( !d->maylog() )
434  return "";
435  os::MutexLock lock( d->inpguard );
436  std::string ret = d->moduleptr.c_str();
437  return ret;
438  }
439 
440 
441 #define ORO_xstr(s) ORO_str(s)
442 #define ORO_str(s) #s
443 
445  if (d->started)
446  return;
447 #ifndef OROBLD_DISABLE_LOGGING
448  std::string xtramsg = "No ORO_LOGLEVEL environment variable set.";
449  *this << Logger::Info; // default log to Info
450 
451  int wantedlevel=4; // default log level is 4.
452 
453  if ( getenv( "ORO_LOGLEVEL" ) != 0 ) {
454  std::stringstream conv;
455  conv.str( std::string( getenv( "ORO_LOGLEVEL" ) ) );
456  conv >> wantedlevel;
457  if ( conv.fail() ) {
458  xtramsg = std::string( "Failed to extract loglevel from environment variable ORO_LOGLEVEL.")
459  + " It contained the string '"+conv.str()+"', while it should contain an integer value.";
460  *this<<Logger::Error;
461  }
462  else {
463  d->outloglevel = d->intToLogLevel(wantedlevel);
464  xtramsg = "Successfully extracted environment variable ORO_LOGLEVEL";
465  }
466  }
467 
468  // Completely disable logging on negative values.
469  if ( wantedlevel < 0 )
470  return;
471  d->started = true;
472 
473  d->timestamp = TimeService::Instance()->getTicks();
474  *this<<xtramsg<<Logger::nl;
475  *this<< " OROCOS version '" ORO_xstr(RTT_VERSION) "'";
476 #ifdef __GNUC__
477  *this << " compiled with GCC " ORO_xstr(__GNUC__) "." ORO_xstr(__GNUC_MINOR__) "." ORO_xstr(__GNUC_PATCHLEVEL__) ".";
478 #endif
479 #ifdef OROPKG_OS_LXRT
480  *this<<" Running in LXRT/RTAI."<< Logger::nl;
481 #endif
482 #ifdef OROPKG_OS_GNULINUX
483  *this<<" Running in GNU/Linux."<< Logger::nl;
484 #endif
485 #ifdef OROPKG_OS_XENOMAI
486  *this<<" Running in Xenomai."<< Logger::nl;
487 #endif
488  *this<<"Orocos Logging Activated at level : " << d->showLevel( d->outloglevel ) << " ( "<<int(d->outloglevel)<<" ) "<< Logger::nl;
489  *this<<"Reference System Time is : " << d->timestamp << " ticks ( "<< Seconds(TimeService::ticks2nsecs(d->timestamp))/NSECS_IN_SECS <<" seconds )." << Logger::nl;
490  *this<<"Logging is relative to this time." <<Logger::endl;
491 #endif
492  }
493 
495  if (!d->started)
496  return;
497  *this<<Logger::Info<<"Orocos Logging Deactivated." << Logger::endl;
498  this->logflush();
499  d->started = false;
500  }
501 
502  std::string Logger::getLogLine() {
503 #ifdef OROSEM_REMOTE_LOGGING
504  if (!d->started)
505  return "";
506 
507  os::MutexLock lock( d->inpguard );
508  std::string line;
509  if(d->remotestring.Pop(line))
510  return line;
511  else
512  return "";
513 #else
514  return "";
515 #endif
516  }
517 
518  void Logger::setStdStream( std::ostream& stdos ) {
519 #ifndef OROSEM_PRINTF_LOGGING
520  d->stdoutput = &stdos;
521 #endif
522  }
523 
524  Logger& Logger::operator<<( const char* t ) {
525  if ( !d->maylog() )
526  return *this;
527 
528  os::MutexLock lock( d->inpguard );
529  if ( d->maylogStdOut() )
530  d->logline << t;
531 
532 #if defined(OROSEM_FILE_LOGGING) || defined(OROSEM_REMOTE_LOGGING)
533  // log Info or better to log file, even if not started.
534  if ( d->maylogFile() )
535  d->fileline << t;
536 #endif
537  return *this;
538  }
539 
540  Logger& Logger::operator<<( const std::string& t ) {
541  return this->operator<<( t.c_str() );
542  }
543 
545  if ( !d->maylog() )
546  return *this;
547  d->inloglevel = ll;
548  return *this;
549  }
550 
551  Logger& Logger::operator<<(std::ostream& (*pf)(std::ostream&))
552  {
553  if ( !d->maylog() )
554  return *this;
555  if ( pf == Logger::endl )
556  this->logendl();
557  else if ( pf == Logger::nl )
558  this->lognl();
559  else if ( pf == Logger::flush )
560  this->logflush();
561  else {
562  os::MutexLock lock( d->inpguard );
563  if ( d->maylogStdOut() )
564  d->logline << pf; // normal std operator in stream.
565 #if defined(OROSEM_FILE_LOGGING) || defined(OROSEM_REMOTE_LOGGING)
566  if ( d->maylogFile() )
567  d->fileline << pf;
568 #endif
569  }
570  return *this;
571  }
572 
574  if (!d->maylog())
575  return;
576  {
577  // just flush all buffers, do not produce a new logline
578  os::MutexLock lock( d->inpguard );
579  if ( d->maylogStdOut() ) {
580 #ifndef OROSEM_PRINTF_LOGGING
581  d->stdoutput->flush();
582 #endif
583  }
584 #if defined(OROSEM_FILE_LOGGING)
585  if ( d->maylogFile() ) {
586 #ifndef OROSEM_PRINTF_LOGGING
587  d->logfile.flush();
588 #endif
589  }
590 #endif
591  }
592  }
593 
594  void Logger::lognl() {
595  if (!d->maylog())
596  return;
597  d->logit( Logger::nl );
598  }
599 
601  if (!d->maylog())
602  return;
603  d->logit( Logger::endl );
604  }
605 
607  d->outloglevel = ll;
608 #if defined(OROSEM_LOG4CPP_LOGGING)
609  d->category.setPriority(level2Priority(ll));
610 #endif
611  }
612 
614  return d->outloglevel ;
615  }
616 
617 
618 #else // OROBLD_DISABLE_LOGGING
619 
620  Logger::Logger(std::ostream& )
621  : d(0)
622  {
623  }
624 
625  Logger::~Logger()
626  {
627  }
628 
629 #endif
630 }
Logger & out(const std::string &modname)
The counterpart of in().
Definition: Logger.cpp:423
std::string getLogModule() const
Get the name of the current Log generating Module.
Definition: Logger.cpp:432
std::string showTime() const
Definition: Logger.cpp:262
const long NSECS_IN_SECS
Definition: Time.hpp:77
bool maylogStdOut() const
Definition: Logger.cpp:163
D(std::ostream &str, char const *logfile_name)
Definition: Logger.cpp:131
double Seconds
Seconds are stored as a double precision float.
Definition: Time.hpp:53
#define RTT_VERSION
Definition: rtt-config.h:4
bool maylog() const
Definition: Logger.cpp:157
std::string moduleptr
Definition: Logger.cpp:320
A Lock-free buffer implementation to read and write data of type T in a FIFO way. ...
#define ORONUM_LOGGING_BUFSIZE
static nsecs ticks2nsecs(const ticks t)
Convert an amount of ticks to nano seconds.
Definition: TimeService.cpp:36
TimeService::ticks timestamp
Definition: Logger.cpp:237
LogLevel getLogLevel() const
Return the current output loglevel.
Definition: Logger.cpp:613
std::string showLevel(LogLevel ll) const
Convert a loglevel to a string representation.
Definition: Logger.cpp:273
long long ticks
The type for the systems clock tick.
Definition: TimeService.hpp:66
static Logger * Instance(std::ostream &str=std::cerr)
Get the singleton logger.
Definition: Logger.cpp:75
bool mlogStdOut
Definition: Logger.cpp:318
void shutdown()
Print a &#39;goodbye&#39; string in Info, Flush all streams and stop Logging.
Definition: Logger.cpp:494
#define OROSEM_FILE_LOGGING
static std::ostream & nl(std::ostream &__os)
Insert a newline &#39; &#39; in the ostream.
Definition: Logger.cpp:373
STL namespace.
#define OROSEM_REMOTE_LOGGING
This hidden struct stores all data structures required for logging.
Definition: Logger.cpp:128
Logger & operator<<(const T &t)
Send (user defined) data into this logger.
Definition: Logger.inl:15
void logflush()
Flush log buffers.
Definition: Logger.cpp:573
Seconds secondsSince(ticks relativeTime) const
Get Seconds passed since a certain moment.
A simple logging class to debug/ analyse what is going on in the Orocos system.
Definition: Logger.hpp:95
static TimeService * Instance()
Definition: TimeService.cpp:41
void logit(std::ostream &(*pf)(std::ostream &))
This function is called when a new message is ready to be written to screen, disk, or stream.
Definition: Logger.cpp:180
std::stringstream logline
Definition: Logger.cpp:218
std::string oldmod
Definition: Logger.hpp:162
LogLevel outloglevel
Definition: Logger.cpp:235
void startup()
Print a &#39;welcome&#39; string in Info and reset log timestamp.
Definition: Logger.cpp:444
std::string getLogLine()
This method gets all messages upto level Info and can be freely read by the user, removing the line f...
Definition: Logger.cpp:502
void disallowRealTime()
Disallow messages of the LogLevel &#39;RealTime&#39; to appear on the console.
Definition: Logger.cpp:362
#define ORO_xstr(s)
Definition: Logger.cpp:441
static std::ostream & flush(std::ostream &__os)
Flush the output stream.
Definition: Logger.cpp:393
static std::ostream & endl(std::ostream &__os)
Definition: Logger.cpp:383
os::Mutex inpguard
Definition: Logger.cpp:322
void lognl()
Add newline without flushing buffers.
Definition: Logger.cpp:594
In(const std::string &module)
Definition: Logger.cpp:403
std::string showModule() const
Definition: Logger.cpp:306
LogLevel
Enumerate all log-levels from absolute silence to everything.
Definition: Logger.hpp:121
static Logger & log()
As Instance(), but more userfriendly.
Definition: Logger.cpp:117
void allowRealTime()
Allow messages of the LogLevel &#39;RealTime&#39; to appear on the console.
Definition: Logger.cpp:357
std::ostream * stdoutput
Definition: Logger.cpp:216
bool maylogFile() const
Definition: Logger.cpp:169
static void Release()
Delete the singleton logger.
Definition: Logger.cpp:82
An object oriented wrapper around a non recursive mutex.
Definition: Mutex.hpp:92
Contains TaskContext, Activity, OperationCaller, Operation, Property, InputPort, OutputPort, Attribute.
Definition: Activity.cpp:52
void setStdStream(std::ostream &stdos)
Set the standard output stream.
Definition: Logger.cpp:518
void logendl()
Add endl and flush buffers.
Definition: Logger.cpp:600
Logger & in(const std::string &modname)
Inform the Logger of the entry of a module.
Definition: Logger.cpp:414
Logger::LogLevel intToLogLevel(int ll)
Definition: Logger.cpp:239
void setLogLevel(LogLevel ll)
Set the loglevel of the outgoing (streamed) messages.
Definition: Logger.cpp:606
os::TimeService::ticks getReferenceTime() const
Function to get the loggers starting timestamp.
Definition: Logger.cpp:367
MutexLock is a scope based Monitor, protecting critical sections with a Mutex object through locking ...
Definition: MutexLock.hpp:51
ticks getTicks() const
Get current tick of the System clock.