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