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