IBR-DTNSuite  0.8
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 #include <unistd.h>
00016 
00017 
00018 namespace ibrcommon
00019 {
00020         Logger::LogWriter Logger::_logwriter;
00021 
00022         Logger::Logger(LogLevel level, int debug_verbosity)
00023          : _level(level), _debug_verbosity(debug_verbosity)
00024         {
00025                 ::gettimeofday(&_logtime, NULL);
00026         }
00027 
00028         Logger::Logger(const Logger &obj)
00029          : std::stringstream(obj.str()), _level(obj._level), _debug_verbosity(obj._debug_verbosity), _logtime(obj._logtime)
00030         {
00031         }
00032 
00033         Logger::~Logger()
00034         {
00035         }
00036 
00037         Logger Logger::emergency()
00038         {
00039                 return Logger(LOGGER_EMERG);
00040         }
00041 
00042         Logger Logger::alert()
00043         {
00044                 return Logger(LOGGER_ALERT);
00045         }
00046 
00047         Logger Logger::critical()
00048         {
00049                 return Logger(LOGGER_CRIT);
00050         }
00051 
00052         Logger Logger::error()
00053         {
00054                 return Logger(LOGGER_ERR);
00055         }
00056 
00057         Logger Logger::warning()
00058         {
00059                 return Logger(LOGGER_WARNING);
00060         }
00061 
00062         Logger Logger::notice()
00063         {
00064                 return Logger(LOGGER_NOTICE);
00065         }
00066 
00067         Logger Logger::info()
00068         {
00069                 return Logger(LOGGER_INFO);
00070         }
00071 
00072         Logger Logger::debug(int verbosity)
00073         {
00074                 return Logger(LOGGER_DEBUG, verbosity);
00075         }
00076 
00077         void Logger::setVerbosity(const int verbosity)
00078         {
00079                 Logger::_logwriter.setVerbosity(verbosity);
00080         }
00081 
00082         void Logger::LogWriter::setVerbosity(const int verbosity)
00083         {
00084                 _verbosity = verbosity;
00085         }
00086 
00087         int Logger::getVerbosity()
00088         {
00089                 return Logger::_logwriter.getVerbosity();
00090         }
00091 
00092         int Logger::LogWriter::getVerbosity()
00093         {
00094                 return _verbosity;
00095         }
00096 
00097         void Logger::addStream(std::ostream &stream, const unsigned char logmask, const unsigned char options)
00098         {
00099                 Logger::_logwriter.addStream(stream, logmask, options);
00100         }
00101 
00102         void Logger::setLogfile(const ibrcommon::File &logfile, const unsigned char logmask, const unsigned char options)
00103         {
00104                 Logger::_logwriter.setLogfile(logfile, logmask, options);
00105         }
00106 
00107         void Logger::LogWriter::addStream(std::ostream &stream, const unsigned char logmask, const unsigned char options)
00108         {
00109                 _logger.push_back( Logger::LoggerOutput(stream, logmask, options) );
00110         }
00111 
00112         void Logger::enableSyslog(const char *name, int option, int facility, const unsigned char logmask)
00113         {
00114                 Logger::_logwriter.enableSyslog(name, option, facility, logmask);
00115         }
00116 
00117         void Logger::print()
00118         {
00119                 Logger::_logwriter.log(*this);
00120         }
00121 
00122         void Logger::LogWriter::enableSyslog(const char *name, int option, int facility, const unsigned char logmask)
00123         {
00124                 // init syslog
00125                 ::openlog(name, option, facility);
00126                 _syslog = true;
00127                 _syslog_mask = logmask;
00128         }
00129 
00130         void Logger::LogWriter::flush(const Logger &logger)
00131         {
00132                 if (_verbosity >= logger._debug_verbosity)
00133                 {
00134                         for (std::list<LoggerOutput>::iterator iter = _logger.begin(); iter != _logger.end(); iter++)
00135                         {
00136                                 LoggerOutput &output = (*iter);
00137                                 output.log(logger);
00138                         }
00139 
00140                         // output to logfile
00141                         {
00142                                 ibrcommon::MutexLock l(_logfile_mutex);
00143                                 if (_logfile_output != NULL)
00144                                 {
00145                                         _logfile_output->log(logger);
00146                                 }
00147                         }
00148 
00149                         // additionally log to the syslog
00150                         if (_syslog)
00151                         {
00152                                 if (logger._level & _syslog_mask)
00153                                 {
00154                                         switch (logger._level)
00155                                         {
00156                                         case LOGGER_EMERG:
00157                                                 ::syslog( LOG_EMERG, "%s", logger.str().c_str() );
00158                                                 break;
00159 
00160                                         case LOGGER_ALERT:
00161                                                 ::syslog( LOG_ALERT, "%s", logger.str().c_str() );
00162                                                 break;
00163 
00164                                         case LOGGER_CRIT:
00165                                                 ::syslog( LOG_CRIT, "%s", logger.str().c_str() );
00166                                                 break;
00167 
00168                                         case LOGGER_ERR:
00169                                                 ::syslog( LOG_ERR, "%s", logger.str().c_str() );
00170                                                 break;
00171 
00172                                         case LOGGER_WARNING:
00173                                                 ::syslog( LOG_WARNING, "%s", logger.str().c_str() );
00174                                                 break;
00175 
00176                                         case LOGGER_NOTICE:
00177                                                 ::syslog( LOG_NOTICE, "%s", logger.str().c_str() );
00178                                                 break;
00179 
00180                                         case LOGGER_INFO:
00181                                                 ::syslog( LOG_INFO, "%s", logger.str().c_str() );
00182                                                 break;
00183 
00184                                         case LOGGER_DEBUG:
00185                                                 ::syslog( LOG_DEBUG, "%s", logger.str().c_str() );
00186                                                 break;
00187 
00188                                         default:
00189                                                 ::syslog( LOG_NOTICE, "%s", logger.str().c_str() );
00190                                                 break;
00191                                         }
00192                                 }
00193                         }
00194                 }
00195         }
00196 
00197         void Logger::LoggerOutput::log(const Logger &log)
00198         {
00199                 if (_level & log._level)
00200                 {
00201                         std::list<std::string> prefixes;
00202 
00203                         // check for prefixes
00204                         if (_options & LOG_DATETIME)
00205                         {
00206                                 // get timestamp
00207                                 std::string timestamp(asctime( localtime(&log._logtime.tv_sec) ));
00208                                 timestamp.erase(std::remove(timestamp.begin(), timestamp.end(), '\n'), timestamp.end());
00209                                 prefixes.push_back(timestamp);
00210                         }
00211 
00212                         // check for prefixes
00213                         if (_options & LOG_TIMESTAMP)
00214                         {
00215                                 std::stringstream ss;
00216                                 ss.fill('0');
00217                                 ss << log._logtime.tv_sec << "." << std::setw(6) << log._logtime.tv_usec;
00218                                 prefixes.push_back(ss.str());
00219                         }
00220 
00221                         if (_options & LOG_LEVEL)
00222                         {
00223                                 // print log level
00224                                 switch (log._level)
00225                                 {
00226                                         case LOGGER_EMERG:
00227                                                 prefixes.push_back("EMERGENCY");
00228                                                 break;
00229 
00230                                         case LOGGER_ALERT:
00231                                                 prefixes.push_back("ALERT");
00232                                                 break;
00233 
00234                                         case LOGGER_CRIT:
00235                                                 prefixes.push_back("CRTITICAL");
00236                                                 break;
00237 
00238                                         case LOGGER_ERR:
00239                                                 prefixes.push_back("ERROR");
00240                                                 break;
00241 
00242                                         case LOGGER_WARNING:
00243                                                 prefixes.push_back("WARNING");
00244                                                 break;
00245 
00246                                         case LOGGER_NOTICE:
00247                                                 prefixes.push_back("NOTICE");
00248                                                 break;
00249 
00250                                         case LOGGER_INFO:
00251                                                 prefixes.push_back("INFO");
00252                                                 break;
00253 
00254                                         case LOGGER_DEBUG:
00255                                         {
00256                                                 std::stringstream ss;
00257                                                 ss << "DEBUG." << log._debug_verbosity;
00258                                                 prefixes.push_back(ss.str());
00259                                                 break;
00260                                         }
00261 
00262                                         default:
00263                                                 break;
00264                                 }
00265                         }
00266 
00267                         if (_options & LOG_HOSTNAME)
00268                         {
00269                                 char *hostname_array = new char[64];
00270                                 if ( gethostname(hostname_array, 64) == 0 )
00271                                 {
00272                                         std::string hostname(hostname_array);
00273                                         prefixes.push_back(hostname);
00274                                 }
00275 
00276                                 delete[] hostname_array;
00277                         }
00278 
00279                         // print prefixes
00280                         for (std::list<std::string>::const_iterator iter = prefixes.begin(); iter != prefixes.end(); iter++)
00281                         {
00282                                 if (iter == prefixes.begin())
00283                                 {
00284                                         _stream << (*iter);
00285                                 }
00286                                 else
00287                                 {
00288                                         _stream << " " << (*iter);
00289                                 }
00290                         }
00291 
00292                         if (!prefixes.empty())
00293                         {
00294                                 _stream << ": ";
00295                         }
00296 
00297                         _stream << log.str() << std::endl;
00298                 }
00299         }
00300 
00301         Logger::LoggerOutput::LoggerOutput(std::ostream &stream, const unsigned char logmask, const unsigned char options)
00302          : _stream(stream), _level(logmask), _options(options)
00303         {
00304         }
00305 
00306         Logger::LoggerOutput::~LoggerOutput()
00307         {
00308         }
00309 
00310         void Logger::enableAsync()
00311         {
00312                 Logger::_logwriter.enableAsync();
00313         }
00314 
00315         void Logger::enableBuffer(size_t size)
00316         {
00317                 Logger::_logwriter.enableBuffer(size);
00318         }
00319 
00320         void Logger::writeBuffer(std::ostream &stream)
00321         {
00322                 unsigned char logmask = ibrcommon::Logger::LOGGER_ALL;
00323                 unsigned char options = ibrcommon::Logger::LOG_DATETIME | ibrcommon::Logger::LOG_LEVEL;
00324 
00325                 Logger::_logwriter.writeBuffer(stream, logmask, options);
00326         }
00327 
00328         void Logger::LogWriter::enableAsync()
00329         {
00330                 try {
00331                         _use_queue = true;
00332                         start();
00333                 } catch (const ibrcommon::ThreadException &ex) {
00334                         IBRCOMMON_LOGGER(error) << "failed to start LogWriter\n" << ex.what() << IBRCOMMON_LOGGER_ENDL;
00335                 }
00336         }
00337         
00338         void Logger::stop()
00339         {
00340                 // stop the LogWriter::run() thread (this is needed with uclibc)
00341                 _logwriter.stop();
00342         }
00343 
00344         void Logger::reload()
00345         {
00346                 //reload the logger
00347                 _logwriter.reload();
00348         }
00349 
00350         Logger::LogWriter::LogWriter()
00351          : _verbosity(0), _syslog(0), _syslog_mask(0), _queue(50), _use_queue(false), _buffer_size(0), _buffer(NULL),
00352            _logfile_output(NULL), _logfile_logmask(0), _logfile_options(0)
00353         // limit queue to 50 entries
00354         {
00355         }
00356 
00357         Logger::LogWriter::~LogWriter()
00358         {
00359                 // do cleanup only if the thread was running before
00360                 if (_use_queue) stop();
00361 
00362                 // join the LogWriter::run() thread
00363                 join();
00364 
00365                 // remove the ring-buffer
00366                 ibrcommon::MutexLock l(_buffer_mutex);
00367                 if (_buffer != NULL) delete _buffer;
00368         }
00369 
00370         void Logger::LogWriter::enableBuffer(size_t size)
00371         {
00372                 ibrcommon::MutexLock l(_buffer_mutex);
00373                 _buffer_size = size;
00374                 _buffer = new std::list<Logger>();
00375         }
00376 
00377         void Logger::LogWriter::setLogfile(const ibrcommon::File &logfile, const unsigned char logmask, const unsigned char options)
00378         {
00379                 ibrcommon::MutexLock l(_logfile_mutex);
00380                 if (_logfile_output != NULL)
00381                 {
00382                         // delete the old logger
00383                         delete _logfile_output;
00384                         _logfile_output = NULL;
00385 
00386                         // close the output file
00387                         _logfile_stream.close();
00388                 }
00389 
00390                 _logfile = logfile;
00391                 _logfile_logmask = logmask;
00392                 _logfile_options = options;
00393 
00394                 // open the new logfile
00395                 _logfile_stream.open(_logfile.getPath().c_str(), std::ios::out | std::ios::app);
00396 
00397                 // create a new logger output
00398                 if (_logfile_stream.good())
00399                 {
00400                         _logfile_output = new LoggerOutput(_logfile_stream, _logfile_logmask, _logfile_options);
00401                 }
00402                 else
00403                 {
00404                         _logfile_stream.close();
00405                 }
00406         }
00407 
00408         void Logger::LogWriter::reload()
00409         {
00410                 ibrcommon::MutexLock l(_logfile_mutex);
00411                 if (_logfile_output != NULL)
00412                 {
00413                         // delete the old logger
00414                         delete _logfile_output;
00415                         _logfile_output = NULL;
00416 
00417                         // close the output file
00418                         _logfile_stream.close();
00419 
00420                         // open the new logfile
00421                         _logfile_stream.open(_logfile.getPath().c_str(), std::ios::out | std::ios::app);
00422 
00423                         // create a new logger output
00424                         if (_logfile_stream.good())
00425                         {
00426                                 _logfile_output = new LoggerOutput(_logfile_stream, _logfile_logmask, _logfile_options);
00427                         }
00428                         else
00429                         {
00430                                 _logfile_stream.close();
00431                         }
00432                 }
00433         }
00434 
00435         void Logger::LogWriter::writeBuffer(std::ostream &stream, const unsigned char logmask, const unsigned char options)
00436         {
00437                 ibrcommon::MutexLock l(_buffer_mutex);
00438                 if (_buffer == NULL) return;
00439 
00440                 LoggerOutput output(stream, logmask, options);
00441 
00442                 for (std::list<Logger>::const_iterator iter = _buffer->begin(); iter != _buffer->end(); iter++)
00443                 {
00444                         const Logger &l = (*iter);
00445                         output.log(l);
00446                 }
00447         }
00448 
00449         void Logger::LogWriter::log(Logger &logger)
00450         {
00451                 if (_use_queue)
00452                 {
00453                         _queue.push(logger);
00454                 }
00455                 else
00456                 {
00457                         flush(logger);
00458                 }
00459         }
00460 
00461         void Logger::LogWriter::run()
00462         {
00463                 try {
00464                         while (true)
00465                         {
00466                                 Logger log = _queue.getnpop(true);
00467                                 flush(log);
00468 
00469                                 // add to ring-buffer
00470                                 ibrcommon::MutexLock l(_buffer_mutex);
00471                                 if (_buffer != NULL)
00472                                 {
00473                                         _buffer->push_back(log);
00474                                         while (_buffer->size() > _buffer_size)
00475                                         {
00476                                                 _buffer->pop_front();
00477                                         }
00478                                 }
00479                         }
00480                 } catch (const std::exception&) {
00481                         ibrcommon::Queue<Logger>::Locked q = _queue.exclusive();
00482 
00483                         try {
00484                                 // In this block we will write all remaining element in the queue
00485                                 // to the logging streams. While we do this, the queue should be locked
00486                                 // and finally we abort the queue to unblock all waiting threads.
00487                                 while (!q.empty())
00488                                 {
00489                                         Logger &log = q.front();
00490                                         try { log.flush(); } catch (const std::exception&) {};
00491 
00492                                         q.pop();
00493                                 }
00494                         } catch (const std::exception&) {
00495 
00496                         }
00497                 }
00498         }
00499 
00500         void Logger::LogWriter::__cancellation()
00501         {
00502                 // cancel the main thread in here
00503                 _queue.abort();
00504         }
00505 }