MythTV  master
logging.cpp
Go to the documentation of this file.
1 #include <QtGlobal>
2 #include <QAtomicInt>
3 #include <QMutex>
4 #include <QMutexLocker>
5 #include <QWaitCondition>
6 #include <QList>
7 #include <QQueue>
8 #include <QHash>
9 #include <QFileInfo>
10 #include <QStringList>
11 #include <QMap>
12 #include <QRegularExpression>
13 #include <QVariantMap>
14 #include <iostream>
15 
16 #include "mythlogging.h"
17 #include "logging.h"
18 #include "loggingserver.h"
19 #include "mythdb.h"
20 #include "mythdirs.h"
21 #include "mythcorecontext.h"
22 #include "mythsystemlegacy.h"
23 #include "dbutil.h"
24 #include "exitcodes.h"
25 #include "compat.h"
26 
27 #include <csignal>
28 #include <cstdarg>
29 #include <cstdio>
30 #include <cstdlib>
31 #include <cstring>
32 #include <fcntl.h>
33 #include <sys/stat.h>
34 #include <sys/types.h>
35 #include <utility>
36 #if HAVE_GETTIMEOFDAY
37 #include <sys/time.h>
38 #endif
39 #define SYSLOG_NAMES
40 #ifndef _WIN32
41 #include <mythsyslog.h>
42 #endif
43 #include <unistd.h>
44 
45 // Various ways to get to thread's tid
46 #if defined(__linux__)
47 #include <sys/syscall.h>
48 #elif defined(__FreeBSD__)
49 extern "C" {
50 #include <sys/ucontext.h>
51 #include <sys/thr.h>
52 }
53 #elif defined(Q_OS_DARWIN)
54 #include <mach/mach.h>
55 #endif
56 
57 // QJson
58 #include "qjsonwrapper/Json.h"
59 
60 #ifdef Q_OS_ANDROID
61 #include <android/log.h>
62 #endif
63 
64 static QMutex logQueueMutex;
65 static QQueue<LoggingItem *> logQueue;
66 
67 static LoggerThread *logThread = nullptr;
68 static QMutex logThreadMutex;
69 static QHash<uint64_t, QString> logThreadHash;
70 
71 static QMutex logThreadTidMutex;
72 static QHash<uint64_t, int64_t> logThreadTidHash;
73 
74 static bool logThreadFinished = false;
75 static bool debugRegistration = false;
76 
79  int m_quiet;
81  bool m_dblog;
82  QString m_path;
83 };
84 
85 LogPropagateOpts logPropagateOpts {false, 0, 0, true, ""};
87 QStringList logPropagateArgList;
88 
89 LogLevel_t logLevel = LOG_INFO;
90 
91 bool verboseInitialized = false;
94 
97 
98 const uint64_t verboseDefaultInt = VB_GENERAL;
99 const QString verboseDefaultStr { QStringLiteral(" general") };
100 
104 
108 
109 void verboseAdd(uint64_t mask, QString name, bool additive, QString helptext);
110 void loglevelAdd(int value, QString name, char shortname);
111 void verboseInit(void);
112 void verboseHelp(void);
113 
115 void resetLogging(void)
116 {
121  haveUserDefaultValues = false;
122 
123  verboseInit();
124 }
125 
126 LoggingItem::LoggingItem(const char *_file, const char *_function,
127  int _line, LogLevel_t _level, LoggingType _type) :
128  ReferenceCounter("LoggingItem", false),
129  m_threadId((uint64_t)(QThread::currentThreadId())),
130  m_line(_line), m_type(_type), m_level(_level),
131  m_file(_file), m_function(_function)
132 {
133  m_epoch = nowAsDuration<std::chrono::microseconds>();
134  setThreadTid();
135 }
136 
137 QByteArray LoggingItem::toByteArray(void)
138 {
139  QVariantMap variant = QJsonWrapper::qobject2qvariant(this);
140  QByteArray json = QJsonWrapper::toJson(variant);
141 
142  //cout << json.constData() << endl;
143 
144  return json;
145 }
146 
150 {
151  static constexpr char const *kSUnknown = "thread_unknown";
152 
153  if( !m_threadName.isEmpty() )
154  return m_threadName;
155 
156  QMutexLocker locker(&logThreadMutex);
157  return logThreadHash.value(m_threadId, kSUnknown);
158 }
159 
166 {
167  QMutexLocker locker(&logThreadTidMutex);
168  m_tid = logThreadTidHash.value(m_threadId, 0);
169  return m_tid;
170 }
171 
179 {
180  QMutexLocker locker(&logThreadTidMutex);
181 
182  m_tid = logThreadTidHash.value(m_threadId, -1);
183  if (m_tid == -1)
184  {
185  m_tid = 0;
186 
187 #if defined(Q_OS_ANDROID)
188  m_tid = (int64_t)gettid();
189 #elif defined(__linux__)
190  m_tid = syscall(SYS_gettid);
191 #elif defined(__FreeBSD__)
192  long lwpid;
193  int dummy = thr_self( &lwpid );
194  (void)dummy;
195  m_tid = (int64_t)lwpid;
196 #elif defined(Q_OS_DARWIN)
197  m_tid = (int64_t)mach_thread_self();
198 #endif
200  }
201 }
202 
204 QString LoggingItem::getTimestamp (const char *format) const
205 {
206  QDateTime epoch = QDateTime::fromMSecsSinceEpoch(m_epoch.count()/1000);
207  QString timestamp = epoch.toString(format);
208  return timestamp;
209 }
210 
211 QString LoggingItem::getTimestampUs (const char *format) const
212 {
213  QString timestamp = getTimestamp(format);
214  timestamp += QString(".%1").arg((m_epoch % 1s).count(),6,10,QChar('0'));
215  return timestamp;
216 }
217 
220 {
221  QMutexLocker locker(&loglevelMapMutex);
222  LoglevelMap::iterator it = loglevelMap.find(m_level);
223  if (it != loglevelMap.end())
224  return (*it)->shortname;
225  return '-';
226 }
227 
232  QString table, int facility) :
233  MThread("Logger"),
234  m_waitNotEmpty(new QWaitCondition()),
235  m_waitEmpty(new QWaitCondition()),
236  m_filename(std::move(filename)), m_progress(progress), m_quiet(quiet),
237  m_tablename(std::move(table)), m_facility(facility), m_pid(getpid())
238 {
239  if (qEnvironmentVariableIsSet("VERBOSE_THREADS"))
240  {
241  LOG(VB_GENERAL, LOG_NOTICE,
242  "Logging thread registration/deregistration enabled!");
243  debugRegistration = true;
244  }
245 
246  if (!logForwardStart())
247  {
248  LOG(VB_GENERAL, LOG_ERR,
249  "Failed to start LogServer thread");
250  }
251  moveToThread(qthread());
252 }
253 
256 {
257  stop();
258  wait();
259  logForwardStop();
260 
261  delete m_waitNotEmpty;
262  delete m_waitEmpty;
263 }
264 
270 {
271  RunProlog();
272 
273  logThreadFinished = false;
274 
275  LOG(VB_GENERAL, LOG_INFO, "Added logging to the console");
276 
277  bool dieNow = false;
278 
279  QMutexLocker qLock(&logQueueMutex);
280 
281  while (!m_aborted || !logQueue.isEmpty())
282  {
283  qLock.unlock();
284  qApp->processEvents(QEventLoop::AllEvents, 10);
285  qApp->sendPostedEvents(nullptr, QEvent::DeferredDelete);
286 
287  qLock.relock();
288  if (logQueue.isEmpty())
289  {
290  m_waitEmpty->wakeAll();
291  m_waitNotEmpty->wait(qLock.mutex(), 100);
292  continue;
293  }
294 
295  LoggingItem *item = logQueue.dequeue();
296  qLock.unlock();
297 
298  fillItem(item);
299  handleItem(item);
300  logConsole(item);
301  item->DecrRef();
302 
303  qLock.relock();
304  }
305 
306  qLock.unlock();
307 
308  // This must be before the timer stop below or we deadlock when the timer
309  // thread tries to deregister, and we wait for it.
310  logThreadFinished = true;
311 
312  RunEpilog();
313 
314  if (dieNow)
315  {
316  qApp->processEvents();
317  }
318 }
319 
326 {
327  if (item->m_type & kRegistering)
328  {
329  item->m_tid = item->getThreadTid();
330 
331  QMutexLocker locker(&logThreadMutex);
332  logThreadHash[item->m_threadId] = item->m_threadName;
333 
334  if (debugRegistration)
335  {
336  item->m_message = QString("Thread 0x%1 (%2) registered as \'%3\'")
337  .arg(QString::number(item->m_threadId,16),
338  QString::number(item->m_tid),
339  logThreadHash[item->m_threadId]);
340  }
341  }
342  else if (item->m_type & kDeregistering)
343  {
344  int64_t tid = 0;
345 
346  {
347  QMutexLocker locker(&logThreadTidMutex);
348  if( logThreadTidHash.contains(item->m_threadId) )
349  {
350  tid = logThreadTidHash[item->m_threadId];
351  logThreadTidHash.remove(item->m_threadId);
352  }
353  }
354 
355  QMutexLocker locker(&logThreadMutex);
356  if (logThreadHash.contains(item->m_threadId))
357  {
358  if (debugRegistration)
359  {
360  item->m_message = QString("Thread 0x%1 (%2) deregistered as \'%3\'")
361  .arg(QString::number(item->m_threadId,16),
362  QString::number(tid),
363  logThreadHash[item->m_threadId]);
364  }
365  logThreadHash.remove(item->m_threadId);
366  }
367  }
368 
369  if (!item->m_message.isEmpty())
370  {
378  QList<QByteArray> list;
379  list.append(QByteArray());
380  list.append(item->toByteArray());
381  logForwardMessage(list);
382  }
383 }
384 
388 {
389  if (m_quiet || (m_progress && item->m_level > LOG_ERR))
390  return false;
391 
392  if (!(item->m_type & kMessage))
393  return false;
394 
395  item->IncrRef();
396 
397 #ifndef Q_OS_ANDROID
398  std::string line;
399 
400  if (item->m_type & kStandardIO)
401  {
402  line = qPrintable(item->m_message);
403  }
404  else
405  {
406  QString timestamp = item->getTimestampUs();
407  char shortname = item->getLevelChar();
408 
409 #ifndef NDEBUG
410  if (item->tid())
411  {
412  line = qPrintable(QString("%1 %2 [%3/%4] %5 %6:%7:%8 %9\n")
413  .arg(timestamp, QString(shortname),
414  QString::number(item->pid()),
415  QString::number(item->tid()),
416  item->threadName(),
417  item->m_file,
418  QString::number(item->m_line),
419  item->m_function,
420  item->m_message));
421  }
422  else
423  {
424  line = qPrintable(QString("%1 %2 [%3] %4 %5:%6:%7 %8\n")
425  .arg(timestamp, QString(shortname),
426  QString::number(item->pid()),
427  item->threadName(),
428  item->m_file,
429  QString::number(item->m_line),
430  item->m_function,
431  item->m_message));
432  }
433 #else
434  line = qPrintable(QString("%1 %2 %3\n")
435  .arg(timestamp, QString(shortname),
436  item->m_message));
437 #endif
438  }
439 
440  (void)write(1, line.data(), line.size());
441 
442 #else // Q_OS_ANDROID
443 
444  android_LogPriority aprio;
445  switch (item->m_level)
446  {
447  case LOG_EMERG:
448  aprio = ANDROID_LOG_FATAL;
449  break;
450  case LOG_ALERT:
451  case LOG_CRIT:
452  case LOG_ERR:
453  aprio = ANDROID_LOG_ERROR;
454  break;
455  case LOG_WARNING:
456  aprio = ANDROID_LOG_WARN;
457  break;
458  case LOG_NOTICE:
459  case LOG_INFO:
460  aprio = ANDROID_LOG_INFO;
461  break;
462  case LOG_DEBUG:
463  aprio = ANDROID_LOG_DEBUG;
464  break;
465  case LOG_UNKNOWN:
466  default:
467  aprio = ANDROID_LOG_UNKNOWN;
468  break;
469  }
470 #ifndef NDEBUG
471  __android_log_print(aprio, "mfe", "%s:%d:%s %s", qPrintable(item->m_file),
472  item->m_line, qPrintable(item->m_function),
473  qPrintable(item->m_message));
474 #else
475  __android_log_print(aprio, "mfe", "%s", qPrintable(item->m_message));
476 #endif
477 #endif
478 
479  item->DecrRef();
480 
481  return true;
482 }
483 
484 
488 {
489  logQueueMutex.lock();
490  flush(1000);
491  m_aborted = true;
492  logQueueMutex.unlock();
493  m_waitNotEmpty->wakeAll();
494 }
495 
499 bool LoggerThread::flush(int timeoutMS)
500 {
501  QElapsedTimer t;
502  t.start();
503  while (!m_aborted && !logQueue.isEmpty() && !t.hasExpired(timeoutMS))
504  {
505  m_waitNotEmpty->wakeAll();
506  int left = timeoutMS - t.elapsed();
507  if (left > 0)
508  m_waitEmpty->wait(&logQueueMutex, left);
509  }
510  return logQueue.isEmpty();
511 }
512 
514 {
515  if (!item)
516  return;
517 
518  item->setPid(m_pid);
519  item->setThreadName(item->getThreadName());
520  item->setAppName(m_appname);
521  item->setTable(m_tablename);
522  item->setLogFile(m_filename);
523  item->setFacility(m_facility);
524 }
525 
526 
534 LoggingItem *LoggingItem::create(const char *_file,
535  const char *_function,
536  int _line, LogLevel_t _level,
537  LoggingType _type)
538 {
539  auto *item = new LoggingItem(_file, _function, _line, _level, _type);
540 
541  return item;
542 }
543 
545 {
546  // Deserialize buffer
547  QVariant variant = QJsonWrapper::parseJson(buf);
548 
549  auto *item = new LoggingItem;
550  QJsonWrapper::qvariant2qobject(variant.toMap(), item);
551 
552  return item;
553 }
554 
555 
564 void LogPrintLine( uint64_t mask, LogLevel_t level, const char *file, int line,
565  const char *function, QString message)
566 {
567  int type = kMessage;
568  type |= (mask & VB_FLUSH) ? kFlush : 0;
569  type |= (mask & VB_STDIO) ? kStandardIO : 0;
570  LoggingItem *item = LoggingItem::create(file, function, line, level,
571  (LoggingType)type);
572  if (!item)
573  return;
574 
575  item->m_message = std::move(message);
576 
577  QMutexLocker qLock(&logQueueMutex);
578 
579 #if defined( _MSC_VER ) && defined( _DEBUG )
580  OutputDebugStringA( qPrintable(item->m_message) );
581  OutputDebugStringA( "\n" );
582 #endif
583 
584  logQueue.enqueue(item);
585 
587  {
588  while (!logQueue.isEmpty())
589  {
590  item = logQueue.dequeue();
591  qLock.unlock();
592  logThread->handleItem(item);
593  logThread->logConsole(item);
594  item->DecrRef();
595  qLock.relock();
596  }
597  }
598  else if (logThread && !logThreadFinished && (type & kFlush))
599  {
600  logThread->flush();
601  }
602 }
603 
604 
609 {
610  logPropagateArgList.clear();
611 
612  QString mask = verboseString.simplified().replace(' ', ',');
613  logPropagateArgs = " --verbose " + mask;
614  logPropagateArgList << "--verbose" << mask;
615 
617  {
618  logPropagateArgs += " --logpath " + logPropagateOpts.m_path;
619  logPropagateArgList << "--logpath" << logPropagateOpts.m_path;
620  }
621 
622  QString name = logLevelGetName(logLevel);
623  logPropagateArgs += " --loglevel " + name;
624  logPropagateArgList << "--loglevel" << name;
625 
626  for (int i = 0; i < logPropagateOpts.m_quiet; i++)
627  {
628  logPropagateArgs += " --quiet";
629  logPropagateArgList << "--quiet";
630  }
631 
633  {
634  logPropagateArgs += " --enable-dblog";
635  logPropagateArgList << "--enable-dblog";
636  }
637 
638 #if !defined(_WIN32) && !defined(Q_OS_ANDROID)
639  if (logPropagateOpts.m_facility >= 0)
640  {
641  const CODE *syslogname = nullptr;
642  for (syslogname = &facilitynames[0];
643  (syslogname->c_name &&
644  syslogname->c_val != logPropagateOpts.m_facility); syslogname++);
645 
646  logPropagateArgs += QString(" --syslog %1").arg(syslogname->c_name);
647  logPropagateArgList << "--syslog" << syslogname->c_name;
648  }
649 #if CONFIG_SYSTEMD_JOURNAL
650  else if (logPropagateOpts.m_facility == SYSTEMD_JOURNAL_FACILITY)
651  {
652  logPropagateArgs += " --systemd-journal";
653  logPropagateArgList << "--systemd-journal";
654  }
655 #endif
656 #endif
657 }
658 
662 {
663  return logPropagateOpts.m_quiet != 0;
664 }
665 
680 void logStart(const QString& logfile, bool progress, int quiet, int facility,
681  LogLevel_t level, bool dblog, bool propagate, bool testHarness)
682 {
683  if (logThread && logThread->isRunning())
684  return;
685 
686  logLevel = level;
687  LOG(VB_GENERAL, LOG_NOTICE, QString("Setting Log Level to LOG_%1")
688  .arg(logLevelGetName(logLevel).toUpper()));
689 
690  logPropagateOpts.m_propagate = propagate;
692  logPropagateOpts.m_facility = facility;
693  logPropagateOpts.m_dblog = dblog;
694 
695  if (propagate)
696  {
697  QFileInfo finfo(logfile);
698  QString path = finfo.path();
699  logPropagateOpts.m_path = path;
700  }
701 
703  if (testHarness)
704  return;
705 
706  QString table = dblog ? QString("logging") : QString("");
707 
708  if (!logThread)
709  logThread = new LoggerThread(logfile, progress, quiet, table, facility);
710 
711  logThread->start();
712 }
713 
715 void logStop(void)
716 {
717  if (logThread)
718  {
719  logThread->stop();
720  logThread->wait();
721  delete logThread;
722  logThread = nullptr;
723  }
724 }
725 
730 void loggingRegisterThread(const QString &name)
731 {
732  if (logThreadFinished)
733  return;
734 
735  QMutexLocker qLock(&logQueueMutex);
736 
737  LoggingItem *item = LoggingItem::create(__FILE__, __FUNCTION__,
738  __LINE__, LOG_DEBUG,
739  kRegistering);
740  if (item)
741  {
742  item->setThreadName((char *)name.toLocal8Bit().constData());
743  logQueue.enqueue(item);
744  }
745 }
746 
750 {
751  if (logThreadFinished)
752  return;
753 
754  QMutexLocker qLock(&logQueueMutex);
755 
756  LoggingItem *item = LoggingItem::create(__FILE__, __FUNCTION__, __LINE__,
757  LOG_DEBUG,
759  if (item)
760  logQueue.enqueue(item);
761 }
762 
763 
767 int syslogGetFacility(const QString& facility)
768 {
769 #ifdef _WIN32
770  LOG(VB_GENERAL, LOG_NOTICE,
771  "Windows does not support syslog, disabling" );
772  Q_UNUSED(facility);
773  return( -2 );
774 #elif defined(Q_OS_ANDROID)
775  LOG(VB_GENERAL, LOG_NOTICE,
776  "Android does not support syslog, disabling" );
777  Q_UNUSED(facility);
778  return( -2 );
779 #else
780  const CODE *name = nullptr;
781  int i = 0;
782  QByteArray ba = facility.toLocal8Bit();
783  char *string = (char *)ba.constData();
784 
785  for (i = 0, name = &facilitynames[0];
786  name->c_name && (strcmp(name->c_name, string) != 0); i++, name++);
787 
788  return( name->c_val );
789 #endif
790 }
791 
795 LogLevel_t logLevelGet(const QString& level)
796 {
797  QMutexLocker locker(&loglevelMapMutex);
798  if (!verboseInitialized)
799  {
800  locker.unlock();
801  verboseInit();
802  locker.relock();
803  }
804 
805  for (auto *item : qAsConst(loglevelMap))
806  {
807  if ( item->name == level.toLower() )
808  return (LogLevel_t)item->value;
809  }
810 
811  return LOG_UNKNOWN;
812 }
813 
817 QString logLevelGetName(LogLevel_t level)
818 {
819  QMutexLocker locker(&loglevelMapMutex);
820  if (!verboseInitialized)
821  {
822  locker.unlock();
823  verboseInit();
824  locker.relock();
825  }
826  LoglevelMap::iterator it = loglevelMap.find((int)level);
827 
828  if ( it == loglevelMap.end() )
829  return QString("unknown");
830 
831  return (*it)->name;
832 }
833 
840 void verboseAdd(uint64_t mask, QString name, bool additive, QString helptext)
841 {
842  auto *item = new VerboseDef;
843 
844  item->mask = mask;
845  // VB_GENERAL -> general
846  name.remove(0, 3);
847  name = name.toLower();
848  item->name = name;
849  item->additive = additive;
850  item->helpText = std::move(helptext);
851 
852  verboseMap.insert(name, item);
853 }
854 
860 void loglevelAdd(int value, QString name, char shortname)
861 {
862  auto *item = new LoglevelDef;
863 
864  item->value = value;
865  // LOG_CRIT -> crit
866  name.remove(0, 4);
867  name = name.toLower();
868  item->name = name;
869  item->shortname = shortname;
870 
871  loglevelMap.insert(value, item);
872 }
873 
875 void verboseInit(void)
876 {
877  QMutexLocker locker(&verboseMapMutex);
878  QMutexLocker locker2(&loglevelMapMutex);
879  verboseMap.clear();
880  loglevelMap.clear();
881 
882  // This looks funky, so I'll put some explanation here. The verbosedefs.h
883  // file gets included as part of the mythlogging.h include, and at that
884  // time, the normal (without MYTH_IMPLEMENT_VERBOSE defined) code case will
885  // define the VerboseMask enum. At this point, we force it to allow us to
886  // include the file again, but with MYTH_IMPLEMENT_VERBOSE set so that the
887  // single definition of the VB_* values can be shared to define also the
888  // contents of verboseMap, via repeated calls to verboseAdd()
889 
890 #undef VERBOSEDEFS_H_
891 #define MYTH_IMPLEMENT_VERBOSE
892 #include "verbosedefs.h"
893 
894  verboseInitialized = true;
895 }
896 
897 
900 void verboseHelp(void)
901 {
902  QString m_verbose = userDefaultValueStr.simplified().replace(' ', ',');
903 
904  std::cerr << "Verbose debug levels.\n"
905  "Accepts any combination (separated by comma) of:\n\n";
906 
907  for (VerboseMap::Iterator vit = verboseMap.begin();
908  vit != verboseMap.end(); ++vit )
909  {
910  VerboseDef *item = vit.value();
911  QString name = QString(" %1").arg(item->name, -15, ' ');
912  if (item->helpText.isEmpty())
913  continue;
914  std::cerr << name.toLocal8Bit().constData() << " - "
915  << item->helpText.toLocal8Bit().constData() << std::endl;
916  }
917 
918  std::cerr << std::endl <<
919  "The default for this program appears to be: '-v " <<
920  m_verbose.toLocal8Bit().constData() << "'\n\n"
921  "Most options are additive except for 'none' and 'all'.\n"
922  "These two are semi-exclusive and take precedence over any\n"
923  "other options. However, you may use something like\n"
924  "'-v none,jobqueue' to receive only JobQueue related messages\n"
925  "and override the default verbosity level.\n\n"
926  "Additive options may also be subtracted from 'all' by\n"
927  "prefixing them with 'no', so you may use '-v all,nodatabase'\n"
928  "to view all but database debug messages.\n\n";
929 
930  std::cerr
931  << "The 'global' loglevel is specified with --loglevel, but can be\n"
932  << "overridden on a component by component basis by appending "
933  << "':level'\n"
934  << "to the component.\n"
935  << " For example: -v gui:debug,channel:notice,record\n\n";
936 
937  std::cerr << "Some debug levels may not apply to this program.\n" << std::endl;
938 }
939 
943 int verboseArgParse(const QString& arg)
944 {
945  QString option;
946 
947  if (!verboseInitialized)
948  verboseInit();
949 
950  QMutexLocker locker(&verboseMapMutex);
951 
954 
955  if (arg.startsWith('-'))
956  {
957  std::cerr << "Invalid or missing argument to -v/--verbose option\n";
959  }
960 
961 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
962  QStringList verboseOpts = arg.split(QRegularExpression("[^\\w:]+"),
963  QString::SkipEmptyParts);
964 #else
965  QStringList verboseOpts = arg.split(QRegularExpression("[^\\w:]+"),
966  Qt::SkipEmptyParts);
967 #endif
968  for (const auto& opt : qAsConst(verboseOpts))
969  {
970  option = opt.toLower();
971  bool reverseOption = false;
972  QString optionLevel;
973 
974  if (option != "none" && option.startsWith("no"))
975  {
976  reverseOption = true;
977  option = option.right(option.length() - 2);
978  }
979 
980  if (option == "help")
981  {
982  verboseHelp();
984  }
985  if (option == "important")
986  {
987  std::cerr << "The \"important\" log mask is no longer valid.\n";
988  }
989  else if (option == "extra")
990  {
991  std::cerr << "The \"extra\" log mask is no longer valid. Please try "
992  "--loglevel debug instead.\n";
993  }
994  else if (option == "default")
995  {
997  {
1000  }
1001  else
1002  {
1005  }
1006  }
1007  else
1008  {
1009  int idx = option.indexOf(':');
1010  if (idx != -1)
1011  {
1012  optionLevel = option.mid(idx + 1);
1013  option = option.left(idx);
1014  }
1015 
1016  VerboseDef *item = verboseMap.value(option);
1017 
1018  if (item)
1019  {
1020  if (reverseOption)
1021  {
1022  verboseMask &= ~(item->mask);
1023  verboseString = verboseString.remove(' ' + item->name);
1024  verboseString += " no" + item->name;
1025  }
1026  else
1027  {
1028  if (item->additive)
1029  {
1030  if (!(verboseMask & item->mask))
1031  {
1032  verboseMask |= item->mask;
1033  verboseString += ' ' + item->name;
1034  }
1035  }
1036  else
1037  {
1038  verboseMask = item->mask;
1039  verboseString = item->name;
1040  }
1041 
1042  if (!optionLevel.isEmpty())
1043  {
1044  LogLevel_t level = logLevelGet(optionLevel);
1045  if (level != LOG_UNKNOWN)
1046  componentLogLevel[item->mask] = level;
1047  }
1048  }
1049  }
1050  else
1051  {
1052  std::cerr << "Unknown argument for -v/--verbose: " <<
1053  option.toLocal8Bit().constData() << std::endl;;
1055  }
1056  }
1057  }
1058 
1059  if (!haveUserDefaultValues)
1060  {
1061  haveUserDefaultValues = true;
1064  }
1065 
1066  return GENERIC_EXIT_OK;
1067 }
1068 
1073 QString logStrerror(int errnum)
1074 {
1075  return QString("%1 (%2)").arg(strerror(errnum)).arg(errnum);
1076 }
1077 
1078 
1079 /*
1080  * vim:ts=4:sw=4:ai:et:si:sts=4
1081  */
LogPropagateOpts::m_path
QString m_path
Definition: logging.cpp:82
loggingDeregisterThread
void loggingDeregisterThread(void)
Deregister the current thread's name.
Definition: logging.cpp:749
LoglevelMap
QMap< int, LoglevelDef * > LoglevelMap
Definition: verbosedefs.h:216
LogPropagateOpts::m_dblog
bool m_dblog
Definition: logging.cpp:81
LoggingItem::m_line
int m_line
Definition: logging.h:129
debugRegistration
static bool debugRegistration
Definition: logging.cpp:75
logForwardStop
void logForwardStop(void)
Definition: loggingserver.cpp:875
LoggingItem::getTimestamp
QString getTimestamp(const char *format="yyyy-MM-dd HH:mm:ss") const
Convert numerical timestamp to a readable date and time.
Definition: logging.cpp:204
logThreadHash
static QHash< uint64_t, QString > logThreadHash
Definition: logging.cpp:69
logStrerror
QString logStrerror(int errnum)
Verbose helper function for ENO macro.
Definition: logging.cpp:1073
MThread::start
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:286
GENERIC_EXIT_OK
#define GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:10
LoggingItem::threadName
QString threadName
Definition: logging.h:69
dbutil.h
LoggerThread::m_tablename
QString m_tablename
Cached table name for db logging.
Definition: logging.h:184
ReferenceCounter::DecrRef
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
Definition: referencecounter.cpp:125
logQueue
static QQueue< LoggingItem * > logQueue
Definition: logging.cpp:65
mythdb.h
false
VERBOSE_PREAMBLE false
Definition: verbosedefs.h:85
logPropagateCalc
void logPropagateCalc(void)
Generate the logPropagateArgs global with the latest logging level, mask, etc to propagate to all of ...
Definition: logging.cpp:608
componentLogLevel
ComponentLogLevelMap componentLogLevel
Definition: logging.cpp:103
LoggerThread::m_waitNotEmpty
QWaitCondition * m_waitNotEmpty
Condition variable for waiting for the queue to not be empty Protected by logQueueMutex.
Definition: logging.h:169
MThread::wait
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:303
LoggerThread::m_appname
QString m_appname
Cached application name.
Definition: logging.h:182
logLevel
LogLevel_t logLevel
Definition: logging.cpp:89
loglevelMapMutex
QMutex loglevelMapMutex
Definition: logging.cpp:96
verboseHelp
void verboseHelp(void)
Outputs the Verbose levels and their descriptions (for –verbose help)
Definition: logging.cpp:900
LoggingItem::getThreadName
QString getThreadName(void)
Get the name of the thread that produced the LoggingItem.
Definition: logging.cpp:149
LoggingItem::m_type
LoggingType m_type
Definition: logging.h:130
progress
bool progress
Definition: mythtv/programs/mythcommflag/main.cpp:72
verboseInit
void verboseInit(void)
Initialize the logging levels and verbose levels.
Definition: logging.cpp:875
mythburn.write
def write(text, progress=True)
Definition: mythburn.py:308
logStart
void logStart(const QString &logfile, bool progress, int quiet, int facility, LogLevel_t level, bool dblog, bool propagate, bool testHarness)
Entry point to start logging for the application.
Definition: logging.cpp:680
logPropagateOpts
LogPropagateOpts logPropagateOpts
Definition: logging.cpp:85
syslogGetFacility
int syslogGetFacility(const QString &facility)
Map a syslog facility name back to the enumerated value.
Definition: logging.cpp:767
LoggerThread
The logging thread that consumes the logging queue and dispatches each LoggingItem.
Definition: logging.h:152
LoggerThread::m_waitEmpty
QWaitCondition * m_waitEmpty
Condition variable for waiting for the queue to be empty Protected by logQueueMutex.
Definition: logging.h:173
logfile
QString logfile
Definition: mythtv/programs/mythjobqueue/main.cpp:41
kDeregistering
@ kDeregistering
Definition: logging.h:43
logForwardMessage
void logForwardMessage(const QList< QByteArray > &msg)
Definition: loggingserver.cpp:891
LoggingItem::epoch
qlonglong epoch
Definition: logging.h:66
LoggerThread::LoggerThread
LoggerThread(QString filename, bool progress, bool quiet, QString table, int facility)
LoggerThread constructor.
Definition: logging.cpp:231
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
MThread::RunProlog
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
Definition: mthread.cpp:196
verbosedefs.h
logForwardStart
bool logForwardStart(void)
Definition: loggingserver.cpp:866
build_compdb.file
file
Definition: build_compdb.py:55
mythdirs.h
LoggingItem::tid
qlonglong tid
Definition: logging.h:60
GENERIC_EXIT_INVALID_CMDLINE
#define GENERIC_EXIT_INVALID_CMDLINE
Command line parse error.
Definition: exitcodes.h:15
LogPropagateOpts::m_facility
int m_facility
Definition: logging.cpp:80
LoggingType
LoggingType
Definition: logging.h:40
LoggingItem::m_function
QString m_function
Definition: logging.h:135
mythsystemlegacy.h
logThreadFinished
static bool logThreadFinished
Definition: logging.cpp:74
LoggingItem::setThreadName
void setThreadName(const QString &val)
Definition: logging.h:119
LoggingItem
The logging items that are generated by LOG() and are sent to the console.
Definition: logging.h:55
verboseString
QString verboseString
Definition: logging.cpp:102
LoggerThread::m_progress
bool m_progress
show only LOG_ERR and more important (console only)
Definition: logging.h:180
LoggerThread::fillItem
void fillItem(LoggingItem *item)
Definition: logging.cpp:513
LoggingItem::getLevelChar
char getLevelChar(void)
Get the message log level as a single character.
Definition: logging.cpp:219
LogPrintLine
void LogPrintLine(uint64_t mask, LogLevel_t level, const char *file, int line, const char *function, QString message)
Format and send a log message into the queue.
Definition: logging.cpp:564
verboseAdd
void verboseAdd(uint64_t mask, QString name, bool additive, QString helptext)
Add a verbose level to the verboseMap.
Definition: logging.cpp:840
kFlush
@ kFlush
Definition: logging.h:44
mythlogging.h
logLevelGetName
QString logLevelGetName(LogLevel_t level)
Map a log level enumerated value back to the name.
Definition: logging.cpp:817
LoggingItem::m_level
LogLevel_t m_level
Definition: logging.h:131
LoggingItem::pid
int pid
Definition: logging.h:59
loggingRegisterThread
void loggingRegisterThread(const QString &name)
Register the current thread with the given name.
Definition: logging.cpp:730
verboseMask
uint64_t verboseMask
Definition: logging.cpp:101
hardwareprofile.i18n.t
t
Definition: i18n.py:36
LogPropagateOpts
Definition: logging.cpp:77
compat.h
LoggerThread::m_aborted
bool m_aborted
Flag to abort the thread.
Definition: logging.h:177
logLevelGet
LogLevel_t logLevelGet(const QString &level)
Map a log level name back to the enumerated value.
Definition: logging.cpp:795
verboseInitialized
bool verboseInitialized
Definition: logging.cpp:91
logThreadMutex
static QMutex logThreadMutex
Definition: logging.cpp:68
MThread::qthread
QThread * qthread(void)
Returns the thread, this will always return the same pointer no matter how often you restart the thre...
Definition: mthread.cpp:236
verboseDefaultStr
const QString verboseDefaultStr
Definition: logging.cpp:99
LoggingItem::setThreadTid
void setThreadTid(void)
Set the thread ID of the thread that produced the LoggingItem.
Definition: logging.cpp:178
LogPropagateOpts::m_quiet
int m_quiet
Definition: logging.cpp:79
LoggerThread::m_filename
QString m_filename
Filename of debug logfile.
Definition: logging.h:179
LoggerThread::run
void run(void) override
Run the logging thread.
Definition: logging.cpp:269
LoggingItem::m_message
QString m_message
Definition: logging.h:140
MThread::RunEpilog
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:209
kMessage
@ kMessage
Definition: logging.h:41
userDefaultValueInt
uint64_t userDefaultValueInt
Definition: logging.cpp:105
LoggerThread::logConsole
bool logConsole(LoggingItem *item) const
Process a log message, writing to the console.
Definition: logging.cpp:387
LoglevelDef::value
int value
Definition: verbosedefs.h:212
LoggerThread::flush
bool flush(int timeoutMS=200000)
Wait for the queue to be flushed (up to a timeout)
Definition: logging.cpp:499
verboseMap
VerboseMap verboseMap
Definition: logging.cpp:92
LoggingItem::setFacility
void setFacility(const int val)
Definition: logging.h:114
LoggerThread::stop
void stop(void)
Stop the thread by setting the abort flag after waiting a second for the queue to be flushed.
Definition: logging.cpp:487
quiet
int quiet
Definition: mythtv/programs/mythcommflag/main.cpp:71
userDefaultValueStr
QString userDefaultValueStr
Definition: logging.cpp:106
LoggingItem::setTable
void setTable(const QString &val)
Definition: logging.h:121
LoggerThread::m_quiet
bool m_quiet
silence the console (console only)
Definition: logging.h:181
LoggerThread::m_facility
int m_facility
Cached syslog facility (or -1 to disable)
Definition: logging.h:185
logStop
void logStop(void)
Entry point for stopping logging for an application.
Definition: logging.cpp:715
LoggingItem::m_epoch
std::chrono::microseconds m_epoch
Definition: logging.h:133
logThread
static LoggerThread * logThread
Definition: logging.cpp:67
verboseArgParse
int verboseArgParse(const QString &arg)
Parse the –verbose commandline argument and set the verbose level.
Definition: logging.cpp:943
LogPropagateOpts::m_propagate
bool m_propagate
Definition: logging.cpp:78
haveUserDefaultValues
bool haveUserDefaultValues
Definition: logging.cpp:107
mythcorecontext.h
verboseDefaultInt
const uint64_t verboseDefaultInt
Definition: logging.cpp:98
LoggingItem::m_threadName
QString m_threadName
Definition: logging.h:136
logQueueMutex
static QMutex logQueueMutex
Definition: logging.cpp:64
LoggingItem::create
static LoggingItem * create(const char *_file, const char *_function, int _line, LogLevel_t _level, LoggingType _type)
Create a new LoggingItem.
Definition: logging.cpp:534
LoggingItem::m_file
QString m_file
Definition: logging.h:134
logThreadTidHash
static QHash< uint64_t, int64_t > logThreadTidHash
Definition: logging.cpp:72
std
Definition: mythchrono.h:23
mythsyslog.h
logging.h
LoggingItem::getTimestampUs
QString getTimestampUs(const char *format="yyyy-MM-dd HH:mm:ss") const
Definition: logging.cpp:211
logPropagateArgList
QStringList logPropagateArgList
Definition: logging.cpp:87
LoggingItem::m_threadId
qulonglong m_threadId
Definition: logging.h:128
MThread
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:48
LoggingItem::m_tid
qlonglong m_tid
Definition: logging.h:127
ComponentLogLevelMap
QMap< uint64_t, LogLevel_t > ComponentLogLevelMap
Definition: verbosedefs.h:217
MThread::isRunning
bool isRunning(void) const
Definition: mthread.cpp:266
loglevelAdd
void loglevelAdd(int value, QString name, char shortname)
Add a log level to the logLevelMap.
Definition: logging.cpp:860
kRegistering
@ kRegistering
Definition: logging.h:42
LoggingItem::setAppName
void setAppName(const QString &val)
Definition: logging.h:120
verboseMapMutex
QMutex verboseMapMutex
Definition: logging.cpp:93
logPropagateQuiet
bool logPropagateQuiet(void)
Check if we are propagating a "--quiet".
Definition: logging.cpp:661
LoggerThread::m_pid
pid_t m_pid
Cached pid value.
Definition: logging.h:186
LoggingItem::getThreadTid
int64_t getThreadTid(void)
Get the thread ID of the thread that produced the LoggingItem.
Definition: logging.cpp:165
LoggingItem::toByteArray
QByteArray toByteArray(void)
Definition: logging.cpp:137
logPropagateArgs
QString logPropagateArgs
Definition: logging.cpp:86
logThreadTidMutex
static QMutex logThreadTidMutex
Definition: logging.cpp:71
LoggerThread::handleItem
static void handleItem(LoggingItem *item)
Handles each LoggingItem.
Definition: logging.cpp:325
loglevelMap
LoglevelMap loglevelMap
Definition: logging.cpp:95
exitcodes.h
LoggingItem::LoggingItem
LoggingItem()
Definition: logging.h:143
kStandardIO
@ kStandardIO
Definition: logging.h:45
ReferenceCounter::IncrRef
virtual int IncrRef(void)
Increments reference count.
Definition: referencecounter.cpp:101
build_compdb.filename
filename
Definition: build_compdb.py:21
loggingserver.h
LoggerThread::~LoggerThread
~LoggerThread() override
LoggerThread destructor. Triggers the deletion of all loggers.
Definition: logging.cpp:255
LoggingItem::setPid
void setPid(const int val)
Definition: logging.h:108
LoggingItem::setLogFile
void setLogFile(const QString &val)
Definition: logging.h:122
resetLogging
void resetLogging(void)
Intended for use only by the test harness.
Definition: logging.cpp:115
LoglevelDef
Definition: verbosedefs.h:211
ReferenceCounter
General purpose reference counter.
Definition: referencecounter.h:26
VerboseMap
QMap< QString, VerboseDef * > VerboseMap
Definition: verbosedefs.h:209