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