IBR-DTNSuite
0.8
|
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 }