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