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