IBR-DTNSuite  0.10
Logger.cpp
Go to the documentation of this file.
1 /*
2  * Logger.cpp
3  *
4  * Copyright (C) 2011 IBR, TU Braunschweig
5  *
6  * Written-by: Johannes Morgenroth <morgenroth@ibr.cs.tu-bs.de>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21 
22 #include "config.h"
23 #include "ibrcommon/Logger.h"
24 #include <ibrcommon/thread/Mutex.h>
26 
27 #include <algorithm>
28 #include <sys/time.h>
29 #include <iomanip>
30 #include <vector>
31 #include <unistd.h>
32 
33 #ifdef HAVE_SYSLOG_H
34 #include <syslog.h>
35 #endif
36 
37 #ifdef ANDROID
38 #include <android/log.h>
39 #endif
40 
41 namespace ibrcommon
42 {
43  std::string Logger::_default_tag = "Core";
44  std::string Logger::_android_tag_prefix = "IBR-DTN/";
45  Logger::LogWriter Logger::_logwriter;
46 
47  Logger::Logger(LogLevel level, const std::string &tag, int debug_verbosity)
48  : _level(level), _tag(tag), _debug_verbosity(debug_verbosity)
49  {
50  ::gettimeofday(&_logtime, NULL);
51  }
52 
53  Logger::Logger(const Logger &obj)
54  : _level(obj._level), _tag(obj._tag), _debug_verbosity(obj._debug_verbosity), _logtime(obj._logtime), _data(obj._data)
55  {
56  }
57 
59  {
60  }
61 
62  void Logger::setMessage(const std::string &data)
63  {
64  _data = data;
65  }
66 
67  const std::string& Logger::str() const
68  {
69  return _data;
70  }
71 
72  Logger Logger::emergency(const std::string &tag)
73  {
74  return Logger(LOGGER_EMERG, tag);
75  }
76 
77  Logger Logger::alert(const std::string &tag)
78  {
79  return Logger(LOGGER_ALERT, tag);
80  }
81 
82  Logger Logger::critical(const std::string &tag)
83  {
84  return Logger(LOGGER_CRIT, tag);
85  }
86 
87  Logger Logger::error(const std::string &tag)
88  {
89  return Logger(LOGGER_ERR, tag);
90  }
91 
92  Logger Logger::warning(const std::string &tag)
93  {
94  return Logger(LOGGER_WARNING, tag);
95  }
96 
97  Logger Logger::notice(const std::string &tag)
98  {
99  return Logger(LOGGER_NOTICE, tag);
100  }
101 
102  Logger Logger::info(const std::string &tag)
103  {
104  return Logger(LOGGER_INFO, tag);
105  }
106 
107  Logger Logger::debug(const std::string &tag, int verbosity)
108  {
109  return Logger(LOGGER_DEBUG, tag, verbosity);
110  }
111 
112  void Logger::setVerbosity(const int verbosity)
113  {
114  Logger::_logwriter.setVerbosity(verbosity);
115  }
116 
117  void Logger::LogWriter::setVerbosity(const int verbosity)
118  {
119  _verbosity = verbosity;
120  }
121 
122  unsigned char Logger::getLogMask()
123  {
124  return Logger::_logwriter.getLogMask();
125  }
126 
128  {
129  return Logger::_logwriter.getVerbosity();
130  }
131 
132  unsigned char Logger::LogWriter::getLogMask() const
133  {
134  return _global_logmask;
135  }
136 
137  int Logger::LogWriter::getVerbosity() const
138  {
139  return _verbosity;
140  }
141 
142  void Logger::addStream(std::ostream &stream, const unsigned char logmask, const unsigned char options)
143  {
144  Logger::_logwriter.addStream(stream, logmask, options);
145  }
146 
147  void Logger::setLogfile(const ibrcommon::File &logfile, const unsigned char logmask, const unsigned char options)
148  {
149  Logger::_logwriter.setLogfile(logfile, logmask, options);
150  }
151 
152  void Logger::LogWriter::addStream(std::ostream &stream, const unsigned char logmask, const unsigned char options)
153  {
154  _global_logmask |= logmask;
155  _logger.push_back( Logger::LoggerOutput(stream, logmask, options) );
156  }
157 
158  void Logger::enableSyslog(const char *name, int option, int facility, const unsigned char logmask)
159  {
160  Logger::_logwriter.enableSyslog(name, option, facility, logmask);
161  }
162 
164  {
165  Logger::_logwriter.log(*this);
166  }
167 
168  void Logger::LogWriter::enableSyslog(const char *name, int option, int facility, const unsigned char logmask)
169  {
170 #if ( defined HAVE_SYSLOG_H || defined ANDROID )
171 #ifdef HAVE_SYSLOG_H
172  // init syslog
173  ::openlog(name, option, facility);
174 #endif
175  _syslog = true;
176  _syslog_mask = logmask;
177  _global_logmask |= logmask;
178 #endif
179  }
180 
181  void Logger::LogWriter::flush(const Logger &logger)
182  {
183  if (_verbosity >= logger._debug_verbosity)
184  {
185  for (std::list<LoggerOutput>::iterator iter = _logger.begin(); iter != _logger.end(); ++iter)
186  {
187  LoggerOutput &output = (*iter);
188  output.log(logger);
189  }
190 
191  // output to logfile
192  {
193  ibrcommon::MutexLock l(_logfile_mutex);
194  if (_logfile_output != NULL)
195  {
196  _logfile_output->log(logger);
197  }
198  }
199 
200 #if ( defined HAVE_SYSLOG_H || defined ANDROID )
201  // additionally log to the syslog/android logcat
202  if (_syslog)
203  {
204  if (logger._level & _syslog_mask)
205  {
206 #ifdef ANDROID
207  std::string log_tag = Logger::_default_tag;
208  if (logger._tag.length() > 0) {
209  log_tag = logger._tag;
210  }
211 
212  // add additional prefix for android tags to seperate them from other logcat messages
213  log_tag = Logger::_android_tag_prefix + log_tag;
214 
215  switch (logger._level)
216  {
217  case LOGGER_EMERG:
218  __android_log_print(ANDROID_LOG_FATAL, log_tag.c_str(), "%s", logger.str().c_str());
219  break;
220 
221  case LOGGER_ALERT:
222  __android_log_print(ANDROID_LOG_FATAL, log_tag.c_str(), "%s", logger.str().c_str());
223  break;
224 
225  case LOGGER_CRIT:
226  __android_log_print(ANDROID_LOG_FATAL, log_tag.c_str(), "%s", logger.str().c_str());
227  break;
228 
229  case LOGGER_ERR:
230  __android_log_print(ANDROID_LOG_ERROR, log_tag.c_str(), "%s", logger.str().c_str());
231  break;
232 
233  case LOGGER_WARNING:
234  __android_log_print(ANDROID_LOG_WARN, log_tag.c_str(), "%s", logger.str().c_str());
235  break;
236 
237  case LOGGER_NOTICE:
238  __android_log_print(ANDROID_LOG_INFO, log_tag.c_str(), "%s", logger.str().c_str());
239  break;
240 
241  case LOGGER_INFO:
242  __android_log_print(ANDROID_LOG_INFO, log_tag.c_str(), "%s", logger.str().c_str());
243  break;
244 
245  case LOGGER_DEBUG:
246  __android_log_print(ANDROID_LOG_DEBUG, log_tag.c_str(), "%s", logger.str().c_str());
247  break;
248 
249  default:
250  __android_log_print(ANDROID_LOG_INFO, log_tag.c_str(), "%s", logger.str().c_str());
251  break;
252  }
253 #else
254  switch (logger._level)
255  {
256  case LOGGER_EMERG:
257  ::syslog( LOG_EMERG, "%s", logger.str().c_str() );
258  break;
259 
260  case LOGGER_ALERT:
261  ::syslog( LOG_ALERT, "%s", logger.str().c_str() );
262  break;
263 
264  case LOGGER_CRIT:
265  ::syslog( LOG_CRIT, "%s", logger.str().c_str() );
266  break;
267 
268  case LOGGER_ERR:
269  ::syslog( LOG_ERR, "%s", logger.str().c_str() );
270  break;
271 
272  case LOGGER_WARNING:
273  ::syslog( LOG_WARNING, "%s", logger.str().c_str() );
274  break;
275 
276  case LOGGER_NOTICE:
277  ::syslog( LOG_NOTICE, "%s", logger.str().c_str() );
278  break;
279 
280  case LOGGER_INFO:
281  ::syslog( LOG_INFO, "%s", logger.str().c_str() );
282  break;
283 
284  case LOGGER_DEBUG:
285  ::syslog( LOG_DEBUG, "%s", logger.str().c_str() );
286  break;
287 
288  default:
289  ::syslog( LOG_NOTICE, "%s", logger.str().c_str() );
290  break;
291  }
292 #endif
293  }
294  }
295 #endif
296  }
297  }
298 
299  void Logger::LoggerOutput::log(const Logger &log)
300  {
301  if (_level & log._level)
302  {
303  std::list<std::string> prefixes;
304 
305  // check for prefixes
306  if (_options & LOG_DATETIME)
307  {
308  // get timestamp
309  std::string timestamp(asctime( localtime(&log._logtime.tv_sec) ));
310  timestamp.erase(std::remove(timestamp.begin(), timestamp.end(), '\n'), timestamp.end());
311  prefixes.push_back(timestamp);
312  }
313 
314  // check for prefixes
315  if (_options & LOG_TIMESTAMP)
316  {
317  std::stringstream ss;
318  ss.fill('0');
319  ss << log._logtime.tv_sec << "." << std::setw(6) << log._logtime.tv_usec;
320  prefixes.push_back(ss.str());
321  }
322 
323  if (_options & LOG_LEVEL)
324  {
325  // print log level
326  switch (log._level)
327  {
328  case LOGGER_EMERG:
329  prefixes.push_back("EMERGENCY");
330  break;
331 
332  case LOGGER_ALERT:
333  prefixes.push_back("ALERT");
334  break;
335 
336  case LOGGER_CRIT:
337  prefixes.push_back("CRTITICAL");
338  break;
339 
340  case LOGGER_ERR:
341  prefixes.push_back("ERROR");
342  break;
343 
344  case LOGGER_WARNING:
345  prefixes.push_back("WARNING");
346  break;
347 
348  case LOGGER_NOTICE:
349  prefixes.push_back("NOTICE");
350  break;
351 
352  case LOGGER_INFO:
353  prefixes.push_back("INFO");
354  break;
355 
356  case LOGGER_DEBUG:
357  {
358  std::stringstream ss;
359  ss << "DEBUG." << log._debug_verbosity;
360  prefixes.push_back(ss.str());
361  break;
362  }
363 
364  default:
365  break;
366  }
367  }
368 
369  if (_options & LOG_HOSTNAME)
370  {
371  std::vector<char> hostname_array(64);
372  if ( gethostname(&hostname_array[0], 64) == 0 )
373  {
374  std::string hostname(&hostname_array[0]);
375  prefixes.push_back(hostname);
376  }
377  }
378 
379  if (_options & LOG_TAG)
380  {
381  if (log._tag.length() > 0) {
382  prefixes.push_back(log._tag);
383  } else {
384  prefixes.push_back(Logger::_default_tag);
385  }
386  }
387 
388  // print prefixes
389  for (std::list<std::string>::const_iterator iter = prefixes.begin(); iter != prefixes.end(); ++iter)
390  {
391  if (iter == prefixes.begin())
392  {
393  _stream << (*iter);
394  }
395  else
396  {
397  _stream << " " << (*iter);
398  }
399  }
400 
401  if (!prefixes.empty())
402  {
403  _stream << ": ";
404  }
405 
406  _stream << log.str() << std::endl;
407  }
408  }
409 
410  Logger::LoggerOutput::LoggerOutput(std::ostream &stream, const unsigned char logmask, const unsigned char options)
411  : _stream(stream), _level(logmask), _options(options)
412  {
413  }
414 
415  Logger::LoggerOutput::~LoggerOutput()
416  {
417  }
418 
420  {
421  Logger::_logwriter.enableAsync();
422  }
423 
424  void Logger::enableBuffer(size_t size)
425  {
426  Logger::_logwriter.enableBuffer(size);
427  }
428 
429  void Logger::writeBuffer(std::ostream &stream)
430  {
431  unsigned char logmask = ibrcommon::Logger::LOGGER_ALL;
433 
434  Logger::_logwriter.writeBuffer(stream, logmask, options);
435  }
436 
437  void Logger::LogWriter::enableAsync()
438  {
439  try {
440  _use_queue = true;
441  start();
442  } catch (const ibrcommon::ThreadException &ex) {
443  IBRCOMMON_LOGGER_TAG("LogWriter", error) << "enableAsync failed: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
444  }
445  }
446 
447  void Logger::setDefaultTag(const std::string &tag)
448  {
449  Logger::_default_tag = tag;
450  }
451 
453  {
454  // stop the LogWriter::run() thread (this is needed with uclibc)
455  _logwriter.stop();
456  }
457 
459  {
460  //reload the logger
461  _logwriter.reload();
462  }
463 
464  Logger::LogWriter::LogWriter()
465  : _global_logmask(0), _verbosity(0), _syslog(0), _syslog_mask(0), _queue(50), _use_queue(false), _buffer_size(0), _buffer(NULL),
466  _logfile_output(NULL), _logfile_logmask(0), _logfile_options(0)
467  // limit queue to 50 entries
468  {
469  }
470 
471  Logger::LogWriter::~LogWriter()
472  {
473  // do cleanup only if the thread was running before
474  if (_use_queue) stop();
475 
476  // join the LogWriter::run() thread
477  join();
478 
479  // remove the ring-buffer
480  ibrcommon::MutexLock l(_buffer_mutex);
481  if (_buffer != NULL) delete _buffer;
482  }
483 
484  void Logger::LogWriter::enableBuffer(size_t size)
485  {
486  ibrcommon::MutexLock l(_buffer_mutex);
487  _buffer_size = size;
488  _buffer = new std::list<Logger>();
489  }
490 
491  void Logger::LogWriter::setLogfile(const ibrcommon::File &logfile, const unsigned char logmask, const unsigned char options)
492  {
493  ibrcommon::MutexLock l(_logfile_mutex);
494  if (_logfile_output != NULL)
495  {
496  // delete the old logger
497  delete _logfile_output;
498  _logfile_output = NULL;
499 
500  // close the output file
501  _logfile_stream.close();
502  }
503 
504  // stop here if the logmask is zero
505  // this can be used to disable file logging
506  if (logmask == 0) return;
507 
508  _logfile = logfile;
509  _logfile_logmask = logmask;
510  _logfile_options = options;
511  _global_logmask |= logmask;
512 
513  // open the new logfile
514  _logfile_stream.open(_logfile.getPath().c_str(), std::ios::out | std::ios::app);
515 
516  // create a new logger output
517  if (_logfile_stream.good())
518  {
519  _logfile_output = new LoggerOutput(_logfile_stream, _logfile_logmask, _logfile_options);
520  }
521  else
522  {
523  _logfile_stream.close();
524  }
525  }
526 
527  void Logger::LogWriter::reload()
528  {
529  ibrcommon::MutexLock l(_logfile_mutex);
530  if (_logfile_output != NULL)
531  {
532  // delete the old logger
533  delete _logfile_output;
534  _logfile_output = NULL;
535 
536  // close the output file
537  _logfile_stream.close();
538 
539  // open the new logfile
540  _logfile_stream.open(_logfile.getPath().c_str(), std::ios::out | std::ios::app);
541 
542  // create a new logger output
543  if (_logfile_stream.good())
544  {
545  _logfile_output = new LoggerOutput(_logfile_stream, _logfile_logmask, _logfile_options);
546  }
547  else
548  {
549  _logfile_stream.close();
550  }
551  }
552  }
553 
554  void Logger::LogWriter::writeBuffer(std::ostream &stream, const unsigned char logmask, const unsigned char options)
555  {
556  ibrcommon::MutexLock l(_buffer_mutex);
557  if (_buffer == NULL) return;
558 
559  LoggerOutput output(stream, logmask, options);
560 
561  for (std::list<Logger>::const_iterator iter = _buffer->begin(); iter != _buffer->end(); ++iter)
562  {
563  const Logger &l = (*iter);
564  output.log(l);
565  }
566  }
567 
568  void Logger::LogWriter::log(Logger &logger)
569  {
570  if (_use_queue)
571  {
572  _queue.push(logger);
573  }
574  else
575  {
576  flush(logger);
577  }
578  }
579 
580  void Logger::LogWriter::run() throw ()
581  {
582  try {
583  while (true)
584  {
585  Logger log = _queue.getnpop(true);
586  flush(log);
587 
588  // add to ring-buffer
589  ibrcommon::MutexLock l(_buffer_mutex);
590  if (_buffer != NULL)
591  {
592  _buffer->push_back(log);
593  while (_buffer->size() > _buffer_size)
594  {
595  _buffer->pop_front();
596  }
597  }
598  }
599  } catch (const std::exception&) {
600  ibrcommon::Queue<Logger>::Locked q = _queue.exclusive();
601 
602  try {
603  // In this block we will write all remaining element in the queue
604  // to the logging streams. While we do this, the queue should be locked
605  // and finally we abort the queue to unblock all waiting threads.
606  while (!q.empty())
607  {
608  Logger &log = q.front();
609  try { flush(log); } catch (const std::exception&) {};
610 
611  q.pop();
612  }
613  } catch (const std::exception&) {
614 
615  }
616  }
617  }
618 
619  void Logger::LogWriter::__cancellation() throw ()
620  {
621  // cancel the main thread in here
622  _queue.abort();
623  }
624 }