|
IBR-DTNSuite 0.6
|
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(<ime) )); 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 }