IBR-DTNSuite  0.12
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 "ibrcommon/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 #ifdef __WIN32__
42 #include <winsock2.h>
43 #endif
44 
45 namespace ibrcommon
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  {
115  }
116 
117  void LogWriter::setVerbosity(const int verbosity)
118  {
119  _verbosity = verbosity;
120  }
121 
122  unsigned char Logger::getLogMask()
123  {
125  }
126 
128  {
130  }
131 
132  unsigned char LogWriter::getLogMask() const
133  {
134  return _global_logmask;
135  }
136 
138  {
139  return _verbosity;
140  }
141 
142  void Logger::addStream(std::ostream &stream, const unsigned char logmask, const unsigned char options)
143  {
144  LogWriter::getInstance().addStream(stream, logmask, options);
145  }
146 
147  void Logger::setLogfile(const ibrcommon::File &logfile, const unsigned char logmask, const unsigned char options)
148  {
149  LogWriter::getInstance().setLogfile(logfile, logmask, options);
150  }
151 
152  void LogWriter::addStream(std::ostream &stream, const unsigned char logmask, const unsigned char options)
153  {
154  _global_logmask |= logmask;
155  _logger.push_back( LogWriter::LoggerOutput(stream, logmask, options) );
156  }
157 
158  void Logger::enableSyslog(const char *name, int option, int facility, const unsigned char logmask)
159  {
160  LogWriter::getInstance().enableSyslog(name, option, facility, logmask);
161  }
162 
164  {
165  LogWriter::getInstance().log(*this);
166  }
167 
168  void 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 LogWriter::flush(const Logger &logger)
182  {
183  if (_verbosity >= logger.getDebugVerbosity())
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.getLevel() & _syslog_mask)
205  {
206 #ifdef ANDROID
207  std::string log_tag = LogWriter::getInstance().getDefaultTag();
208  if (logger.getTag().length() > 0) {
209  log_tag = logger.getTag();
210  }
211 
212  // add additional prefix for android tags to seperate them from other logcat messages
213  log_tag = _android_tag_prefix + log_tag;
214 
215  switch (logger.getLevel())
216  {
218  __android_log_print(ANDROID_LOG_FATAL, log_tag.c_str(), "%s", logger.str().c_str());
219  break;
220 
222  __android_log_print(ANDROID_LOG_FATAL, log_tag.c_str(), "%s", logger.str().c_str());
223  break;
224 
225  case Logger::LOGGER_CRIT:
226  __android_log_print(ANDROID_LOG_FATAL, log_tag.c_str(), "%s", logger.str().c_str());
227  break;
228 
229  case Logger::LOGGER_ERR:
230  __android_log_print(ANDROID_LOG_ERROR, log_tag.c_str(), "%s", logger.str().c_str());
231  break;
232 
234  __android_log_print(ANDROID_LOG_WARN, log_tag.c_str(), "%s", logger.str().c_str());
235  break;
236 
238  __android_log_print(ANDROID_LOG_INFO, log_tag.c_str(), "%s", logger.str().c_str());
239  break;
240 
241  case Logger::LOGGER_INFO:
242  __android_log_print(ANDROID_LOG_INFO, log_tag.c_str(), "%s", logger.str().c_str());
243  break;
244 
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.getLevel())
255  {
257  ::syslog( LOG_EMERG, "%s", logger.str().c_str() );
258  break;
259 
261  ::syslog( LOG_ALERT, "%s", logger.str().c_str() );
262  break;
263 
264  case Logger::LOGGER_CRIT:
265  ::syslog( LOG_CRIT, "%s", logger.str().c_str() );
266  break;
267 
268  case Logger::LOGGER_ERR:
269  ::syslog( LOG_ERR, "%s", logger.str().c_str() );
270  break;
271 
273  ::syslog( LOG_WARNING, "%s", logger.str().c_str() );
274  break;
275 
277  ::syslog( LOG_NOTICE, "%s", logger.str().c_str() );
278  break;
279 
280  case Logger::LOGGER_INFO:
281  ::syslog( LOG_INFO, "%s", logger.str().c_str() );
282  break;
283 
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 LogWriter::LoggerOutput::log(const Logger &log)
300  {
301  if (_level & log.getLevel())
302  {
303  std::list<std::string> prefixes;
304 
305  // check for prefixes
306  if (_options & Logger::LOG_DATETIME)
307  {
308  // get timestamp
309  time_t secs = log.getLogTime().tv_sec;
310  std::string timestamp(asctime( localtime(&secs) ));
311  timestamp.erase(std::remove(timestamp.begin(), timestamp.end(), '\n'), timestamp.end());
312  prefixes.push_back(timestamp);
313  }
314 
315  // check for prefixes
316  if (_options & Logger::LOG_TIMESTAMP)
317  {
318  std::stringstream ss;
319  ss.fill('0');
320  ss << log.getLogTime().tv_sec << "." << std::setw(6) << log.getLogTime().tv_usec;
321  prefixes.push_back(ss.str());
322  }
323 
324  if (_options & Logger::LOG_LEVEL)
325  {
326  // print log level
327  switch (log.getLevel())
328  {
330  prefixes.push_back("EMERGENCY");
331  break;
332 
334  prefixes.push_back("ALERT");
335  break;
336 
337  case Logger::LOGGER_CRIT:
338  prefixes.push_back("CRTITICAL");
339  break;
340 
341  case Logger::LOGGER_ERR:
342  prefixes.push_back("ERROR");
343  break;
344 
346  prefixes.push_back("WARNING");
347  break;
348 
350  prefixes.push_back("NOTICE");
351  break;
352 
353  case Logger::LOGGER_INFO:
354  prefixes.push_back("INFO");
355  break;
356 
358  {
359  std::stringstream ss;
360  ss << "DEBUG." << log.getDebugVerbosity();
361  prefixes.push_back(ss.str());
362  break;
363  }
364 
365  default:
366  break;
367  }
368  }
369 
370  if (_options & Logger::LOG_HOSTNAME)
371  {
372  std::vector<char> hostname_array(64);
373  if ( gethostname(&hostname_array[0], 64) == 0 )
374  {
375  std::string hostname(&hostname_array[0]);
376  prefixes.push_back(hostname);
377  }
378  }
379 
380  if (_options & Logger::LOG_TAG)
381  {
382  if (log.getTag().length() > 0) {
383  prefixes.push_back(log.getTag());
384  } else {
385  prefixes.push_back(LogWriter::getInstance().getDefaultTag());
386  }
387  }
388 
389  // print prefixes
390  for (std::list<std::string>::const_iterator iter = prefixes.begin(); iter != prefixes.end(); ++iter)
391  {
392  if (iter == prefixes.begin())
393  {
394  _stream << (*iter);
395  }
396  else
397  {
398  _stream << " " << (*iter);
399  }
400  }
401 
402  if (!prefixes.empty())
403  {
404  _stream << ": ";
405  }
406 
407  _stream << log.str() << std::endl;
408  }
409  }
410 
411  LogWriter::LoggerOutput::LoggerOutput(std::ostream &stream, const unsigned char logmask, const unsigned char options)
412  : _stream(stream), _level(logmask), _options(options)
413  {
414  }
415 
416  LogWriter::LoggerOutput::~LoggerOutput()
417  {
418  }
419 
421  {
423  }
424 
425  void Logger::enableBuffer(size_t size)
426  {
428  }
429 
430  void Logger::writeBuffer(std::ostream &stream)
431  {
432  unsigned char logmask = ibrcommon::Logger::LOGGER_ALL;
434 
435  LogWriter::getInstance().writeBuffer(stream, logmask, options);
436  }
437 
439  {
440  try {
441  _use_queue = true;
442  start();
443  } catch (const ibrcommon::ThreadException &ex) {
444  IBRCOMMON_LOGGER_TAG("LogWriter", error) << "enableAsync failed: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
445  }
446  }
447 
448  void Logger::setDefaultTag(const std::string &tag)
449  {
451  }
452 
454  {
455  // stop the LogWriter::run() thread (this is needed with uclibc)
457  }
458 
460  {
461  //reload the logger
463  }
464 
466  {
467  return _level;
468  }
469 
470  const std::string& Logger::getTag() const
471  {
472  return _tag;
473  }
474 
476  {
477  return _debug_verbosity;
478  }
479 
480  struct timeval Logger::getLogTime() const
481  {
482  return _logtime;
483  }
484 
486  {
487  static LogWriter instance;
488  return instance;
489  }
490 
491  LogWriter::LogWriter()
492  : _global_logmask(0), _verbosity(0), _syslog(0), _syslog_mask(0), _queue(50), _use_queue(false), _buffer_size(0), _buffer(NULL),
493  _logfile_output(NULL), _logfile_logmask(0), _logfile_options(0), _default_tag("Core"), _android_tag_prefix("IBR-DTN/")
494  // limit queue to 50 entries
495  {
496  }
497 
499  {
500  // do cleanup only if the thread was running before
501  if (_use_queue) stop();
502 
503  // join the LogWriter::run() thread
504  join();
505 
506  // remove the ring-buffer
507  ibrcommon::MutexLock l(_buffer_mutex);
508  if (_buffer != NULL) delete _buffer;
509  }
510 
511  void LogWriter::enableBuffer(size_t size)
512  {
513  ibrcommon::MutexLock l(_buffer_mutex);
514  _buffer_size = size;
515  _buffer = new std::list<Logger>();
516  }
517 
518  void LogWriter::setLogfile(const ibrcommon::File &logfile, const unsigned char logmask, const unsigned char options)
519  {
520  ibrcommon::MutexLock l(_logfile_mutex);
521  if (_logfile_output != NULL)
522  {
523  // delete the old logger
524  delete _logfile_output;
525  _logfile_output = NULL;
526 
527  // close the output file
528  _logfile_stream.close();
529  }
530 
531  // stop here if the logmask is zero
532  // this can be used to disable file logging
533  if (logmask == 0) return;
534 
535  _logfile = logfile;
536  _logfile_logmask = logmask;
537  _logfile_options = options;
538  _global_logmask |= logmask;
539 
540  // open the new logfile
541  _logfile_stream.open(_logfile.getPath().c_str(), std::ios::out | std::ios::app);
542 
543  // create a new logger output
544  if (_logfile_stream.good())
545  {
546  _logfile_output = new LoggerOutput(_logfile_stream, _logfile_logmask, _logfile_options);
547  }
548  else
549  {
550  _logfile_stream.close();
551  }
552  }
553 
555  {
556  ibrcommon::MutexLock l(_logfile_mutex);
557  if (_logfile_output != NULL)
558  {
559  // delete the old logger
560  delete _logfile_output;
561  _logfile_output = NULL;
562 
563  // close the output file
564  _logfile_stream.close();
565 
566  // open the new logfile
567  _logfile_stream.open(_logfile.getPath().c_str(), std::ios::out | std::ios::app);
568 
569  // create a new logger output
570  if (_logfile_stream.good())
571  {
572  _logfile_output = new LoggerOutput(_logfile_stream, _logfile_logmask, _logfile_options);
573  }
574  else
575  {
576  _logfile_stream.close();
577  }
578  }
579  }
580 
581  void LogWriter::writeBuffer(std::ostream &stream, const unsigned char logmask, const unsigned char options)
582  {
583  ibrcommon::MutexLock l(_buffer_mutex);
584  if (_buffer == NULL) return;
585 
586  LoggerOutput output(stream, logmask, options);
587 
588  for (std::list<Logger>::const_iterator iter = _buffer->begin(); iter != _buffer->end(); ++iter)
589  {
590  const Logger &l = (*iter);
591  output.log(l);
592  }
593  }
594 
595  const std::string& LogWriter::getDefaultTag() const
596  {
597  return _default_tag;
598  }
599 
600  void LogWriter::setDefaultTag(const std::string &value)
601  {
602  _default_tag = value;
603  }
604 
605  void LogWriter::log(Logger &logger)
606  {
607  if (_use_queue)
608  {
609  _queue.push(logger);
610  }
611  else
612  {
613  flush(logger);
614  }
615  }
616 
617  void LogWriter::run() throw ()
618  {
619  try {
620  while (true)
621  {
622  Logger log = _queue.getnpop(true);
623  flush(log);
624 
625  // add to ring-buffer
626  ibrcommon::MutexLock l(_buffer_mutex);
627  if (_buffer != NULL)
628  {
629  _buffer->push_back(log);
630  while (_buffer->size() > _buffer_size)
631  {
632  _buffer->pop_front();
633  }
634  }
635  }
636  } catch (const std::exception&) {
637  ibrcommon::Queue<Logger>::Locked q = _queue.exclusive();
638 
639  try {
640  // In this block we will write all remaining element in the queue
641  // to the logging streams. While we do this, the queue should be locked
642  // and finally we abort the queue to unblock all waiting threads.
643  while (!q.empty())
644  {
645  Logger &log = q.front();
646  try { flush(log); } catch (const std::exception&) {};
647 
648  q.pop();
649  }
650  } catch (const std::exception&) {
651 
652  }
653  }
654  }
655 
657  {
658  // cancel the main thread in here
659  _queue.abort();
660  }
661 }