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