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