IBR-DTNSuite 0.6

ibrcommon/ibrcommon/Logger.cpp

Go to the documentation of this file.
00001 /*
00002  * Logger.cpp
00003  *
00004  *  Created on: 08.06.2010
00005  *      Author: morgenro
00006  */
00007 
00008 #include "ibrcommon/Logger.h"
00009 #include "ibrcommon/SyslogStream.h"
00010 #include <algorithm>
00011 #include <sys/time.h>
00012 #include <ibrcommon/thread/Mutex.h>
00013 #include <ibrcommon/thread/MutexLock.h>
00014 #include <iomanip>
00015 
00016 
00017 namespace ibrcommon
00018 {
00019         Logger::LogWriter Logger::_logwriter;
00020 
00021         Logger::Logger(LogLevel level, int debug_verbosity)
00022          : _level(level), _debug_verbosity(debug_verbosity)
00023         {
00024                 ::gettimeofday(&_logtime, NULL);
00025         }
00026 
00027         Logger::Logger(const Logger &obj)
00028          : std::stringstream(obj.str()), _level(obj._level), _debug_verbosity(obj._debug_verbosity), _logtime(obj._logtime)
00029         {
00030         }
00031 
00032         Logger::~Logger()
00033         {
00034         }
00035 
00036         Logger Logger::emergency()
00037         {
00038                 return Logger(LOGGER_EMERG);
00039         }
00040 
00041         Logger Logger::alert()
00042         {
00043                 return Logger(LOGGER_ALERT);
00044         }
00045 
00046         Logger Logger::critical()
00047         {
00048                 return Logger(LOGGER_CRIT);
00049         }
00050 
00051         Logger Logger::error()
00052         {
00053                 return Logger(LOGGER_ERR);
00054         }
00055 
00056         Logger Logger::warning()
00057         {
00058                 return Logger(LOGGER_WARNING);
00059         }
00060 
00061         Logger Logger::notice()
00062         {
00063                 return Logger(LOGGER_NOTICE);
00064         }
00065 
00066         Logger Logger::info()
00067         {
00068                 return Logger(LOGGER_INFO);
00069         }
00070 
00071         Logger Logger::debug(int verbosity)
00072         {
00073                 return Logger(LOGGER_DEBUG, verbosity);
00074         }
00075 
00076         void Logger::setVerbosity(const int verbosity)
00077         {
00078                 Logger::_logwriter.setVerbosity(verbosity);
00079         }
00080 
00081         void Logger::LogWriter::setVerbosity(const int verbosity)
00082         {
00083                 _verbosity = verbosity;
00084         }
00085 
00086         int Logger::getVerbosity()
00087         {
00088                 return Logger::_logwriter.getVerbosity();
00089         }
00090 
00091         int Logger::LogWriter::getVerbosity()
00092         {
00093                 return _verbosity;
00094         }
00095 
00096         void Logger::addStream(std::ostream &stream, const unsigned char logmask, const unsigned char options)
00097         {
00098                 Logger::_logwriter.addStream(stream, logmask, options);
00099         }
00100 
00101         void Logger::LogWriter::addStream(std::ostream &stream, const unsigned char logmask, const unsigned char options)
00102         {
00103                 _logger.push_back( Logger::LoggerOutput(stream, logmask, options) );
00104         }
00105 
00106         void Logger::enableSyslog(const char *name, int option, int facility, const unsigned char logmask)
00107         {
00108                 Logger::_logwriter.enableSyslog(name, option, facility, logmask);
00109         }
00110 
00111         void Logger::print()
00112         {
00113                 Logger::_logwriter.log(*this);
00114         }
00115 
00116         void Logger::LogWriter::enableSyslog(const char *name, int option, int facility, const unsigned char logmask)
00117         {
00118                 // init syslog
00119                 ::openlog(name, option, facility);
00120                 _syslog = true;
00121                 _syslog_mask = logmask;
00122         }
00123 
00124         void Logger::LogWriter::flush(const Logger &logger)
00125         {
00126                 if (_verbosity >= logger._debug_verbosity)
00127                 {
00128                         for (std::list<LoggerOutput>::iterator iter = _logger.begin(); iter != _logger.end(); iter++)
00129                         {
00130                                 LoggerOutput &output = (*iter);
00131                                 output.log(logger);
00132                         }
00133 
00134                         // additionally log to the syslog
00135                         if (_syslog)
00136                         {
00137                                 if (logger._level & _syslog_mask)
00138                                 {
00139                                         switch (logger._level)
00140                                         {
00141                                         case LOGGER_EMERG:
00142                                                 ::syslog( LOG_EMERG, "%s", logger.str().c_str() );
00143                                                 break;
00144 
00145                                         case LOGGER_ALERT:
00146                                                 ::syslog( LOG_ALERT, "%s", logger.str().c_str() );
00147                                                 break;
00148 
00149                                         case LOGGER_CRIT:
00150                                                 ::syslog( LOG_CRIT, "%s", logger.str().c_str() );
00151                                                 break;
00152 
00153                                         case LOGGER_ERR:
00154                                                 ::syslog( LOG_ERR, "%s", logger.str().c_str() );
00155                                                 break;
00156 
00157                                         case LOGGER_WARNING:
00158                                                 ::syslog( LOG_WARNING, "%s", logger.str().c_str() );
00159                                                 break;
00160 
00161                                         case LOGGER_NOTICE:
00162                                                 ::syslog( LOG_NOTICE, "%s", logger.str().c_str() );
00163                                                 break;
00164 
00165                                         case LOGGER_INFO:
00166                                                 ::syslog( LOG_INFO, "%s", logger.str().c_str() );
00167                                                 break;
00168 
00169                                         case LOGGER_DEBUG:
00170                                                 ::syslog( LOG_DEBUG, "%s", logger.str().c_str() );
00171                                                 break;
00172 
00173                                         default:
00174                                                 ::syslog( LOG_NOTICE, "%s", logger.str().c_str() );
00175                                                 break;
00176                                         }
00177                                 }
00178                         }
00179                 }
00180         }
00181 
00182         void Logger::LoggerOutput::log(const Logger &log)
00183         {
00184                 if (_level & log._level)
00185                 {
00186                         std::list<std::string> prefixes;
00187 
00188                         // check for prefixes
00189                         if (_options & LOG_DATETIME)
00190                         {
00191                                 // get timestamp
00192                                 time_t ltime; /* calendar time */
00193                                 ltime=time(NULL); /* get current cal time */
00194                                 std::string timestamp(asctime( localtime(&ltime) ));
00195                                 timestamp.erase(std::remove(timestamp.begin(), timestamp.end(), '\n'), timestamp.end());
00196                                 prefixes.push_back(timestamp);
00197                         }
00198 
00199                         // check for prefixes
00200                         if (_options & LOG_TIMESTAMP)
00201                         {
00202                                 std::stringstream ss;
00203                                 ss.fill('0');
00204                                 ss << log._logtime.tv_sec << "." << std::setw(6) << log._logtime.tv_usec;
00205                                 prefixes.push_back(ss.str());
00206                         }
00207 
00208                         if (_options & LOG_LEVEL)
00209                         {
00210                                 // print log level
00211                                 switch (log._level)
00212                                 {
00213                                         case LOGGER_EMERG:
00214                                                 prefixes.push_back("EMERGENCY");
00215                                                 break;
00216 
00217                                         case LOGGER_ALERT:
00218                                                 prefixes.push_back("ALERT");
00219                                                 break;
00220 
00221                                         case LOGGER_CRIT:
00222                                                 prefixes.push_back("CRTITICAL");
00223                                                 break;
00224 
00225                                         case LOGGER_ERR:
00226                                                 prefixes.push_back("ERROR");
00227                                                 break;
00228 
00229                                         case LOGGER_WARNING:
00230                                                 prefixes.push_back("WARNING");
00231                                                 break;
00232 
00233                                         case LOGGER_NOTICE:
00234                                                 prefixes.push_back("NOTICE");
00235                                                 break;
00236 
00237                                         case LOGGER_INFO:
00238                                                 prefixes.push_back("INFO");
00239                                                 break;
00240 
00241                                         case LOGGER_DEBUG:
00242                                         {
00243                                                 std::stringstream ss;
00244                                                 ss << "DEBUG." << log._debug_verbosity;
00245                                                 prefixes.push_back(ss.str());
00246                                                 break;
00247                                         }
00248 
00249                                         default:
00250                                                 break;
00251                                 }
00252                         }
00253 
00254                         if (_options & LOG_HOSTNAME)
00255                         {
00256                                 char *hostname_array = new char[64];
00257                                 if ( gethostname(hostname_array, 64) == 0 )
00258                                 {
00259                                         std::string hostname(hostname_array);
00260                                         prefixes.push_back(hostname);
00261                                 }
00262 
00263                                 delete[] hostname_array;
00264                         }
00265 
00266                         // print prefixes
00267                         for (std::list<std::string>::const_iterator iter = prefixes.begin(); iter != prefixes.end(); iter++)
00268                         {
00269                                 if (iter == prefixes.begin())
00270                                 {
00271                                         _stream << (*iter);
00272                                 }
00273                                 else
00274                                 {
00275                                         _stream << " " << (*iter);
00276                                 }
00277                         }
00278 
00279                         if (!prefixes.empty())
00280                         {
00281                                 _stream << ": ";
00282                         }
00283 
00284                         _stream << log.str() << std::endl;
00285                 }
00286         }
00287 
00288         Logger::LoggerOutput::LoggerOutput(std::ostream &stream, const unsigned char logmask, const unsigned char options)
00289          : _stream(stream), _level(logmask), _options(options)
00290         {
00291         }
00292 
00293         Logger::LoggerOutput::~LoggerOutput()
00294         {
00295         }
00296 
00297         void Logger::enableAsync()
00298         {
00299                 Logger::_logwriter.enableAsync();
00300         }
00301 
00302         void Logger::LogWriter::enableAsync()
00303         {
00304                 try {
00305                         _use_queue = true;
00306                         start();
00307                 } catch (const ibrcommon::ThreadException &ex) {
00308                         IBRCOMMON_LOGGER(error) << "failed to start LogWriter\n" << ex.what() << IBRCOMMON_LOGGER_ENDL;
00309                 }
00310         }
00311         
00312         void Logger::stop()
00313         {
00314                 // stop the LogWriter::run() thread (this is needed with uclibc)
00315                 _logwriter.stop();
00316         }
00317 
00318         Logger::LogWriter::LogWriter()
00319          : _verbosity(0), _syslog(0), _syslog_mask(0), _queue(50), _use_queue(false)
00320         // limit queue to 50 entries
00321         {
00322         }
00323 
00324         Logger::LogWriter::~LogWriter()
00325         {
00326                 // do cleanup only if the thread was running before
00327                 if (_use_queue) stop();
00328 
00329                 // join the LogWriter::run() thread
00330                 join();
00331         }
00332 
00333         void Logger::LogWriter::log(Logger &logger)
00334         {
00335                 if (_use_queue)
00336                 {
00337                         _queue.push(logger);
00338                 }
00339                 else
00340                 {
00341                         flush(logger);
00342                 }
00343         }
00344 
00345         void Logger::LogWriter::run()
00346         {
00347                 try {
00348                         while (true)
00349                         {
00350                                 Logger log = _queue.getnpop(true);
00351                                 flush(log);
00352                         }
00353                 } catch (const std::exception&) {
00354                         ibrcommon::Queue<Logger>::Locked q = _queue.exclusive();
00355 
00356                         try {
00357                                 // In this block we will write all remaining element in the queue
00358                                 // to the logging streams. While we do this, the queue should be locked
00359                                 // and finally we abort the queue to unblock all waiting threads.
00360                                 while (!q.empty())
00361                                 {
00362                                         Logger &log = q.front();
00363                                         try { log.flush(); } catch (...) {};
00364                                         q.pop();
00365                                 }
00366                         } catch (const std::exception&) {
00367 
00368                         }
00369                 }
00370         }
00371 
00372         bool Logger::LogWriter::__cancellation()
00373         {
00374                 // cancel the main thread in here
00375                 _queue.abort();
00376 
00377                 // return true, to signal that no further cancel (the hardway) is needed
00378                 return true;
00379         }
00380 }