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 #ifdef Q_OS_ANDROID
58 #include <android/log.h>
59 #endif
60 
61 static QMutex logQueueMutex;
62 static QQueue<LoggingItem *> logQueue;
63 
64 static LoggerThread *logThread = nullptr;
65 static QMutex logThreadMutex;
66 static QHash<uint64_t, QString> logThreadHash;
67 
68 static QMutex logThreadTidMutex;
69 static QHash<uint64_t, int64_t> logThreadTidHash;
70 
71 static bool logThreadFinished = false;
72 static bool debugRegistration = false;
73 
76  int m_quiet;
78  QString m_path;
79 };
80 
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 
219  int facility) :
220  MThread("Logger"),
221  m_waitNotEmpty(new QWaitCondition()),
222  m_waitEmpty(new QWaitCondition()),
223  m_filename(std::move(filename)), m_progress(progress), m_quiet(quiet),
224  m_facility(facility), m_pid(getpid())
225 {
226  if (qEnvironmentVariableIsSet("VERBOSE_THREADS"))
227  {
228  LOG(VB_GENERAL, LOG_NOTICE,
229  "Logging thread registration/deregistration enabled!");
230  debugRegistration = true;
231  }
232 
233  if (!logForwardStart())
234  {
235  LOG(VB_GENERAL, LOG_ERR,
236  "Failed to start LogServer thread");
237  }
238  moveToThread(qthread());
239 }
240 
243 {
244  stop();
245  wait();
246  logForwardStop();
247 
248  delete m_waitNotEmpty;
249  delete m_waitEmpty;
250 }
251 
257 {
258  RunProlog();
259 
260  logThreadFinished = false;
261 
262  LOG(VB_GENERAL, LOG_INFO, "Added logging to the console");
263 
264  bool dieNow = false;
265 
266  QMutexLocker qLock(&logQueueMutex);
267 
268  while (!m_aborted || !logQueue.isEmpty())
269  {
270  qLock.unlock();
271  qApp->processEvents(QEventLoop::AllEvents, 10);
272  qApp->sendPostedEvents(nullptr, QEvent::DeferredDelete);
273 
274  qLock.relock();
275  if (logQueue.isEmpty())
276  {
277  m_waitEmpty->wakeAll();
278  m_waitNotEmpty->wait(qLock.mutex(), 100);
279  continue;
280  }
281 
282  LoggingItem *item = logQueue.dequeue();
283  qLock.unlock();
284 
285  fillItem(item);
286  handleItem(item);
287  logConsole(item);
288  item->DecrRef();
289 
290  qLock.relock();
291  }
292 
293  qLock.unlock();
294 
295  // This must be before the timer stop below or we deadlock when the timer
296  // thread tries to deregister, and we wait for it.
297  logThreadFinished = true;
298 
299  RunEpilog();
300 
301  if (dieNow)
302  {
303  qApp->processEvents();
304  }
305 }
306 
313 {
314  if (item->m_type & kRegistering)
315  {
316  item->m_tid = item->getThreadTid();
317 
318  QMutexLocker locker(&logThreadMutex);
319  logThreadHash[item->m_threadId] = item->m_threadName;
320 
321  if (debugRegistration)
322  {
323  item->m_message = QString("Thread 0x%1 (%2) registered as \'%3\'")
324  .arg(QString::number(item->m_threadId,16),
325  QString::number(item->m_tid),
326  logThreadHash[item->m_threadId]);
327  }
328  }
329  else if (item->m_type & kDeregistering)
330  {
331  int64_t tid = 0;
332 
333  {
334  QMutexLocker locker(&logThreadTidMutex);
335  if( logThreadTidHash.contains(item->m_threadId) )
336  {
337  tid = logThreadTidHash[item->m_threadId];
338  logThreadTidHash.remove(item->m_threadId);
339  }
340  }
341 
342  QMutexLocker locker(&logThreadMutex);
343  if (logThreadHash.contains(item->m_threadId))
344  {
345  if (debugRegistration)
346  {
347  item->m_message = QString("Thread 0x%1 (%2) deregistered as \'%3\'")
348  .arg(QString::number(item->m_threadId,16),
349  QString::number(tid),
350  logThreadHash[item->m_threadId]);
351  }
352  logThreadHash.remove(item->m_threadId);
353  }
354  }
355 
356  if (!item->m_message.isEmpty())
357  {
358  logForwardMessage(item);
359  }
360 }
361 
365 {
366  if (m_quiet || (m_progress && item->m_level > LOG_ERR))
367  return false;
368 
369  if (!(item->m_type & kMessage))
370  return false;
371 
372  item->IncrRef();
373 
374 #ifndef Q_OS_ANDROID
375  std::string line;
376 
377  if (item->m_type & kStandardIO)
378  {
379  line = qPrintable(item->m_message);
380  }
381  else
382  {
383  QString timestamp = item->getTimestampUs();
384  char shortname = item->getLevelChar();
385 
386 #ifndef NDEBUG
387  if (item->tid())
388  {
389  line = qPrintable(QString("%1 %2 [%3/%4] %5 %6:%7:%8 %9\n")
390  .arg(timestamp, QString(shortname),
391  QString::number(item->pid()),
392  QString::number(item->tid()),
393  item->threadName(),
394  item->m_file,
395  QString::number(item->m_line),
396  item->m_function,
397  item->m_message));
398  }
399  else
400  {
401  line = qPrintable(QString("%1 %2 [%3] %4 %5:%6:%7 %8\n")
402  .arg(timestamp, QString(shortname),
403  QString::number(item->pid()),
404  item->threadName(),
405  item->m_file,
406  QString::number(item->m_line),
407  item->m_function,
408  item->m_message));
409  }
410 #else
411  line = qPrintable(QString("%1 %2 %3\n")
412  .arg(timestamp, QString(shortname),
413  item->m_message));
414 #endif
415  }
416 
417  (void)write(1, line.data(), line.size());
418 
419 #else // Q_OS_ANDROID
420 
421  android_LogPriority aprio;
422  switch (item->m_level)
423  {
424  case LOG_EMERG:
425  aprio = ANDROID_LOG_FATAL;
426  break;
427  case LOG_ALERT:
428  case LOG_CRIT:
429  case LOG_ERR:
430  aprio = ANDROID_LOG_ERROR;
431  break;
432  case LOG_WARNING:
433  aprio = ANDROID_LOG_WARN;
434  break;
435  case LOG_NOTICE:
436  case LOG_INFO:
437  aprio = ANDROID_LOG_INFO;
438  break;
439  case LOG_DEBUG:
440  aprio = ANDROID_LOG_DEBUG;
441  break;
442  case LOG_UNKNOWN:
443  default:
444  aprio = ANDROID_LOG_UNKNOWN;
445  break;
446  }
447 #ifndef NDEBUG
448  __android_log_print(aprio, "mfe", "%s:%d:%s %s", qPrintable(item->m_file),
449  item->m_line, qPrintable(item->m_function),
450  qPrintable(item->m_message));
451 #else
452  __android_log_print(aprio, "mfe", "%s", qPrintable(item->m_message));
453 #endif
454 #endif
455 
456  item->DecrRef();
457 
458  return true;
459 }
460 
461 
465 {
466  logQueueMutex.lock();
467  flush(1000);
468  m_aborted = true;
469  logQueueMutex.unlock();
470  m_waitNotEmpty->wakeAll();
471 }
472 
476 bool LoggerThread::flush(int timeoutMS)
477 {
478  QElapsedTimer t;
479  t.start();
480  while (!m_aborted && !logQueue.isEmpty() && !t.hasExpired(timeoutMS))
481  {
482  m_waitNotEmpty->wakeAll();
483  int left = timeoutMS - t.elapsed();
484  if (left > 0)
485  m_waitEmpty->wait(&logQueueMutex, left);
486  }
487  return logQueue.isEmpty();
488 }
489 
491 {
492  if (!item)
493  return;
494 
495  item->setPid(m_pid);
496  item->setThreadName(item->getThreadName());
497  item->setAppName(m_appname);
498  item->setLogFile(m_filename);
499  item->setFacility(m_facility);
500 }
501 
502 
510 LoggingItem *LoggingItem::create(const char *_file,
511  const char *_function,
512  int _line, LogLevel_t _level,
513  LoggingType _type)
514 {
515  auto *item = new LoggingItem(_file, _function, _line, _level, _type);
516 
517  return item;
518 }
519 
528 void LogPrintLine( uint64_t mask, LogLevel_t level, const char *file, int line,
529  const char *function, QString message)
530 {
531  int type = kMessage;
532  type |= (mask & VB_FLUSH) ? kFlush : 0;
533  type |= (mask & VB_STDIO) ? kStandardIO : 0;
534  LoggingItem *item = LoggingItem::create(file, function, line, level,
535  (LoggingType)type);
536  if (!item)
537  return;
538 
539  item->m_message = std::move(message);
540 
541  QMutexLocker qLock(&logQueueMutex);
542 
543 #if defined( _MSC_VER ) && defined( _DEBUG )
544  OutputDebugStringA( qPrintable(item->m_message) );
545  OutputDebugStringA( "\n" );
546 #endif
547 
548  logQueue.enqueue(item);
549 
551  {
552  while (!logQueue.isEmpty())
553  {
554  item = logQueue.dequeue();
555  qLock.unlock();
556  logThread->handleItem(item);
557  logThread->logConsole(item);
558  item->DecrRef();
559  qLock.relock();
560  }
561  }
562  else if (logThread && !logThreadFinished && (type & kFlush))
563  {
564  logThread->flush();
565  }
566 }
567 
568 
573 {
574  logPropagateArgList.clear();
575 
576  QString mask = verboseString.simplified().replace(' ', ',');
577  logPropagateArgs = " --verbose " + mask;
578  logPropagateArgList << "--verbose" << mask;
579 
581  {
582  logPropagateArgs += " --logpath " + logPropagateOpts.m_path;
583  logPropagateArgList << "--logpath" << logPropagateOpts.m_path;
584  }
585 
586  QString name = logLevelGetName(logLevel);
587  logPropagateArgs += " --loglevel " + name;
588  logPropagateArgList << "--loglevel" << name;
589 
590  for (int i = 0; i < logPropagateOpts.m_quiet; i++)
591  {
592  logPropagateArgs += " --quiet";
593  logPropagateArgList << "--quiet";
594  }
595 
596 #if !defined(_WIN32) && !defined(Q_OS_ANDROID)
597  if (logPropagateOpts.m_facility >= 0)
598  {
599  const CODE *syslogname = nullptr;
600  for (syslogname = &facilitynames[0];
601  (syslogname->c_name &&
602  syslogname->c_val != logPropagateOpts.m_facility); syslogname++);
603 
604  logPropagateArgs += QString(" --syslog %1").arg(syslogname->c_name);
605  logPropagateArgList << "--syslog" << syslogname->c_name;
606  }
607 #if CONFIG_SYSTEMD_JOURNAL
608  else if (logPropagateOpts.m_facility == SYSTEMD_JOURNAL_FACILITY)
609  {
610  logPropagateArgs += " --systemd-journal";
611  logPropagateArgList << "--systemd-journal";
612  }
613 #endif
614 #endif
615 }
616 
620 {
621  return logPropagateOpts.m_quiet != 0;
622 }
623 
637 void logStart(const QString& logfile, bool progress, int quiet, int facility,
638  LogLevel_t level, bool propagate, bool testHarness)
639 {
640  if (logThread && logThread->isRunning())
641  return;
642 
643  logLevel = level;
644  LOG(VB_GENERAL, LOG_NOTICE, QString("Setting Log Level to LOG_%1")
645  .arg(logLevelGetName(logLevel).toUpper()));
646 
647  logPropagateOpts.m_propagate = propagate;
649  logPropagateOpts.m_facility = facility;
650 
651  if (propagate)
652  {
653  QFileInfo finfo(logfile);
654  QString path = finfo.path();
655  logPropagateOpts.m_path = path;
656  }
657 
659  if (testHarness)
660  return;
661 
662  if (!logThread)
663  logThread = new LoggerThread(logfile, progress, quiet, facility);
664 
665  logThread->start();
666 }
667 
669 void logStop(void)
670 {
671  if (logThread)
672  {
673  logThread->stop();
674  logThread->wait();
675  delete logThread;
676  logThread = nullptr;
677  }
678 }
679 
684 void loggingRegisterThread(const QString &name)
685 {
686  if (logThreadFinished)
687  return;
688 
689  QMutexLocker qLock(&logQueueMutex);
690 
691  LoggingItem *item = LoggingItem::create(__FILE__, __FUNCTION__,
692  __LINE__, LOG_DEBUG,
693  kRegistering);
694  if (item)
695  {
696  item->setThreadName((char *)name.toLocal8Bit().constData());
697  logQueue.enqueue(item);
698  }
699 }
700 
704 {
705  if (logThreadFinished)
706  return;
707 
708  QMutexLocker qLock(&logQueueMutex);
709 
710  LoggingItem *item = LoggingItem::create(__FILE__, __FUNCTION__, __LINE__,
711  LOG_DEBUG,
713  if (item)
714  logQueue.enqueue(item);
715 }
716 
717 
721 int syslogGetFacility([[maybe_unused]] const QString& facility)
722 {
723 #ifdef _WIN32
724  LOG(VB_GENERAL, LOG_NOTICE,
725  "Windows does not support syslog, disabling" );
726  return( -2 );
727 #elif defined(Q_OS_ANDROID)
728  LOG(VB_GENERAL, LOG_NOTICE,
729  "Android does not support syslog, disabling" );
730  return( -2 );
731 #else
732  const CODE *name = nullptr;
733  QByteArray ba = facility.toLocal8Bit();
734  char *string = (char *)ba.constData();
735 
736  for (name = &facilitynames[0];
737  name->c_name && (strcmp(name->c_name, string) != 0); name++);
738 
739  return( name->c_val );
740 #endif
741 }
742 
746 LogLevel_t logLevelGet(const QString& level)
747 {
748  QMutexLocker locker(&loglevelMapMutex);
749  if (!verboseInitialized)
750  {
751  locker.unlock();
752  verboseInit();
753  locker.relock();
754  }
755 
756  for (auto *item : std::as_const(loglevelMap))
757  {
758  if ( item->name == level.toLower() )
759  return (LogLevel_t)item->value;
760  }
761 
762  return LOG_UNKNOWN;
763 }
764 
768 QString logLevelGetName(LogLevel_t level)
769 {
770  QMutexLocker locker(&loglevelMapMutex);
771  if (!verboseInitialized)
772  {
773  locker.unlock();
774  verboseInit();
775  locker.relock();
776  }
777  LoglevelMap::iterator it = loglevelMap.find((int)level);
778 
779  if ( it == loglevelMap.end() )
780  return {"unknown"};
781 
782  return (*it)->name;
783 }
784 
791 void verboseAdd(uint64_t mask, QString name, bool additive, QString helptext)
792 {
793  auto *item = new VerboseDef;
794 
795  item->mask = mask;
796  // VB_GENERAL -> general
797  name.remove(0, 3);
798  name = name.toLower();
799  item->name = name;
800  item->additive = additive;
801  item->helpText = std::move(helptext);
802 
803  verboseMap.insert(name, item);
804 }
805 
811 void loglevelAdd(int value, QString name, char shortname)
812 {
813  auto *item = new LoglevelDef;
814 
815  item->value = value;
816  // LOG_CRIT -> crit
817  name.remove(0, 4);
818  name = name.toLower();
819  item->name = name;
820  item->shortname = shortname;
821 
822  loglevelMap.insert(value, item);
823 }
824 
826 void verboseInit(void)
827 {
828  QMutexLocker locker(&verboseMapMutex);
829  QMutexLocker locker2(&loglevelMapMutex);
830  verboseMap.clear();
831  loglevelMap.clear();
832 
833  // This looks funky, so I'll put some explanation here. The verbosedefs.h
834  // file gets included as part of the mythlogging.h include, and at that
835  // time, the normal (without MYTH_IMPLEMENT_VERBOSE defined) code case will
836  // define the VerboseMask enum. At this point, we force it to allow us to
837  // include the file again, but with MYTH_IMPLEMENT_VERBOSE set so that the
838  // single definition of the VB_* values can be shared to define also the
839  // contents of verboseMap, via repeated calls to verboseAdd()
840 
841 #undef VERBOSEDEFS_H_
842 #define MYTH_IMPLEMENT_VERBOSE
843 #include "verbosedefs.h"
844 
845  verboseInitialized = true;
846 }
847 
848 
851 void verboseHelp(void)
852 {
853  QString m_verbose = userDefaultValueStr.simplified().replace(' ', ',');
854 
855  std::cerr << "Verbose debug levels.\n"
856  "Accepts any combination (separated by comma) of:\n\n";
857 
858  for (VerboseMap::Iterator vit = verboseMap.begin();
859  vit != verboseMap.end(); ++vit )
860  {
861  VerboseDef *item = vit.value();
862  QString name = QString(" %1").arg(item->name, -15, ' ');
863  if (item->helpText.isEmpty())
864  continue;
865  std::cerr << name.toLocal8Bit().constData() << " - "
866  << item->helpText.toLocal8Bit().constData() << std::endl;
867  }
868 
869  std::cerr << std::endl <<
870  "The default for this program appears to be: '-v " <<
871  m_verbose.toLocal8Bit().constData() << "'\n\n"
872  "Most options are additive except for 'none' and 'all'.\n"
873  "These two are semi-exclusive and take precedence over any\n"
874  "other options. However, you may use something like\n"
875  "'-v none,jobqueue' to receive only JobQueue related messages\n"
876  "and override the default verbosity level.\n\n"
877  "Additive options may also be subtracted from 'all' by\n"
878  "prefixing them with 'no', so you may use '-v all,nodatabase'\n"
879  "to view all but database debug messages.\n\n";
880 
881  std::cerr
882  << "The 'global' loglevel is specified with --loglevel, but can be\n"
883  << "overridden on a component by component basis by appending "
884  << "':level'\n"
885  << "to the component.\n"
886  << " For example: -v gui:debug,channel:notice,record\n\n";
887 
888  std::cerr << "Some debug levels may not apply to this program.\n" << std::endl;
889 }
890 
894 int verboseArgParse(const QString& arg)
895 {
896  QString option;
897 
898  if (!verboseInitialized)
899  verboseInit();
900 
901  QMutexLocker locker(&verboseMapMutex);
902 
905 
906  if (arg.startsWith('-'))
907  {
908  std::cerr << "Invalid or missing argument to -v/--verbose option\n";
910  }
911 
912  static const QRegularExpression kSeparatorRE { "[^\\w:]+" };
913  QStringList verboseOpts = arg.split(kSeparatorRE, Qt::SkipEmptyParts);
914  for (const auto& opt : std::as_const(verboseOpts))
915  {
916  option = opt.toLower();
917  bool reverseOption = false;
918  QString optionLevel;
919 
920  if (option != "none" && option.startsWith("no"))
921  {
922  reverseOption = true;
923  option = option.right(option.length() - 2);
924  }
925 
926  if (option == "help")
927  {
928  verboseHelp();
930  }
931  if (option == "important")
932  {
933  std::cerr << "The \"important\" log mask is no longer valid.\n";
934  }
935  else if (option == "extra")
936  {
937  std::cerr << "The \"extra\" log mask is no longer valid. Please try "
938  "--loglevel debug instead.\n";
939  }
940  else if (option == "default")
941  {
943  {
946  }
947  else
948  {
951  }
952  }
953  else
954  {
955  int idx = option.indexOf(':');
956  if (idx != -1)
957  {
958  optionLevel = option.mid(idx + 1);
959  option = option.left(idx);
960  }
961 
962  VerboseDef *item = verboseMap.value(option);
963 
964  if (item)
965  {
966  if (reverseOption)
967  {
968  verboseMask &= ~(item->mask);
969  verboseString = verboseString.remove(' ' + item->name);
970  verboseString += " no" + item->name;
971  }
972  else
973  {
974  if (item->additive)
975  {
976  if (!(verboseMask & item->mask))
977  {
978  verboseMask |= item->mask;
979  verboseString += ' ' + item->name;
980  }
981  }
982  else
983  {
984  verboseMask = item->mask;
985  verboseString = item->name;
986  }
987 
988  if (!optionLevel.isEmpty())
989  {
990  LogLevel_t level = logLevelGet(optionLevel);
991  if (level != LOG_UNKNOWN)
992  componentLogLevel[item->mask] = level;
993  }
994  }
995  }
996  else
997  {
998  std::cerr << "Unknown argument for -v/--verbose: " <<
999  option.toLocal8Bit().constData() << std::endl;;
1001  }
1002  }
1003  }
1004 
1005  if (!haveUserDefaultValues)
1006  {
1007  haveUserDefaultValues = true;
1010  }
1011 
1012  return GENERIC_EXIT_OK;
1013 }
1014 
1019 QString logStrerror(int errnum)
1020 {
1021  return QString("%1 (%2)").arg(strerror(errnum)).arg(errnum);
1022 }
1023 
1024 
1025 /*
1026  * vim:ts=4:sw=4:ai:et:si:sts=4
1027  */
LogPropagateOpts::m_path
QString m_path
Definition: logging.cpp:78
loggingDeregisterThread
void loggingDeregisterThread(void)
Deregister the current thread's name.
Definition: logging.cpp:703
LoglevelMap
QMap< int, LoglevelDef * > LoglevelMap
Definition: verbosedefs.h:220
LoggingItem::m_line
int m_line
Definition: logging.h:122
debugRegistration
static bool debugRegistration
Definition: logging.cpp:72
logForwardStop
void logForwardStop(void)
Definition: loggingserver.cpp:504
logStart
void logStart(const QString &logfile, bool progress, int quiet, int facility, LogLevel_t level, bool propagate, bool testHarness)
Entry point to start logging for the application.
Definition: logging.cpp:637
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:66
logStrerror
QString logStrerror(int errnum)
Verbose helper function for ENO macro.
Definition: logging.cpp:1019
MThread::start
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:283
LoggingItem::threadName
QString threadName
Definition: logging.h:67
dbutil.h
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:62
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:572
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:160
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:300
LoggerThread::m_appname
QString m_appname
Cached application name.
Definition: logging.h:173
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:851
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:123
verboseInit
void verboseInit(void)
Initialize the logging levels and verbose levels.
Definition: logging.cpp:826
mythburn.write
def write(text, progress=True)
Definition: mythburn.py:308
logPropagateOpts
LogPropagateOpts logPropagateOpts
Definition: logging.cpp:81
LoggerThread
The logging thread that consumes the logging queue and dispatches each LoggingItem.
Definition: logging.h:144
LoggerThread::m_waitEmpty
QWaitCondition * m_waitEmpty
Condition variable for waiting for the queue to be empty Protected by logQueueMutex.
Definition: logging.h:164
kDeregistering
@ kDeregistering
Definition: logging.h:41
LoggingItem::epoch
qlonglong epoch
Definition: logging.h:64
quiet
int quiet
Definition: mythcommflag.cpp:68
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:495
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:58
LogPropagateOpts::m_facility
int m_facility
Definition: logging.cpp:77
GENERIC_EXIT_OK
@ GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:11
LoggingType
LoggingType
Definition: logging.h:38
LoggingItem::m_function
QString m_function
Definition: logging.h:128
mythsystemlegacy.h
logThreadFinished
static bool logThreadFinished
Definition: logging.cpp:71
logForwardMessage
void logForwardMessage(LoggingItem *item)
Definition: loggingserver.cpp:516
LoggingItem::setThreadName
void setThreadName(const QString &val)
Definition: logging.h:113
LoggingItem
The logging items that are generated by LOG() and are sent to the console.
Definition: logging.h:53
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:171
LoggerThread::fillItem
void fillItem(LoggingItem *item)
Definition: logging.cpp:490
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:528
verboseAdd
void verboseAdd(uint64_t mask, QString name, bool additive, QString helptext)
Add a verbose level to the verboseMap.
Definition: logging.cpp:791
kFlush
@ kFlush
Definition: logging.h:42
mythlogging.h
logLevelGetName
QString logLevelGetName(LogLevel_t level)
Map a log level enumerated value back to the name.
Definition: logging.cpp:768
LoggingItem::m_level
LogLevel_t m_level
Definition: logging.h:124
LoggingItem::pid
int pid
Definition: logging.h:57
loggingRegisterThread
void loggingRegisterThread(const QString &name)
Register the current thread with the given name.
Definition: logging.cpp:684
verboseMask
uint64_t verboseMask
Definition: logging.cpp:97
hardwareprofile.i18n.t
t
Definition: i18n.py:36
LogPropagateOpts
Definition: logging.cpp:74
compat.h
LoggerThread::m_aborted
bool m_aborted
Flag to abort the thread.
Definition: logging.h:168
logLevelGet
LogLevel_t logLevelGet(const QString &level)
Map a log level name back to the enumerated value.
Definition: logging.cpp:746
verboseInitialized
bool verboseInitialized
Definition: logging.cpp:87
logThreadMutex
static QMutex logThreadMutex
Definition: logging.cpp:65
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:76
LoggerThread::m_filename
QString m_filename
Filename of debug logfile.
Definition: logging.h:170
LoggerThread::run
void run(void) override
Run the logging thread.
Definition: logging.cpp:256
LoggingItem::m_message
QString m_message
Definition: logging.h:132
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:39
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:364
LoglevelDef::value
int value
Definition: verbosedefs.h:216
LoggerThread::flush
bool flush(int timeoutMS=200000)
Wait for the queue to be flushed (up to a timeout)
Definition: logging.cpp:476
verboseMap
VerboseMap verboseMap
Definition: logging.cpp:88
LoggingItem::setFacility
void setFacility(const int val)
Definition: logging.h:108
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:464
userDefaultValueStr
QString userDefaultValueStr
Definition: logging.cpp:102
LoggerThread::m_quiet
bool m_quiet
silence the console (console only)
Definition: logging.h:172
LoggerThread::m_facility
int m_facility
Cached syslog facility (or -1 to disable)
Definition: logging.h:175
logStop
void logStop(void)
Entry point for stopping logging for an application.
Definition: logging.cpp:669
LoggerThread::LoggerThread
LoggerThread(QString filename, bool progress, bool quiet, int facility)
LoggerThread constructor.
Definition: logging.cpp:218
LoggingItem::m_epoch
std::chrono::microseconds m_epoch
Definition: logging.h:126
logThread
static LoggerThread * logThread
Definition: logging.cpp:64
verboseArgParse
int verboseArgParse(const QString &arg)
Parse the –verbose commandline argument and set the verbose level.
Definition: logging.cpp:894
LogPropagateOpts::m_propagate
bool m_propagate
Definition: logging.cpp:75
syslogGetFacility
int syslogGetFacility([[maybe_unused]] const QString &facility)
Map a syslog facility name back to the enumerated value.
Definition: logging.cpp:721
haveUserDefaultValues
bool haveUserDefaultValues
Definition: logging.cpp:103
mythcorecontext.h
verboseDefaultInt
const uint64_t verboseDefaultInt
Definition: logging.cpp:94
LoggingItem::m_threadName
QString m_threadName
Definition: logging.h:129
logQueueMutex
static QMutex logQueueMutex
Definition: logging.cpp:61
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:510
LoggingItem::m_file
QString m_file
Definition: logging.h:127
logThreadTidHash
static QHash< uint64_t, int64_t > logThreadTidHash
Definition: logging.cpp:69
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:198
logPropagateArgList
QStringList logPropagateArgList
Definition: logging.cpp:83
LoggingItem::m_threadId
qulonglong m_threadId
Definition: logging.h:121
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:120
ComponentLogLevelMap
QMap< uint64_t, LogLevel_t > ComponentLogLevelMap
Definition: verbosedefs.h:221
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:811
kRegistering
@ kRegistering
Definition: logging.h:40
LoggingItem::setAppName
void setAppName(const QString &val)
Definition: logging.h:114
verboseMapMutex
QMutex verboseMapMutex
Definition: logging.cpp:89
logPropagateQuiet
bool logPropagateQuiet(void)
Check if we are propagating a "--quiet".
Definition: logging.cpp:619
LoggerThread::m_pid
pid_t m_pid
Cached pid value.
Definition: logging.h:176
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:68
LoggerThread::handleItem
static void handleItem(LoggingItem *item)
Handles each LoggingItem.
Definition: logging.cpp:312
loglevelMap
LoglevelMap loglevelMap
Definition: logging.cpp:91
exitcodes.h
LoggingItem::LoggingItem
LoggingItem()
Definition: logging.h:135
kStandardIO
@ kStandardIO
Definition: logging.h:43
ReferenceCounter::IncrRef
virtual int IncrRef(void)
Increments reference count.
Definition: referencecounter.cpp:101
build_compdb.filename
filename
Definition: build_compdb.py:21
GENERIC_EXIT_INVALID_CMDLINE
@ GENERIC_EXIT_INVALID_CMDLINE
Command line parse error.
Definition: exitcodes.h:16
loggingserver.h
LoggerThread::~LoggerThread
~LoggerThread() override
LoggerThread destructor. Triggers the deletion of all loggers.
Definition: logging.cpp:242
LoggingItem::setPid
void setPid(const int val)
Definition: logging.h:102
LoggingItem::setLogFile
void setLogFile(const QString &val)
Definition: logging.h:115
resetLogging
void resetLogging(void)
Intended for use only by the test harness.
Definition: logging.cpp:111
LoglevelDef
Definition: verbosedefs.h:215
ReferenceCounter
General purpose reference counter.
Definition: referencecounter.h:26
VerboseMap
QMap< QString, VerboseDef * > VerboseMap
Definition: verbosedefs.h:213