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