MythTV  master
logging.cpp
Go to the documentation of this file.
1 #include <QAtomicInt>
2 #include <QMutex>
3 #include <QMutexLocker>
4 #include <QWaitCondition>
5 #include <QList>
6 #include <QQueue>
7 #include <QHash>
8 #include <QFileInfo>
9 #include <QStringList>
10 #include <QMap>
11 #include <QRegularExpression>
12 #include <QVariantMap>
13 #include <iostream>
14 
15 #include "mythlogging.h"
16 #include "logging.h"
17 #include "loggingserver.h"
18 #include "mythdb.h"
19 #include "mythdirs.h"
20 #include "mythcorecontext.h"
21 #include "mythsystemlegacy.h"
22 #include "mythsignalingtimer.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 CONFIG_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 static QRegExp logRegExp = QRegExp("[%]{1,2}");
67 
68 static LoggerThread *logThread = nullptr;
69 static QMutex logThreadMutex;
70 static QHash<uint64_t, QString> logThreadHash;
71 
72 static QMutex logThreadTidMutex;
73 static QHash<uint64_t, int64_t> logThreadTidHash;
74 
75 static bool logThreadFinished = false;
76 static bool debugRegistration = false;
77 
80  int m_quiet;
82  bool m_dblog;
83  QString m_path;
84 };
85 
86 LogPropagateOpts logPropagateOpts {false, 0, 0, true, ""};
88 QStringList logPropagateArgList;
89 
90 LogLevel_t logLevel = LOG_INFO;
91 
92 bool verboseInitialized = false;
95 
98 
99 const uint64_t verboseDefaultInt = VB_GENERAL;
100 const char *verboseDefaultStr = " general";
101 
103 QString verboseString = QString(verboseDefaultStr);
105 
109 
110 void verboseAdd(uint64_t mask, QString name, bool additive, QString helptext);
111 void loglevelAdd(int value, QString name, char shortname);
112 void verboseInit(void);
113 void verboseHelp(void);
114 
116 void resetLogging(void)
117 {
119  verboseString = QString(verboseDefaultStr);
122  haveUserDefaultValues = false;
123 
124  verboseInit();
125 }
126 
127 void loggingGetTimeStamp(qlonglong *epoch, uint *usec)
128 {
129 #if HAVE_GETTIMEOFDAY
130  struct timeval tv {};
131  gettimeofday(&tv, nullptr);
132  *epoch = tv.tv_sec;
133  if (usec)
134  *usec = tv.tv_usec;
135 #else
136  /* Stupid system has no gettimeofday, use less precise QDateTime */
137  QDateTime date = MythDate::current();
138  *epoch = date.toTime_t();
139  if (usec)
140  {
141  QTime time = date.time();
142  *usec = time.msec() * 1000;
143  }
144 #endif
145 }
146 
147 LoggingItem::LoggingItem(const char *_file, const char *_function,
148  int _line, LogLevel_t _level, LoggingType _type) :
149  ReferenceCounter("LoggingItem", false),
150  m_threadId((uint64_t)(QThread::currentThreadId())),
151  m_line(_line), m_type(_type), m_level(_level),
152  m_file(_file), m_function(_function)
153 {
155  setThreadTid();
156 }
157 
158 QByteArray LoggingItem::toByteArray(void)
159 {
160  QVariantMap variant = QJsonWrapper::qobject2qvariant(this);
161  QByteArray json = QJsonWrapper::toJson(variant);
162 
163  //cout << json.constData() << endl;
164 
165  return json;
166 }
167 
171 {
172  static constexpr char const *kSUnknown = "thread_unknown";
173 
174  if( !m_threadName.isEmpty() )
175  return m_threadName;
176 
177  QMutexLocker locker(&logThreadMutex);
178  return logThreadHash.value(m_threadId, kSUnknown);
179 }
180 
187 {
188  QMutexLocker locker(&logThreadTidMutex);
189  m_tid = logThreadTidHash.value(m_threadId, 0);
190  return m_tid;
191 }
192 
200 {
201  QMutexLocker locker(&logThreadTidMutex);
202 
203  m_tid = logThreadTidHash.value(m_threadId, -1);
204  if (m_tid == -1)
205  {
206  m_tid = 0;
207 
208 #if defined(Q_OS_ANDROID)
209  m_tid = (int64_t)gettid();
210 #elif defined(linux)
211  m_tid = syscall(SYS_gettid);
212 #elif defined(__FreeBSD__)
213  long lwpid;
214  int dummy = thr_self( &lwpid );
215  (void)dummy;
216  m_tid = (int64_t)lwpid;
217 #elif CONFIG_DARWIN
218  m_tid = (int64_t)mach_thread_self();
219 #endif
221  }
222 }
223 
225 QString LoggingItem::getTimestamp (void) const
226 {
228  QString timestamp = epoch.toString("yyyy-MM-dd HH:mm:ss");
229  return timestamp;
230 }
231 
232 QString LoggingItem::getTimestampUs (void) const
233 {
234  QString timestamp = getTimestamp();
235  timestamp += QString(".%1").arg(m_usec,6,10,QChar('0'));
236  return timestamp;
237 }
238 
241 {
242  QMutexLocker locker(&loglevelMapMutex);
243  LoglevelMap::iterator it = loglevelMap.find(m_level);
244  if (it != loglevelMap.end())
245  return (*it)->shortname;
246  return '-';
247 }
248 
253  QString table, int facility) :
254  MThread("Logger"),
255  m_waitNotEmpty(new QWaitCondition()),
256  m_waitEmpty(new QWaitCondition()),
257  m_filename(std::move(filename)), m_progress(progress), m_quiet(quiet),
258  m_tablename(std::move(table)), m_facility(facility), m_pid(getpid())
259 {
260  char *debug = getenv("VERBOSE_THREADS");
261  if (debug != nullptr)
262  {
263  LOG(VB_GENERAL, LOG_NOTICE,
264  "Logging thread registration/deregistration enabled!");
265  debugRegistration = true;
266  }
267 
268  if (!logForwardStart())
269  {
270  LOG(VB_GENERAL, LOG_ERR,
271  "Failed to start LogServer thread");
272  }
273  moveToThread(qthread());
274 }
275 
278 {
279  stop();
280  wait();
281  logForwardStop();
282 
283  delete m_waitNotEmpty;
284  delete m_waitEmpty;
285 }
286 
292 {
293  RunProlog();
294 
295  logThreadFinished = false;
296 
297  LOG(VB_GENERAL, LOG_INFO, "Added logging to the console");
298 
299  bool dieNow = false;
300 
301  QMutexLocker qLock(&logQueueMutex);
302 
303  while (!m_aborted || !logQueue.isEmpty())
304  {
305  qLock.unlock();
306  qApp->processEvents(QEventLoop::AllEvents, 10);
307  qApp->sendPostedEvents(nullptr, QEvent::DeferredDelete);
308 
309  qLock.relock();
310  if (logQueue.isEmpty())
311  {
312  m_waitEmpty->wakeAll();
313  m_waitNotEmpty->wait(qLock.mutex(), 100);
314  continue;
315  }
316 
317  LoggingItem *item = logQueue.dequeue();
318  qLock.unlock();
319 
320  fillItem(item);
321  handleItem(item);
322  logConsole(item);
323  item->DecrRef();
324 
325  qLock.relock();
326  }
327 
328  qLock.unlock();
329 
330  // This must be before the timer stop below or we deadlock when the timer
331  // thread tries to deregister, and we wait for it.
332  logThreadFinished = true;
333 
334  RunEpilog();
335 
336  // cppcheck-suppress knownConditionTrueFalse
337  if (dieNow)
338  {
339  qApp->processEvents();
340  }
341 }
342 
349 {
350  if (item->m_type & kRegistering)
351  {
352  item->m_tid = item->getThreadTid();
353 
354  QMutexLocker locker(&logThreadMutex);
355  logThreadHash[item->m_threadId] = item->m_threadName;
356 
357  if (debugRegistration)
358  {
359  item->m_message = QString("Thread 0x%1 (%2) registered as \'%3\'")
360  .arg(QString::number(item->m_threadId,16),
361  QString::number(item->m_tid),
362  logThreadHash[item->m_threadId]);
363  }
364  }
365  else if (item->m_type & kDeregistering)
366  {
367  int64_t tid = 0;
368 
369  {
370  QMutexLocker locker(&logThreadTidMutex);
371  if( logThreadTidHash.contains(item->m_threadId) )
372  {
373  tid = logThreadTidHash[item->m_threadId];
374  logThreadTidHash.remove(item->m_threadId);
375  }
376  }
377 
378  QMutexLocker locker(&logThreadMutex);
379  if (logThreadHash.contains(item->m_threadId))
380  {
381  if (debugRegistration)
382  {
383  item->m_message = QString("Thread 0x%1 (%2) deregistered as \'%3\'")
384  .arg(QString::number(item->m_threadId,16),
385  QString::number(tid),
386  logThreadHash[item->m_threadId]);
387  }
388  logThreadHash.remove(item->m_threadId);
389  }
390  }
391 
392  if (!item->m_message.isEmpty())
393  {
401  QList<QByteArray> list;
402  list.append(QByteArray());
403  list.append(item->toByteArray());
404  logForwardMessage(list);
405  }
406 }
407 
411 {
412  if (m_quiet || (m_progress && item->m_level > LOG_ERR))
413  return false;
414 
415  if (!(item->m_type & kMessage))
416  return false;
417 
418  item->IncrRef();
419 
420 #ifndef Q_OS_ANDROID
421  std::string line;
422 
423  if (item->m_type & kStandardIO)
424  {
425  line = qPrintable(item->m_message);
426  }
427  else
428  {
429  QString timestamp = item->getTimestampUs();
430  char shortname = item->getLevelChar();
431 
432 #if CONFIG_DEBUGTYPE
433  if (item->tid())
434  {
435  line = qPrintable(QString("%1 %2 [%3/%4] %5 %6:%7:%8 %9\n")
436  .arg(timestamp, QString(shortname),
437  QString::number(item->pid()),
438  QString::number(item->tid()),
439  item->threadName(),
440  item->m_file,
441  QString::number(item->m_line),
442  item->m_function,
443  item->m_message));
444  }
445  else
446  {
447  line = qPrintable(QString("%1 %2 [%3] %4 %5:%6:%7 %8\n")
448  .arg(timestamp, QString(shortname),
449  QString::number(item->pid()),
450  item->threadName(),
451  item->m_file,
452  QString::number(item->m_line),
453  item->m_function,
454  item->m_message));
455  }
456 #else
457  line = qPrintable(QString("%1 %2 %3\n")
458  .arg(timestamp, QString(shortname),
459  item->m_message));
460 #endif
461  }
462 
463  (void)write(1, line.data(), line.size());
464 
465 #else // Q_OS_ANDROID
466 
467  android_LogPriority aprio;
468  switch (item->m_level)
469  {
470  case LOG_EMERG:
471  aprio = ANDROID_LOG_FATAL;
472  break;
473  case LOG_ALERT:
474  case LOG_CRIT:
475  case LOG_ERR:
476  aprio = ANDROID_LOG_ERROR;
477  break;
478  case LOG_WARNING:
479  aprio = ANDROID_LOG_WARN;
480  break;
481  case LOG_NOTICE:
482  case LOG_INFO:
483  aprio = ANDROID_LOG_INFO;
484  break;
485  case LOG_DEBUG:
486  aprio = ANDROID_LOG_DEBUG;
487  break;
488  case LOG_UNKNOWN:
489  default:
490  aprio = ANDROID_LOG_UNKNOWN;
491  break;
492  }
493 #if CONFIG_DEBUGTYPE
494  __android_log_print(aprio, "mfe", "%s:%d:%s %s", qPrintable(item->m_file),
495  item->m_line, qPrintable(item->m_function),
496  qPrintable(item->m_message));
497 #else
498  __android_log_print(aprio, "mfe", "%s", qPrintable(item->m_message));
499 #endif
500 #endif
501 
502  item->DecrRef();
503 
504  return true;
505 }
506 
507 
511 {
512  logQueueMutex.lock();
513  flush(1000);
514  m_aborted = true;
515  logQueueMutex.unlock();
516  m_waitNotEmpty->wakeAll();
517 }
518 
522 bool LoggerThread::flush(int timeoutMS)
523 {
524  QElapsedTimer t;
525  t.start();
526  while (!m_aborted && !logQueue.isEmpty() && !t.hasExpired(timeoutMS))
527  {
528  m_waitNotEmpty->wakeAll();
529  int left = timeoutMS - t.elapsed();
530  if (left > 0)
531  m_waitEmpty->wait(&logQueueMutex, left);
532  }
533  return logQueue.isEmpty();
534 }
535 
537 {
538  if (!item)
539  return;
540 
541  item->setPid(m_pid);
542  item->setThreadName(item->getThreadName());
543  item->setAppName(m_appname);
544  item->setTable(m_tablename);
545  item->setLogFile(m_filename);
546  item->setFacility(m_facility);
547 }
548 
549 
557 LoggingItem *LoggingItem::create(const char *_file,
558  const char *_function,
559  int _line, LogLevel_t _level,
560  LoggingType _type)
561 {
562  auto *item = new LoggingItem(_file, _function, _line, _level, _type);
563 
564  return item;
565 }
566 
568 {
569  // Deserialize buffer
570  QVariant variant = QJsonWrapper::parseJson(buf);
571 
572  auto *item = new LoggingItem;
573  QJsonWrapper::qvariant2qobject(variant.toMap(), item);
574 
575  return item;
576 }
577 
578 
587 void LogPrintLine( uint64_t mask, LogLevel_t level, const char *file, int line,
588  const char *function, QString message)
589 {
590  int type = kMessage;
591  type |= (mask & VB_FLUSH) ? kFlush : 0;
592  type |= (mask & VB_STDIO) ? kStandardIO : 0;
593  LoggingItem *item = LoggingItem::create(file, function, line, level,
594  (LoggingType)type);
595  if (!item)
596  return;
597 
598  item->m_message = std::move(message);
599 
600  QMutexLocker qLock(&logQueueMutex);
601 
602 #if defined( _MSC_VER ) && defined( _DEBUG )
603  OutputDebugStringA( qPrintable(item->m_message) );
604  OutputDebugStringA( "\n" );
605 #endif
606 
607  logQueue.enqueue(item);
608 
610  {
611  while (!logQueue.isEmpty())
612  {
613  item = logQueue.dequeue();
614  qLock.unlock();
615  logThread->handleItem(item);
616  logThread->logConsole(item);
617  item->DecrRef();
618  qLock.relock();
619  }
620  }
621  else if (logThread && !logThreadFinished && (type & kFlush))
622  {
623  logThread->flush();
624  }
625 }
626 
627 
632 {
633  logPropagateArgList.clear();
634 
635  QString mask = verboseString.simplified().replace(' ', ',');
636  logPropagateArgs = " --verbose " + mask;
637  logPropagateArgList << "--verbose" << mask;
638 
640  {
641  logPropagateArgs += " --logpath " + logPropagateOpts.m_path;
642  logPropagateArgList << "--logpath" << logPropagateOpts.m_path;
643  }
644 
645  QString name = logLevelGetName(logLevel);
646  logPropagateArgs += " --loglevel " + name;
647  logPropagateArgList << "--loglevel" << name;
648 
649  for (int i = 0; i < logPropagateOpts.m_quiet; i++)
650  {
651  logPropagateArgs += " --quiet";
652  logPropagateArgList << "--quiet";
653  }
654 
656  {
657  logPropagateArgs += " --enable-dblog";
658  logPropagateArgList << "--enable-dblog";
659  }
660 
661 #if !defined(_WIN32) && !defined(Q_OS_ANDROID)
662  if (logPropagateOpts.m_facility >= 0)
663  {
664  const CODE *syslogname = nullptr;
665  for (syslogname = &facilitynames[0];
666  (syslogname->c_name &&
667  syslogname->c_val != logPropagateOpts.m_facility); syslogname++);
668 
669  logPropagateArgs += QString(" --syslog %1").arg(syslogname->c_name);
670  logPropagateArgList << "--syslog" << syslogname->c_name;
671  }
672 #if CONFIG_SYSTEMD_JOURNAL
673  else if (logPropagateOpts.m_facility == SYSTEMD_JOURNAL_FACILITY)
674  {
675  logPropagateArgs += " --systemd-journal";
676  logPropagateArgList << "--systemd-journal";
677  }
678 #endif
679 #endif
680 }
681 
685 {
686  return logPropagateOpts.m_quiet != 0;
687 }
688 
703 void logStart(const QString& logfile, bool progress, int quiet, int facility,
704  LogLevel_t level, bool dblog, bool propagate, bool testHarness)
705 {
706  if (logThread && logThread->isRunning())
707  return;
708 
709  logLevel = level;
710  LOG(VB_GENERAL, LOG_NOTICE, QString("Setting Log Level to LOG_%1")
711  .arg(logLevelGetName(logLevel).toUpper()));
712 
713  logPropagateOpts.m_propagate = propagate;
715  logPropagateOpts.m_facility = facility;
716  logPropagateOpts.m_dblog = dblog;
717 
718  if (propagate)
719  {
720  QFileInfo finfo(logfile);
721  QString path = finfo.path();
722  logPropagateOpts.m_path = path;
723  }
724 
726  if (testHarness)
727  return;
728 
729  QString table = dblog ? QString("logging") : QString("");
730 
731  if (!logThread)
732  logThread = new LoggerThread(logfile, progress, quiet, table, facility);
733 
734  logThread->start();
735 }
736 
738 void logStop(void)
739 {
740  if (logThread)
741  {
742  logThread->stop();
743  logThread->wait();
744  delete logThread;
745  logThread = nullptr;
746  }
747 }
748 
753 void loggingRegisterThread(const QString &name)
754 {
755  if (logThreadFinished)
756  return;
757 
758  QMutexLocker qLock(&logQueueMutex);
759 
760  LoggingItem *item = LoggingItem::create(__FILE__, __FUNCTION__,
761  __LINE__, LOG_DEBUG,
762  kRegistering);
763  if (item)
764  {
765  item->setThreadName((char *)name.toLocal8Bit().constData());
766  logQueue.enqueue(item);
767  }
768 }
769 
773 {
774  if (logThreadFinished)
775  return;
776 
777  QMutexLocker qLock(&logQueueMutex);
778 
779  LoggingItem *item = LoggingItem::create(__FILE__, __FUNCTION__, __LINE__,
780  LOG_DEBUG,
782  if (item)
783  logQueue.enqueue(item);
784 }
785 
786 
790 int syslogGetFacility(const QString& facility)
791 {
792 #ifdef _WIN32
793  LOG(VB_GENERAL, LOG_NOTICE,
794  "Windows does not support syslog, disabling" );
795  Q_UNUSED(facility);
796  return( -2 );
797 #elif defined(Q_OS_ANDROID)
798  LOG(VB_GENERAL, LOG_NOTICE,
799  "Android does not support syslog, disabling" );
800  Q_UNUSED(facility);
801  return( -2 );
802 #else
803  const CODE *name = nullptr;
804  int i = 0;
805  QByteArray ba = facility.toLocal8Bit();
806  char *string = (char *)ba.constData();
807 
808  for (i = 0, name = &facilitynames[0];
809  name->c_name && (strcmp(name->c_name, string) != 0); i++, name++);
810 
811  return( name->c_val );
812 #endif
813 }
814 
818 LogLevel_t logLevelGet(const QString& level)
819 {
820  QMutexLocker locker(&loglevelMapMutex);
821  if (!verboseInitialized)
822  {
823  locker.unlock();
824  verboseInit();
825  locker.relock();
826  }
827 
828  for (auto *item : qAsConst(loglevelMap))
829  {
830  if ( item->name == level.toLower() )
831  return (LogLevel_t)item->value;
832  }
833 
834  return LOG_UNKNOWN;
835 }
836 
840 QString logLevelGetName(LogLevel_t level)
841 {
842  QMutexLocker locker(&loglevelMapMutex);
843  if (!verboseInitialized)
844  {
845  locker.unlock();
846  verboseInit();
847  locker.relock();
848  }
849  LoglevelMap::iterator it = loglevelMap.find((int)level);
850 
851  if ( it == loglevelMap.end() )
852  return QString("unknown");
853 
854  return (*it)->name;
855 }
856 
863 void verboseAdd(uint64_t mask, QString name, bool additive, QString helptext)
864 {
865  auto *item = new VerboseDef;
866 
867  item->mask = mask;
868  // VB_GENERAL -> general
869  name.remove(0, 3);
870  name = name.toLower();
871  item->name = name;
872  item->additive = additive;
873  item->helpText = std::move(helptext);
874 
875  verboseMap.insert(name, item);
876 }
877 
883 void loglevelAdd(int value, QString name, char shortname)
884 {
885  auto *item = new LoglevelDef;
886 
887  item->value = value;
888  // LOG_CRIT -> crit
889  name.remove(0, 4);
890  name = name.toLower();
891  item->name = name;
892  item->shortname = shortname;
893 
894  loglevelMap.insert(value, item);
895 }
896 
898 void verboseInit(void)
899 {
900  QMutexLocker locker(&verboseMapMutex);
901  QMutexLocker locker2(&loglevelMapMutex);
902  verboseMap.clear();
903  loglevelMap.clear();
904 
905  // This looks funky, so I'll put some explanation here. The verbosedefs.h
906  // file gets included as part of the mythlogging.h include, and at that
907  // time, the normal (without MYTH_IMPLEMENT_VERBOSE defined) code case will
908  // define the VerboseMask enum. At this point, we force it to allow us to
909  // include the file again, but with MYTH_IMPLEMENT_VERBOSE set so that the
910  // single definition of the VB_* values can be shared to define also the
911  // contents of verboseMap, via repeated calls to verboseAdd()
912 
913 #undef VERBOSEDEFS_H_
914 #define MYTH_IMPLEMENT_VERBOSE
915 #include "verbosedefs.h"
916 
917  verboseInitialized = true;
918 }
919 
920 
923 void verboseHelp(void)
924 {
925  QString m_verbose = userDefaultValueStr.simplified().replace(' ', ',');
926 
927  std::cerr << "Verbose debug levels.\n"
928  "Accepts any combination (separated by comma) of:\n\n";
929 
930  for (VerboseMap::Iterator vit = verboseMap.begin();
931  vit != verboseMap.end(); ++vit )
932  {
933  VerboseDef *item = vit.value();
934  QString name = QString(" %1").arg(item->name, -15, ' ');
935  if (item->helpText.isEmpty())
936  continue;
937  std::cerr << name.toLocal8Bit().constData() << " - "
938  << item->helpText.toLocal8Bit().constData() << std::endl;
939  }
940 
941  std::cerr << std::endl <<
942  "The default for this program appears to be: '-v " <<
943  m_verbose.toLocal8Bit().constData() << "'\n\n"
944  "Most options are additive except for 'none' and 'all'.\n"
945  "These two are semi-exclusive and take precedence over any\n"
946  "other options. However, you may use something like\n"
947  "'-v none,jobqueue' to receive only JobQueue related messages\n"
948  "and override the default verbosity level.\n\n"
949  "Additive options may also be subtracted from 'all' by\n"
950  "prefixing them with 'no', so you may use '-v all,nodatabase'\n"
951  "to view all but database debug messages.\n\n";
952 
953  std::cerr
954  << "The 'global' loglevel is specified with --loglevel, but can be\n"
955  << "overridden on a component by component basis by appending "
956  << "':level'\n"
957  << "to the component.\n"
958  << " For example: -v gui:debug,channel:notice,record\n\n";
959 
960  std::cerr << "Some debug levels may not apply to this program.\n" << std::endl;
961 }
962 
966 int verboseArgParse(const QString& arg)
967 {
968  QString option;
969 
970  if (!verboseInitialized)
971  verboseInit();
972 
973  QMutexLocker locker(&verboseMapMutex);
974 
976  verboseString = QString(verboseDefaultStr);
977 
978  if (arg.startsWith('-'))
979  {
980  std::cerr << "Invalid or missing argument to -v/--verbose option\n";
982  }
983 
984 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
985  QStringList verboseOpts = arg.split(QRegularExpression("[^\\w:]+"),
986  QString::SkipEmptyParts);
987 #else
988  QStringList verboseOpts = arg.split(QRegularExpression("[^\\w:]+"),
989  Qt::SkipEmptyParts);
990 #endif
991  for (const auto& opt : qAsConst(verboseOpts))
992  {
993  option = opt.toLower();
994  bool reverseOption = false;
995  QString optionLevel;
996 
997  if (option != "none" && option.startsWith("no"))
998  {
999  reverseOption = true;
1000  option = option.right(option.length() - 2);
1001  }
1002 
1003  if (option == "help")
1004  {
1005  verboseHelp();
1007  }
1008  if (option == "important")
1009  {
1010  std::cerr << "The \"important\" log mask is no longer valid.\n";
1011  }
1012  else if (option == "extra")
1013  {
1014  std::cerr << "The \"extra\" log mask is no longer valid. Please try "
1015  "--loglevel debug instead.\n";
1016  }
1017  else if (option == "default")
1018  {
1020  {
1023  }
1024  else
1025  {
1027  verboseString = QString(verboseDefaultStr);
1028  }
1029  }
1030  else
1031  {
1032  int idx = option.indexOf(':');
1033  if (idx != -1)
1034  {
1035  optionLevel = option.mid(idx + 1);
1036  option = option.left(idx);
1037  }
1038 
1039  VerboseDef *item = verboseMap.value(option);
1040 
1041  if (item)
1042  {
1043  if (reverseOption)
1044  {
1045  verboseMask &= ~(item->mask);
1046  verboseString = verboseString.remove(' ' + item->name);
1047  verboseString += " no" + item->name;
1048  }
1049  else
1050  {
1051  if (item->additive)
1052  {
1053  if (!(verboseMask & item->mask))
1054  {
1055  verboseMask |= item->mask;
1056  verboseString += ' ' + item->name;
1057  }
1058  }
1059  else
1060  {
1061  verboseMask = item->mask;
1062  verboseString = item->name;
1063  }
1064 
1065  if (!optionLevel.isEmpty())
1066  {
1067  LogLevel_t level = logLevelGet(optionLevel);
1068  if (level != LOG_UNKNOWN)
1069  componentLogLevel[item->mask] = level;
1070  }
1071  }
1072  }
1073  else
1074  {
1075  std::cerr << "Unknown argument for -v/--verbose: " <<
1076  option.toLocal8Bit().constData() << std::endl;;
1078  }
1079  }
1080  }
1081 
1082  if (!haveUserDefaultValues)
1083  {
1084  haveUserDefaultValues = true;
1087  }
1088 
1089  return GENERIC_EXIT_OK;
1090 }
1091 
1096 QString logStrerror(int errnum)
1097 {
1098  return QString("%1 (%2)").arg(strerror(errnum)).arg(errnum);
1099 }
1100 
1101 
1102 /*
1103  * vim:ts=4:sw=4:ai:et:si:sts=4
1104  */
LogPropagateOpts::m_path
QString m_path
Definition: logging.cpp:83
loggingDeregisterThread
void loggingDeregisterThread(void)
Deregister the current thread's name.
Definition: logging.cpp:772
LoglevelMap
QMap< int, LoglevelDef * > LoglevelMap
Definition: verbosedefs.h:216
LogPropagateOpts::m_dblog
bool m_dblog
Definition: logging.cpp:82
LoggingItem::m_line
int m_line
Definition: logging.h:132
debugRegistration
static bool debugRegistration
Definition: logging.cpp:76
logForwardStop
void logForwardStop(void)
Definition: loggingserver.cpp:878
logThreadHash
static QHash< uint64_t, QString > logThreadHash
Definition: logging.cpp:70
logStrerror
QString logStrerror(int errnum)
Verbose helper function for ENO macro.
Definition: logging.cpp:1096
MThread::start
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:288
GENERIC_EXIT_OK
#define GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:10
LoggingItem::threadName
QString threadName
Definition: logging.h:71
dbutil.h
LoggerThread::m_tablename
QString m_tablename
Cached table name for db logging.
Definition: logging.h:187
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:631
componentLogLevel
ComponentLogLevelMap componentLogLevel
Definition: logging.cpp:104
LoggerThread::m_waitNotEmpty
QWaitCondition * m_waitNotEmpty
Condition variable for waiting for the queue to not be empty Protected by logQueueMutex.
Definition: logging.h:172
LoggerThread::m_appname
QString m_appname
Cached application name.
Definition: logging.h:185
logLevel
LogLevel_t logLevel
Definition: logging.cpp:90
loglevelMapMutex
QMutex loglevelMapMutex
Definition: logging.cpp:97
verboseHelp
void verboseHelp(void)
Outputs the Verbose levels and their descriptions (for –verbose help)
Definition: logging.cpp:923
LoggingItem::getThreadName
QString getThreadName(void)
Get the name of the thread that produced the LoggingItem.
Definition: logging.cpp:170
LoggingItem::m_epoch
qlonglong m_epoch
Definition: logging.h:136
LoggingItem::m_type
LoggingType m_type
Definition: logging.h:133
progress
bool progress
Definition: mythtv/programs/mythcommflag/main.cpp:73
verboseInit
void verboseInit(void)
Initialize the logging levels and verbose levels.
Definition: logging.cpp:898
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:703
logPropagateOpts
LogPropagateOpts logPropagateOpts
Definition: logging.cpp:86
syslogGetFacility
int syslogGetFacility(const QString &facility)
Map a syslog facility name back to the enumerated value.
Definition: logging.cpp:790
arg
arg(title).arg(filename).arg(doDelete))
LoggerThread
The logging thread that consumes the logging queue and dispatches each LoggingItem.
Definition: logging.h:156
LoggerThread::m_waitEmpty
QWaitCondition * m_waitEmpty
Condition variable for waiting for the queue to be empty Protected by logQueueMutex.
Definition: logging.h:176
kDeregistering
@ kDeregistering
Definition: logging.h:44
logForwardMessage
void logForwardMessage(const QList< QByteArray > &msg)
Definition: loggingserver.cpp:894
LoggingItem::epoch
qlonglong epoch
Definition: logging.h:68
LoggerThread::LoggerThread
LoggerThread(QString filename, bool progress, bool quiet, QString table, int facility)
LoggerThread constructor.
Definition: logging.cpp:252
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:198
verbosedefs.h
logForwardStart
bool logForwardStart(void)
Definition: loggingserver.cpp:869
build_compdb.file
file
Definition: build_compdb.py:55
mythdirs.h
LoggingItem::tid
qlonglong tid
Definition: logging.h:61
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:81
LoggingType
LoggingType
Definition: logging.h:41
LoggingItem::m_function
QString m_function
Definition: logging.h:138
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:10
mythsystemlegacy.h
logThreadFinished
static bool logThreadFinished
Definition: logging.cpp:75
LoggingItem::setThreadName
void setThreadName(const QString &val)
Definition: logging.h:121
LoggingItem
The logging items that are generated by LOG() and are sent to the console.
Definition: logging.h:57
verboseString
QString verboseString
Definition: logging.cpp:103
LoggerThread::m_progress
bool m_progress
show only LOG_ERR and more important (console only)
Definition: logging.h:183
LoggerThread::fillItem
void fillItem(LoggingItem *item)
Definition: logging.cpp:536
MythDate::fromSecsSinceEpoch
MBASE_PUBLIC QDateTime fromSecsSinceEpoch(uint seconds)
This function takes the number of seconds since the start of the epoch and returns a QDateTime with t...
Definition: mythdate.cpp:68
LoggingItem::getLevelChar
char getLevelChar(void)
Get the message log level as a single character.
Definition: logging.cpp:240
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:587
verboseAdd
void verboseAdd(uint64_t mask, QString name, bool additive, QString helptext)
Add a verbose level to the verboseMap.
Definition: logging.cpp:863
kFlush
@ kFlush
Definition: logging.h:45
mythlogging.h
logLevelGetName
QString logLevelGetName(LogLevel_t level)
Map a log level enumerated value back to the name.
Definition: logging.cpp:840
LoggingItem::m_level
LogLevel_t m_level
Definition: logging.h:134
LoggingItem::pid
int pid
Definition: logging.h:60
logfile
QString logfile
Definition: backendcontext.cpp:14
loggingRegisterThread
void loggingRegisterThread(const QString &name)
Register the current thread with the given name.
Definition: logging.cpp:753
verboseMask
uint64_t verboseMask
Definition: logging.cpp:102
hardwareprofile.i18n.t
t
Definition: i18n.py:36
LogPropagateOpts
Definition: logging.cpp:78
compat.h
LoggerThread::m_aborted
bool m_aborted
Flag to abort the thread.
Definition: logging.h:180
logLevelGet
LogLevel_t logLevelGet(const QString &level)
Map a log level name back to the enumerated value.
Definition: logging.cpp:818
verboseInitialized
bool verboseInitialized
Definition: logging.cpp:92
debug
VERBOSE_PREAMBLE Most debug(nodatabase, notimestamp, noextra)") VERBOSE_MAP(VB_GENERAL
logThreadMutex
static QMutex logThreadMutex
Definition: logging.cpp:69
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:238
LoggingItem::setThreadTid
void setThreadTid(void)
Set the thread ID of the thread that produced the LoggingItem.
Definition: logging.cpp:199
LogPropagateOpts::m_quiet
int m_quiet
Definition: logging.cpp:80
filename
QString filename
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:637
LoggerThread::m_filename
QString m_filename
Filename of debug logfile.
Definition: logging.h:182
LoggerThread::run
void run(void) override
Run the logging thread.
Definition: logging.cpp:291
LoggingItem::m_message
QString m_message
Definition: logging.h:143
MThread::RunEpilog
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:211
kMessage
@ kMessage
Definition: logging.h:42
userDefaultValueInt
uint64_t userDefaultValueInt
Definition: logging.cpp:106
LoggerThread::logConsole
bool logConsole(LoggingItem *item) const
Process a log message, writing to the console.
Definition: logging.cpp:410
LoglevelDef::value
int value
Definition: verbosedefs.h:212
LoggingItem::getTimestamp
QString getTimestamp(void) const
Convert numerical timestamp to a readable date and time.
Definition: logging.cpp:225
LoggerThread::flush
bool flush(int timeoutMS=200000)
Wait for the queue to be flushed (up to a timeout)
Definition: logging.cpp:522
verboseMap
VerboseMap verboseMap
Definition: logging.cpp:93
LoggingItem::setFacility
void setFacility(const int val)
Definition: logging.h:117
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:510
quiet
int quiet
Definition: mythtv/programs/mythcommflag/main.cpp:72
userDefaultValueStr
QString userDefaultValueStr
Definition: logging.cpp:107
LoggingItem::setTable
void setTable(const QString &val)
Definition: logging.h:123
LoggerThread::m_quiet
bool m_quiet
silence the console (console only)
Definition: logging.h:184
uint
unsigned int uint
Definition: compat.h:140
LoggingItem::m_usec
uint m_usec
Definition: logging.h:131
LoggerThread::m_facility
int m_facility
Cached syslog facility (or -1 to disable)
Definition: logging.h:188
logStop
void logStop(void)
Entry point for stopping logging for an application.
Definition: logging.cpp:738
logThread
static LoggerThread * logThread
Definition: logging.cpp:68
verboseArgParse
int verboseArgParse(const QString &arg)
Parse the –verbose commandline argument and set the verbose level.
Definition: logging.cpp:966
LogPropagateOpts::m_propagate
bool m_propagate
Definition: logging.cpp:79
LoggingItem::getTimestampUs
QString getTimestampUs(void) const
Definition: logging.cpp:232
loggingGetTimeStamp
void loggingGetTimeStamp(qlonglong *epoch, uint *usec)
Definition: logging.cpp:127
haveUserDefaultValues
bool haveUserDefaultValues
Definition: logging.cpp:108
mythcorecontext.h
verboseDefaultInt
const uint64_t verboseDefaultInt
Definition: logging.cpp:99
LoggingItem::m_threadName
QString m_threadName
Definition: logging.h:139
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:557
LoggingItem::m_file
QString m_file
Definition: logging.h:137
logThreadTidHash
static QHash< uint64_t, int64_t > logThreadTidHash
Definition: logging.cpp:73
mythsyslog.h
logging.h
logPropagateArgList
QStringList logPropagateArgList
Definition: logging.cpp:88
LoggingItem::m_threadId
qulonglong m_threadId
Definition: logging.h:130
MThread
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:49
LoggingItem::m_tid
qlonglong m_tid
Definition: logging.h:129
ComponentLogLevelMap
QMap< uint64_t, LogLevel_t > ComponentLogLevelMap
Definition: verbosedefs.h:217
MThread::isRunning
bool isRunning(void) const
Definition: mthread.cpp:268
loglevelAdd
void loglevelAdd(int value, QString name, char shortname)
Add a log level to the logLevelMap.
Definition: logging.cpp:883
kRegistering
@ kRegistering
Definition: logging.h:43
LoggingItem::setAppName
void setAppName(const QString &val)
Definition: logging.h:122
mythsignalingtimer.h
verboseMapMutex
QMutex verboseMapMutex
Definition: logging.cpp:94
logPropagateQuiet
bool logPropagateQuiet(void)
Check if we are propagating a "--quiet".
Definition: logging.cpp:684
LoggerThread::m_pid
pid_t m_pid
Cached pid value.
Definition: logging.h:189
LoggingItem::getThreadTid
int64_t getThreadTid(void)
Get the thread ID of the thread that produced the LoggingItem.
Definition: logging.cpp:186
LoggingItem::toByteArray
QByteArray toByteArray(void)
Definition: logging.cpp:158
logPropagateArgs
QString logPropagateArgs
Definition: logging.cpp:87
logThreadTidMutex
static QMutex logThreadTidMutex
Definition: logging.cpp:72
LoggerThread::handleItem
static void handleItem(LoggingItem *item)
Handles each LoggingItem.
Definition: logging.cpp:348
verboseDefaultStr
const char * verboseDefaultStr
Definition: logging.cpp:100
MThread::wait
bool wait(unsigned long time=ULONG_MAX)
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:305
loglevelMap
LoglevelMap loglevelMap
Definition: logging.cpp:96
exitcodes.h
LoggingItem::LoggingItem
LoggingItem()
Definition: logging.h:146
kStandardIO
@ kStandardIO
Definition: logging.h:46
ReferenceCounter::IncrRef
virtual int IncrRef(void)
Increments reference count.
Definition: referencecounter.cpp:101
loggingserver.h
LoggerThread::~LoggerThread
~LoggerThread() override
LoggerThread destructor. Triggers the deletion of all loggers.
Definition: logging.cpp:277
LoggingItem::setPid
void setPid(const int val)
Definition: logging.h:110
logRegExp
static QRegExp logRegExp
Definition: logging.cpp:66
LoggingItem::setLogFile
void setLogFile(const QString &val)
Definition: logging.h:124
resetLogging
void resetLogging(void)
Intended for use only by the test harness.
Definition: logging.cpp:116
LoglevelDef
Definition: verbosedefs.h:211
ReferenceCounter
General purpose reference counter.
Definition: referencecounter.h:27
VerboseMap
QMap< QString, VerboseDef * > VerboseMap
Definition: verbosedefs.h:209