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 "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 defined(Q_OS_DARWIN)
53 #include <mach/mach.h>
54 #endif
55 
56 #ifdef Q_OS_ANDROID
57 #include <android/log.h>
58 #endif
59 
60 static QMutex logQueueMutex;
61 static QQueue<LoggingItem *> logQueue;
62 
63 static LoggerThread *logThread = nullptr;
64 static QMutex logThreadMutex;
65 static QHash<uint64_t, QString> logThreadHash;
66 
67 static QMutex logThreadTidMutex;
68 static QHash<uint64_t, int64_t> logThreadTidHash;
69 
70 static bool logThreadFinished = false;
71 static bool debugRegistration = false;
72 
75  int m_quiet;
77  QString m_path;
78  bool m_loglong;
79 };
80 
81 LogPropagateOpts logPropagateOpts {false, 0, 0, "", false};
83 QStringList logPropagateArgList;
84 
85 LogLevel_t logLevel = LOG_INFO;
86 
87 bool verboseInitialized = false;
90 
93 
94 const uint64_t verboseDefaultInt = VB_GENERAL;
95 const QString verboseDefaultStr { QStringLiteral(" general") };
96 
100 
104 
105 void verboseAdd(uint64_t mask, QString name, bool additive, QString helptext);
106 void loglevelAdd(int value, QString name, char shortname);
107 void verboseInit(void);
108 void verboseHelp(void);
109 
111 void resetLogging(void)
112 {
117  haveUserDefaultValues = false;
118 
119  verboseInit();
120 }
121 
122 LoggingItem::LoggingItem(const char *_file, const char *_function,
123  int _line, LogLevel_t _level, LoggingType _type) :
124  ReferenceCounter("LoggingItem", false),
125  m_threadId((uint64_t)(QThread::currentThreadId())),
126  m_line(_line), m_type(_type), m_level(_level),
127  m_function(_function)
128 {
129  const char *slash = std::strrchr(_file, '/');
130  m_file = (slash != nullptr) ? slash+1 : _file;
131  m_epoch = nowAsDuration<std::chrono::microseconds>();
132  setThreadTid();
133 }
134 
138 {
139  static constexpr char const *kSUnknown = "thread_unknown";
140 
141  if( !m_threadName.isEmpty() )
142  return m_threadName;
143 
144  QMutexLocker locker(&logThreadMutex);
145  return logThreadHash.value(m_threadId, kSUnknown);
146 }
147 
154 {
155  QMutexLocker locker(&logThreadTidMutex);
156  m_tid = logThreadTidHash.value(m_threadId, 0);
157  return m_tid;
158 }
159 
167 {
168  QMutexLocker locker(&logThreadTidMutex);
169 
170  m_tid = logThreadTidHash.value(m_threadId, -1);
171  if (m_tid == -1)
172  {
173  m_tid = 0;
174 
175 #if defined(Q_OS_ANDROID)
176  m_tid = (int64_t)gettid();
177 #elif defined(__linux__)
178  m_tid = syscall(SYS_gettid);
179 #elif defined(__FreeBSD__)
180  long lwpid;
181  [[maybe_unused]] int dummy = thr_self( &lwpid );
182  m_tid = (int64_t)lwpid;
183 #elif defined(Q_OS_DARWIN)
184  m_tid = (int64_t)mach_thread_self();
185 #endif
187  }
188 }
189 
191 QString LoggingItem::getTimestamp (const char *format) const
192 {
193  QDateTime epoch = QDateTime::fromMSecsSinceEpoch(m_epoch.count()/1000);
194  QString timestamp = epoch.toString(format);
195  return timestamp;
196 }
197 
198 QString LoggingItem::getTimestampUs (const char *format) const
199 {
200  QString timestamp = getTimestamp(format);
201  timestamp += QString(".%1").arg((m_epoch % 1s).count(),6,10,QChar('0'));
202  return timestamp;
203 }
204 
207 {
208  QMutexLocker locker(&loglevelMapMutex);
209  LoglevelMap::iterator it = loglevelMap.find(m_level);
210  if (it != loglevelMap.end())
211  return (*it)->shortname;
212  return '-';
213 }
214 
216 {
217  QString ptid = QString::number(pid()); // pid, add tid if non-zero
218  if(tid())
219  {
220  ptid.append("/").append(QString::number(tid()));
221  }
222  return qPrintable(QString("%1 %2 [%3] %4 %5:%6:%7 %8\n")
223  .arg(getTimestampUs(),
224  QString(QChar(getLevelChar())),
225  ptid,
226  threadName(),
227  file(),
228  QString::number(line()),
229  function(),
230  message()
231  ));
232 }
233 
235 {
236  return qPrintable(QString("%1 %2 %3\n")
237  .arg(getTimestampUs(),
238  QString(QChar(getLevelChar())),
239  message()
240  ));
241 }
242 
247  int facility, bool loglong) :
248  MThread("Logger"),
249  m_waitNotEmpty(new QWaitCondition()),
250  m_waitEmpty(new QWaitCondition()),
251  m_filename(std::move(filename)), m_progress(progress), m_quiet(quiet),
252  m_loglong(loglong),
253  m_facility(facility), m_pid(getpid())
254 {
255  if (qEnvironmentVariableIsSet("VERBOSE_THREADS"))
256  {
257  LOG(VB_GENERAL, LOG_NOTICE,
258  "Logging thread registration/deregistration enabled!");
259  debugRegistration = true;
260  }
261 
262  if (!logForwardStart())
263  {
264  LOG(VB_GENERAL, LOG_ERR,
265  "Failed to start LogServer thread");
266  }
267  moveToThread(qthread());
268 }
269 
272 {
273  stop();
274  wait();
275  logForwardStop();
276 
277  delete m_waitNotEmpty;
278  delete m_waitEmpty;
279 }
280 
286 {
287  RunProlog();
288 
289  logThreadFinished = false;
290 
291  LOG(VB_GENERAL, LOG_INFO, "Added logging to the console");
292 
293  bool dieNow = false;
294 
295  QMutexLocker qLock(&logQueueMutex);
296 
297  while (!m_aborted || !logQueue.isEmpty())
298  {
299  qLock.unlock();
300  qApp->processEvents(QEventLoop::AllEvents, 10);
301  qApp->sendPostedEvents(nullptr, QEvent::DeferredDelete);
302 
303  qLock.relock();
304  if (logQueue.isEmpty())
305  {
306  m_waitEmpty->wakeAll();
307  m_waitNotEmpty->wait(qLock.mutex(), 100);
308  continue;
309  }
310 
311  LoggingItem *item = logQueue.dequeue();
312  qLock.unlock();
313 
314  fillItem(item);
315  handleItem(item);
316  logConsole(item);
317  item->DecrRef();
318 
319  qLock.relock();
320  }
321 
322  qLock.unlock();
323 
324  // This must be before the timer stop below or we deadlock when the timer
325  // thread tries to deregister, and we wait for it.
326  logThreadFinished = true;
327 
328  RunEpilog();
329 
330  if (dieNow)
331  {
332  qApp->processEvents();
333  }
334 }
335 
342 {
343  if (item->m_type & kRegistering)
344  {
345  item->m_tid = item->getThreadTid();
346 
347  QMutexLocker locker(&logThreadMutex);
348  logThreadHash[item->m_threadId] = item->m_threadName;
349 
350  if (debugRegistration)
351  {
352  item->m_message = QString("Thread 0x%1 (%2) registered as \'%3\'")
353  .arg(QString::number(item->m_threadId,16),
354  QString::number(item->m_tid),
355  logThreadHash[item->m_threadId]);
356  }
357  }
358  else if (item->m_type & kDeregistering)
359  {
360  int64_t tid = 0;
361 
362  {
363  QMutexLocker locker(&logThreadTidMutex);
364  if( logThreadTidHash.contains(item->m_threadId) )
365  {
366  tid = logThreadTidHash[item->m_threadId];
367  logThreadTidHash.remove(item->m_threadId);
368  }
369  }
370 
371  QMutexLocker locker(&logThreadMutex);
372  if (logThreadHash.contains(item->m_threadId))
373  {
374  if (debugRegistration)
375  {
376  item->m_message = QString("Thread 0x%1 (%2) deregistered as \'%3\'")
377  .arg(QString::number(item->m_threadId,16),
378  QString::number(tid),
379  logThreadHash[item->m_threadId]);
380  }
381  logThreadHash.remove(item->m_threadId);
382  }
383  }
384 
385  if (!item->m_message.isEmpty())
386  {
387  logForwardMessage(item);
388  }
389 }
390 
394 {
395  if (m_quiet || (m_progress && item->m_level > LOG_ERR))
396  return false;
397 
398  if (!(item->m_type & kMessage))
399  return false;
400 
401  item->IncrRef();
402 
403 #ifndef Q_OS_ANDROID
404  std::string line;
405 
406  if (item->m_type & kStandardIO)
407  {
408  line = qPrintable(item->m_message);
409  }
410  else
411  {
412 #if !defined(NDEBUG) || CONFIG_FORCE_LOGLONG
413  if (true)
414 #else
415  if (m_loglong)
416 #endif
417  {
418  line = item->toString();
419  }
420  else
421  {
422  line = item->toStringShort();
423  }
424  }
425 
426  std::cout << line << std::flush;
427 
428 #else // Q_OS_ANDROID
429 
430  android_LogPriority aprio;
431  switch (item->m_level)
432  {
433  case LOG_EMERG:
434  aprio = ANDROID_LOG_FATAL;
435  break;
436  case LOG_ALERT:
437  case LOG_CRIT:
438  case LOG_ERR:
439  aprio = ANDROID_LOG_ERROR;
440  break;
441  case LOG_WARNING:
442  aprio = ANDROID_LOG_WARN;
443  break;
444  case LOG_NOTICE:
445  case LOG_INFO:
446  aprio = ANDROID_LOG_INFO;
447  break;
448  case LOG_DEBUG:
449  aprio = ANDROID_LOG_DEBUG;
450  break;
451  case LOG_UNKNOWN:
452  default:
453  aprio = ANDROID_LOG_UNKNOWN;
454  break;
455  }
456 #ifndef NDEBUG
457  __android_log_print(aprio, "mfe", "%s:%d:%s %s", qPrintable(item->m_file),
458  item->m_line, qPrintable(item->m_function),
459  qPrintable(item->m_message));
460 #else
461  __android_log_print(aprio, "mfe", "%s", qPrintable(item->m_message));
462 #endif
463 #endif
464 
465  item->DecrRef();
466 
467  return true;
468 }
469 
470 
474 {
475  logQueueMutex.lock();
476  flush(1000);
477  m_aborted = true;
478  logQueueMutex.unlock();
479  m_waitNotEmpty->wakeAll();
480 }
481 
485 bool LoggerThread::flush(int timeoutMS)
486 {
487  QElapsedTimer t;
488  t.start();
489  while (!m_aborted && !logQueue.isEmpty() && !t.hasExpired(timeoutMS))
490  {
491  m_waitNotEmpty->wakeAll();
492  int left = timeoutMS - t.elapsed();
493  if (left > 0)
494  m_waitEmpty->wait(&logQueueMutex, left);
495  }
496  return logQueue.isEmpty();
497 }
498 
500 {
501  if (!item)
502  return;
503 
504  item->setPid(m_pid);
505  item->setThreadName(item->getThreadName());
506  item->setAppName(m_appname);
507  item->setLogFile(m_filename);
508  item->setFacility(m_facility);
509 }
510 
511 
519 LoggingItem *LoggingItem::create(const char *_file,
520  const char *_function,
521  int _line, LogLevel_t _level,
522  LoggingType _type)
523 {
524  auto *item = new LoggingItem(_file, _function, _line, _level, _type);
525 
526  return item;
527 }
528 
537 void LogPrintLine( uint64_t mask, LogLevel_t level, const char *file, int line,
538  const char *function, QString message)
539 {
540  int type = kMessage;
541  type |= (mask & VB_FLUSH) ? kFlush : 0;
542  type |= (mask & VB_STDIO) ? kStandardIO : 0;
543  LoggingItem *item = LoggingItem::create(file, function, line, level,
544  (LoggingType)type);
545  if (!item)
546  return;
547 
548  item->m_message = std::move(message);
549 
550  QMutexLocker qLock(&logQueueMutex);
551 
552 #if defined( _MSC_VER ) && defined( _DEBUG )
553  OutputDebugStringA( qPrintable(item->m_message) );
554  OutputDebugStringA( "\n" );
555 #endif
556 
557  logQueue.enqueue(item);
558 
560  {
561  while (!logQueue.isEmpty())
562  {
563  item = logQueue.dequeue();
564  qLock.unlock();
566  logThread->logConsole(item);
567  item->DecrRef();
568  qLock.relock();
569  }
570  }
571  else if (logThread && !logThreadFinished && (type & kFlush))
572  {
573  logThread->flush();
574  }
575 }
576 
577 
582 {
583  logPropagateArgList.clear();
584 
585  QString mask = verboseString.simplified().replace(' ', ',');
586  logPropagateArgs = " --verbose " + mask;
587  logPropagateArgList << "--verbose" << mask;
588 
590  {
591  logPropagateArgs += " --logpath " + logPropagateOpts.m_path;
592  logPropagateArgList << "--logpath" << logPropagateOpts.m_path;
593  }
594 
595  QString name = logLevelGetName(logLevel);
596  logPropagateArgs += " --loglevel " + name;
597  logPropagateArgList << "--loglevel" << name;
598 
599  for (int i = 0; i < logPropagateOpts.m_quiet; i++)
600  {
601  logPropagateArgs += " --quiet";
602  logPropagateArgList << "--quiet";
603  }
604 
606  {
607  logPropagateArgs += " --loglong";
608  logPropagateArgList << "--loglong";
609  }
610 
611 #if !defined(_WIN32) && !defined(Q_OS_ANDROID)
612  if (logPropagateOpts.m_facility >= 0)
613  {
614  const CODE *syslogname = nullptr;
615  for (syslogname = &facilitynames[0];
616  (syslogname->c_name &&
617  syslogname->c_val != logPropagateOpts.m_facility); syslogname++);
618 
619  logPropagateArgs += QString(" --syslog %1").arg(syslogname->c_name);
620  logPropagateArgList << "--syslog" << syslogname->c_name;
621  }
622 #if CONFIG_SYSTEMD_JOURNAL
623  else if (logPropagateOpts.m_facility == SYSTEMD_JOURNAL_FACILITY)
624  {
625  logPropagateArgs += " --systemd-journal";
626  logPropagateArgList << "--systemd-journal";
627  }
628 #endif
629 #endif
630 }
631 
635 {
636  return logPropagateOpts.m_quiet != 0;
637 }
638 
652 void logStart(const QString& logfile, bool progress, int quiet, int facility,
653  LogLevel_t level, bool propagate, bool loglong, bool testHarness)
654 {
655  if (logThread && logThread->isRunning())
656  return;
657 
658  logLevel = level;
659  LOG(VB_GENERAL, LOG_NOTICE, QString("Setting Log Level to LOG_%1")
660  .arg(logLevelGetName(logLevel).toUpper()));
661 
662  logPropagateOpts.m_propagate = propagate;
664  logPropagateOpts.m_facility = facility;
665  logPropagateOpts.m_loglong = loglong;
666 
667  if (propagate)
668  {
669  QFileInfo finfo(logfile);
670  QString path = finfo.path();
671  logPropagateOpts.m_path = path;
672  }
673 
675  if (testHarness)
676  return;
677 
678  if (!logThread)
679  logThread = new LoggerThread(logfile, progress, quiet, facility, loglong);
680 
681  logThread->start();
682 }
683 
685 void logStop(void)
686 {
687  if (logThread)
688  {
689  logThread->stop();
690  logThread->wait();
691  delete logThread;
692  logThread = nullptr;
693  }
694 }
695 
700 void loggingRegisterThread(const QString &name)
701 {
702  if (logThreadFinished)
703  return;
704 
705  QMutexLocker qLock(&logQueueMutex);
706 
707  LoggingItem *item = LoggingItem::create(__FILE__, __FUNCTION__,
708  __LINE__, LOG_DEBUG,
709  kRegistering);
710  if (item)
711  {
712  item->setThreadName((char *)name.toLocal8Bit().constData());
713  logQueue.enqueue(item);
714  }
715 }
716 
720 {
721  if (logThreadFinished)
722  return;
723 
724  QMutexLocker qLock(&logQueueMutex);
725 
726  LoggingItem *item = LoggingItem::create(__FILE__, __FUNCTION__, __LINE__,
727  LOG_DEBUG,
729  if (item)
730  logQueue.enqueue(item);
731 }
732 
733 
737 int syslogGetFacility([[maybe_unused]] const QString& facility)
738 {
739 #ifdef _WIN32
740  LOG(VB_GENERAL, LOG_NOTICE,
741  "Windows does not support syslog, disabling" );
742  return( -2 );
743 #elif defined(Q_OS_ANDROID)
744  LOG(VB_GENERAL, LOG_NOTICE,
745  "Android does not support syslog, disabling" );
746  return( -2 );
747 #else
748  const CODE *name = nullptr;
749  QByteArray ba = facility.toLocal8Bit();
750  char *string = (char *)ba.constData();
751 
752  for (name = &facilitynames[0];
753  name->c_name && (strcmp(name->c_name, string) != 0); name++);
754 
755  return( name->c_val );
756 #endif
757 }
758 
762 LogLevel_t logLevelGet(const QString& level)
763 {
764  QMutexLocker locker(&loglevelMapMutex);
765  if (!verboseInitialized)
766  {
767  locker.unlock();
768  verboseInit();
769  locker.relock();
770  }
771 
772  for (auto *item : std::as_const(loglevelMap))
773  {
774  if ( item->name == level.toLower() )
775  return (LogLevel_t)item->value;
776  }
777 
778  return LOG_UNKNOWN;
779 }
780 
784 QString logLevelGetName(LogLevel_t level)
785 {
786  QMutexLocker locker(&loglevelMapMutex);
787  if (!verboseInitialized)
788  {
789  locker.unlock();
790  verboseInit();
791  locker.relock();
792  }
793  LoglevelMap::iterator it = loglevelMap.find((int)level);
794 
795  if ( it == loglevelMap.end() )
796  return {"unknown"};
797 
798  return (*it)->name;
799 }
800 
807 void verboseAdd(uint64_t mask, QString name, bool additive, QString helptext)
808 {
809  auto *item = new VerboseDef;
810 
811  item->mask = mask;
812  // VB_GENERAL -> general
813  name.remove(0, 3);
814  name = name.toLower();
815  item->name = name;
816  item->additive = additive;
817  item->helpText = std::move(helptext);
818 
819  verboseMap.insert(name, item);
820 }
821 
827 void loglevelAdd(int value, QString name, char shortname)
828 {
829  auto *item = new LoglevelDef;
830 
831  item->value = value;
832  // LOG_CRIT -> crit
833  name.remove(0, 4);
834  name = name.toLower();
835  item->name = name;
836  item->shortname = shortname;
837 
838  loglevelMap.insert(value, item);
839 }
840 
842 void verboseInit(void)
843 {
844  QMutexLocker locker(&verboseMapMutex);
845  QMutexLocker locker2(&loglevelMapMutex);
846  verboseMap.clear();
847  loglevelMap.clear();
848 
849  // This looks funky, so I'll put some explanation here. The verbosedefs.h
850  // file gets included as part of the mythlogging.h include, and at that
851  // time, the normal (without MYTH_IMPLEMENT_VERBOSE defined) code case will
852  // define the VerboseMask enum. At this point, we force it to allow us to
853  // include the file again, but with MYTH_IMPLEMENT_VERBOSE set so that the
854  // single definition of the VB_* values can be shared to define also the
855  // contents of verboseMap, via repeated calls to verboseAdd()
856 
857 #undef VERBOSEDEFS_H_
858 #define MYTH_IMPLEMENT_VERBOSE
859 #include "verbosedefs.h"
860 
861  verboseInitialized = true;
862 }
863 
864 
867 void verboseHelp(void)
868 {
869  QString m_verbose = userDefaultValueStr.simplified().replace(' ', ',');
870 
871  std::cerr << "Verbose debug levels.\n"
872  "Accepts any combination (separated by comma) of:\n\n";
873 
874  for (VerboseMap::Iterator vit = verboseMap.begin();
875  vit != verboseMap.end(); ++vit )
876  {
877  VerboseDef *item = vit.value();
878  QString name = QString(" %1").arg(item->name, -15, ' ');
879  if (item->helpText.isEmpty())
880  continue;
881  std::cerr << name.toLocal8Bit().constData() << " - "
882  << item->helpText.toLocal8Bit().constData() << std::endl;
883  }
884 
885  std::cerr << std::endl <<
886  "The default for this program appears to be: '-v " <<
887  m_verbose.toLocal8Bit().constData() << "'\n\n"
888  "Most options are additive except for 'none' and 'all'.\n"
889  "These two are semi-exclusive and take precedence over any\n"
890  "other options. However, you may use something like\n"
891  "'-v none,jobqueue' to receive only JobQueue related messages\n"
892  "and override the default verbosity level.\n\n"
893  "Additive options may also be subtracted from 'all' by\n"
894  "prefixing them with 'no', so you may use '-v all,nodatabase'\n"
895  "to view all but database debug messages.\n\n";
896 
897  std::cerr
898  << "The 'global' loglevel is specified with --loglevel, but can be\n"
899  << "overridden on a component by component basis by appending "
900  << "':level'\n"
901  << "to the component.\n"
902  << " For example: -v gui:debug,channel:notice,record\n\n";
903 
904  std::cerr << "Some debug levels may not apply to this program.\n" << std::endl;
905 }
906 
910 int verboseArgParse(const QString& arg)
911 {
912  QString option;
913 
914  if (!verboseInitialized)
915  verboseInit();
916 
917  QMutexLocker locker(&verboseMapMutex);
918 
921 
922  if (arg.startsWith('-'))
923  {
924  std::cerr << "Invalid or missing argument to -v/--verbose option\n";
926  }
927 
928  static const QRegularExpression kSeparatorRE { "[^\\w:]+" };
929  QStringList verboseOpts = arg.split(kSeparatorRE, Qt::SkipEmptyParts);
930  for (const auto& opt : std::as_const(verboseOpts))
931  {
932  option = opt.toLower();
933  bool reverseOption = false;
934  QString optionLevel;
935 
936  if (option != "none" && option.startsWith("no"))
937  {
938  reverseOption = true;
939  option = option.right(option.length() - 2);
940  }
941 
942  if (option == "help")
943  {
944  verboseHelp();
946  }
947  if (option == "important")
948  {
949  std::cerr << "The \"important\" log mask is no longer valid.\n";
950  }
951  else if (option == "extra")
952  {
953  std::cerr << "The \"extra\" log mask is no longer valid. Please try "
954  "--loglevel debug instead.\n";
955  }
956  else if (option == "default")
957  {
959  {
962  }
963  else
964  {
967  }
968  }
969  else
970  {
971  int idx = option.indexOf(':');
972  if (idx != -1)
973  {
974  optionLevel = option.mid(idx + 1);
975  option = option.left(idx);
976  }
977 
978  VerboseDef *item = verboseMap.value(option);
979 
980  if (item)
981  {
982  if (reverseOption)
983  {
984  verboseMask &= ~(item->mask);
985  verboseString = verboseString.remove(' ' + item->name);
986  verboseString += " no" + item->name;
987  }
988  else
989  {
990  if (item->additive)
991  {
992  if (!(verboseMask & item->mask))
993  {
994  verboseMask |= item->mask;
995  verboseString += ' ' + item->name;
996  }
997  }
998  else
999  {
1000  verboseMask = item->mask;
1001  verboseString = item->name;
1002  }
1003 
1004  if (!optionLevel.isEmpty())
1005  {
1006  LogLevel_t level = logLevelGet(optionLevel);
1007  if (level != LOG_UNKNOWN)
1008  componentLogLevel[item->mask] = level;
1009  }
1010  }
1011  }
1012  else
1013  {
1014  std::cerr << "Unknown argument for -v/--verbose: " <<
1015  option.toLocal8Bit().constData() << std::endl;;
1017  }
1018  }
1019  }
1020 
1021  if (!haveUserDefaultValues)
1022  {
1023  haveUserDefaultValues = true;
1026  }
1027 
1028  return GENERIC_EXIT_OK;
1029 }
1030 
1035 QString logStrerror(int errnum)
1036 {
1037  return QString("%1 (%2)").arg(strerror(errnum)).arg(errnum);
1038 }
1039 
1040 
1041 /*
1042  * vim:ts=4:sw=4:ai:et:si:sts=4
1043  */
LogPropagateOpts::m_path
QString m_path
Definition: logging.cpp:77
loggingDeregisterThread
void loggingDeregisterThread(void)
Deregister the current thread's name.
Definition: logging.cpp:719
LoglevelMap
QMap< int, LoglevelDef * > LoglevelMap
Definition: verbosedefs.h:221
LoggingItem::m_line
int m_line
Definition: logging.h:126
debugRegistration
static bool debugRegistration
Definition: logging.cpp:71
logStart
void logStart(const QString &logfile, bool progress, int quiet, int facility, LogLevel_t level, bool propagate, bool loglong, bool testHarness)
Entry point to start logging for the application.
Definition: logging.cpp:652
logForwardStop
void logForwardStop(void)
Definition: loggingserver.cpp:476
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:191
logThreadHash
static QHash< uint64_t, QString > logThreadHash
Definition: logging.cpp:65
logStrerror
QString logStrerror(int errnum)
Verbose helper function for ENO macro.
Definition: logging.cpp:1035
MThread::start
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:283
LogPropagateOpts::m_loglong
bool m_loglong
Definition: logging.cpp:78
LoggingItem::threadName
QString threadName
Definition: logging.h:68
dbutil.h
ReferenceCounter::DecrRef
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
Definition: referencecounter.cpp:124
logQueue
static QQueue< LoggingItem * > logQueue
Definition: logging.cpp:61
mythdb.h
false
VERBOSE_PREAMBLE false
Definition: verbosedefs.h:89
logPropagateCalc
void logPropagateCalc(void)
Generate the logPropagateArgs global with the latest logging level, mask, etc to propagate to all of ...
Definition: logging.cpp:581
componentLogLevel
ComponentLogLevelMap componentLogLevel
Definition: logging.cpp:99
LoggerThread::m_waitNotEmpty
QWaitCondition * m_waitNotEmpty
Condition variable for waiting for the queue to not be empty Protected by logQueueMutex.
Definition: logging.h:164
progress
bool progress
Definition: mythcommflag.cpp:60
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:300
LoggerThread::m_appname
QString m_appname
Cached application name.
Definition: logging.h:178
logLevel
LogLevel_t logLevel
Definition: logging.cpp:85
loglevelMapMutex
QMutex loglevelMapMutex
Definition: logging.cpp:92
verboseHelp
void verboseHelp(void)
Outputs the Verbose levels and their descriptions (for –verbose help)
Definition: logging.cpp:867
LoggingItem::getThreadName
QString getThreadName(void)
Get the name of the thread that produced the LoggingItem.
Definition: logging.cpp:137
LoggingItem::m_type
LoggingType m_type
Definition: logging.h:127
verboseInit
void verboseInit(void)
Initialize the logging levels and verbose levels.
Definition: logging.cpp:842
logPropagateOpts
LogPropagateOpts logPropagateOpts
Definition: logging.cpp:81
LoggerThread
The logging thread that consumes the logging queue and dispatches each LoggingItem.
Definition: logging.h:148
LoggerThread::m_waitEmpty
QWaitCondition * m_waitEmpty
Condition variable for waiting for the queue to be empty Protected by logQueueMutex.
Definition: logging.h:168
LoggingItem::epoch
qlonglong epoch
Definition: logging.h:65
quiet
int quiet
Definition: mythcommflag.cpp:59
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
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:467
LoggingItem::toString
std::string toString()
Long format to string.
Definition: logging.cpp:215
build_compdb.file
file
Definition: build_compdb.py:55
mythdirs.h
LoggingItem::tid
qlonglong tid
Definition: logging.h:59
LogPropagateOpts::m_facility
int m_facility
Definition: logging.cpp:76
kStandardIO
@ kStandardIO
Definition: logging.h:44
kDeregistering
@ kDeregistering
Definition: logging.h:42
LoggingItem::m_function
QString m_function
Definition: logging.h:132
mythsystemlegacy.h
logThreadFinished
static bool logThreadFinished
Definition: logging.cpp:70
logForwardMessage
void logForwardMessage(LoggingItem *item)
Definition: loggingserver.cpp:488
LoggingItem::setThreadName
void setThreadName(const QString &val)
Definition: logging.h:114
LoggingItem
The logging items that are generated by LOG() and are sent to the console.
Definition: logging.h:54
verboseString
QString verboseString
Definition: logging.cpp:98
LoggerThread::m_progress
bool m_progress
show only LOG_ERR and more important (console only)
Definition: logging.h:175
kFlush
@ kFlush
Definition: logging.h:43
LoggerThread::fillItem
void fillItem(LoggingItem *item)
Definition: logging.cpp:499
LoggingItem::getLevelChar
char getLevelChar(void)
Get the message log level as a single character.
Definition: logging.cpp:206
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:537
kRegistering
@ kRegistering
Definition: logging.h:41
verboseAdd
void verboseAdd(uint64_t mask, QString name, bool additive, QString helptext)
Add a verbose level to the verboseMap.
Definition: logging.cpp:807
GENERIC_EXIT_INVALID_CMDLINE
@ GENERIC_EXIT_INVALID_CMDLINE
Command line parse error.
Definition: exitcodes.h:18
mythlogging.h
logLevelGetName
QString logLevelGetName(LogLevel_t level)
Map a log level enumerated value back to the name.
Definition: logging.cpp:784
LoggingItem::m_level
LogLevel_t m_level
Definition: logging.h:128
LoggingItem::pid
int pid
Definition: logging.h:58
kMessage
@ kMessage
Definition: logging.h:40
loggingRegisterThread
void loggingRegisterThread(const QString &name)
Register the current thread with the given name.
Definition: logging.cpp:700
verboseMask
uint64_t verboseMask
Definition: logging.cpp:97
hardwareprofile.i18n.t
t
Definition: i18n.py:36
GENERIC_EXIT_OK
@ GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:13
LogPropagateOpts
Definition: logging.cpp:73
compat.h
LoggerThread::m_aborted
bool m_aborted
Flag to abort the thread.
Definition: logging.h:172
logLevelGet
LogLevel_t logLevelGet(const QString &level)
Map a log level name back to the enumerated value.
Definition: logging.cpp:762
verboseInitialized
bool verboseInitialized
Definition: logging.cpp:87
logThreadMutex
static QMutex logThreadMutex
Definition: logging.cpp:64
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:233
verboseDefaultStr
const QString verboseDefaultStr
Definition: logging.cpp:95
LoggingItem::setThreadTid
void setThreadTid(void)
Set the thread ID of the thread that produced the LoggingItem.
Definition: logging.cpp:166
LogPropagateOpts::m_quiet
int m_quiet
Definition: logging.cpp:75
LoggerThread::m_filename
QString m_filename
Filename of debug logfile.
Definition: logging.h:174
LoggerThread::run
void run(void) override
Run the logging thread.
Definition: logging.cpp:285
LoggingItem::m_message
QString m_message
Definition: logging.h:136
MThread::RunEpilog
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:209
userDefaultValueInt
uint64_t userDefaultValueInt
Definition: logging.cpp:101
LoggerThread::logConsole
bool logConsole(LoggingItem *item) const
Process a log message, writing to the console.
Definition: logging.cpp:393
LoggingItem::message
QString message
Definition: logging.h:71
LoglevelDef::value
int value
Definition: verbosedefs.h:217
LoggerThread::flush
bool flush(int timeoutMS=200000)
Wait for the queue to be flushed (up to a timeout)
Definition: logging.cpp:485
verboseMap
VerboseMap verboseMap
Definition: logging.cpp:88
LoggingItem::setFacility
void setFacility(const int val)
Definition: logging.h:109
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:473
userDefaultValueStr
QString userDefaultValueStr
Definition: logging.cpp:102
LoggerThread::m_quiet
bool m_quiet
silence the console (console only)
Definition: logging.h:176
LoggerThread::m_facility
int m_facility
Cached syslog facility (or -1 to disable)
Definition: logging.h:180
logStop
void logStop(void)
Entry point for stopping logging for an application.
Definition: logging.cpp:685
LoggingItem::file
QString file
Definition: logging.h:66
LoggingItem::m_epoch
std::chrono::microseconds m_epoch
Definition: logging.h:130
logThread
static LoggerThread * logThread
Definition: logging.cpp:63
verboseArgParse
int verboseArgParse(const QString &arg)
Parse the –verbose commandline argument and set the verbose level.
Definition: logging.cpp:910
LoggingType
LoggingType
Definition: logging.h:39
LoggingItem::toStringShort
std::string toStringShort()
short console format
Definition: logging.cpp:234
LoggingItem::line
int line
Definition: logging.h:61
LogPropagateOpts::m_propagate
bool m_propagate
Definition: logging.cpp:74
syslogGetFacility
int syslogGetFacility([[maybe_unused]] const QString &facility)
Map a syslog facility name back to the enumerated value.
Definition: logging.cpp:737
haveUserDefaultValues
bool haveUserDefaultValues
Definition: logging.cpp:103
LoggerThread::LoggerThread
LoggerThread(QString filename, bool progress, bool quiet, int facility, bool loglong)
LoggerThread constructor.
Definition: logging.cpp:246
verboseDefaultInt
const uint64_t verboseDefaultInt
Definition: logging.cpp:94
LoggingItem::m_threadName
QString m_threadName
Definition: logging.h:133
logQueueMutex
static QMutex logQueueMutex
Definition: logging.cpp:60
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:519
LoggingItem::m_file
QString m_file
Definition: logging.h:131
logThreadTidHash
static QHash< uint64_t, int64_t > logThreadTidHash
Definition: logging.cpp:68
mythsyslog.h
logging.h
LoggingItem::getTimestampUs
QString getTimestampUs(const char *format="yyyy-MM-dd HH:mm:ss") const
Definition: logging.cpp:198
logPropagateArgList
QStringList logPropagateArgList
Definition: logging.cpp:83
LoggingItem::m_threadId
qulonglong m_threadId
Definition: logging.h:125
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:124
ComponentLogLevelMap
QMap< uint64_t, LogLevel_t > ComponentLogLevelMap
Definition: verbosedefs.h:222
MThread::isRunning
bool isRunning(void) const
Definition: mthread.cpp:263
loglevelAdd
void loglevelAdd(int value, QString name, char shortname)
Add a log level to the logLevelMap.
Definition: logging.cpp:827
LoggingItem::setAppName
void setAppName(const QString &val)
Definition: logging.h:115
verboseMapMutex
QMutex verboseMapMutex
Definition: logging.cpp:89
logPropagateQuiet
bool logPropagateQuiet(void)
Check if we are propagating a "--quiet".
Definition: logging.cpp:634
LoggerThread::m_pid
pid_t m_pid
Cached pid value.
Definition: logging.h:181
LoggingItem::getThreadTid
int64_t getThreadTid(void)
Get the thread ID of the thread that produced the LoggingItem.
Definition: logging.cpp:153
logPropagateArgs
QString logPropagateArgs
Definition: logging.cpp:82
logThreadTidMutex
static QMutex logThreadTidMutex
Definition: logging.cpp:67
LoggerThread::handleItem
static void handleItem(LoggingItem *item)
Handles each LoggingItem.
Definition: logging.cpp:341
LoggerThread::m_loglong
bool m_loglong
use long log format (console only)
Definition: logging.h:177
loglevelMap
LoglevelMap loglevelMap
Definition: logging.cpp:91
exitcodes.h
LoggingItem::LoggingItem
LoggingItem()
Definition: logging.h:139
ReferenceCounter::IncrRef
virtual int IncrRef(void)
Increments reference count.
Definition: referencecounter.cpp:100
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:271
LoggingItem::setPid
void setPid(const int val)
Definition: logging.h:103
LoggingItem::setLogFile
void setLogFile(const QString &val)
Definition: logging.h:116
resetLogging
void resetLogging(void)
Intended for use only by the test harness.
Definition: logging.cpp:111
LoglevelDef
Definition: verbosedefs.h:216
ReferenceCounter
General purpose reference counter.
Definition: referencecounter.h:26
VerboseMap
QMap< QString, VerboseDef * > VerboseMap
Definition: verbosedefs.h:214