MythTV  master
loggingserver.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 <QCoreApplication>
10 #include <QFileInfo>
11 #include <QStringList>
12 #include <QMap>
13 #include <QSocketNotifier>
14 #include <iostream>
15 
16 #include "mythlogging.h"
17 #include "logging.h"
18 #include "loggingserver.h"
19 #include "mythdb.h"
20 #include "mythcorecontext.h"
21 #include "dbutil.h"
22 #include "exitcodes.h"
23 #include "compat.h"
24 
25 #include <cstdlib>
26 #ifndef _WIN32
27 #include "mythsyslog.h"
28 #if CONFIG_SYSTEMD_JOURNAL
29 #define SD_JOURNAL_SUPPRESS_LOCATION 1 // NOLINT(cppcoreguidelines-macro-usage)
30 #include <systemd/sd-journal.h>
31 #endif
32 #endif
33 #include <cstdarg>
34 #include <cstring>
35 #include <sys/stat.h>
36 #include <sys/types.h>
37 #include <fcntl.h>
38 #include <cstdio>
39 #include <unistd.h>
40 #if HAVE_GETTIMEOFDAY
41 #include <sys/time.h>
42 #endif
43 #include <csignal>
44 
45 // Various ways to get to thread's tid
46 #if defined(__linux__)
47 #include <sys/syscall.h>
48 #elif defined(__FreeBSD__)
49 extern "C" {
50 #include <sys/ucontext.h>
51 #include <sys/thr.h>
52 }
53 #elif defined(Q_OS_DARWIN)
54 #include <mach/mach.h>
55 #endif
56 
57 static QMutex loggerMapMutex;
58 static QMap<QString, LoggerBase *> loggerMap;
59 
61 
62 using LoggerList = QList<LoggerBase *>;
63 
66  std::chrono::seconds m_itemEpoch;
67 };
68 using ClientMap = QMap<QString, LoggerListItem *>;
69 
70 using ClientList = QList<QString>;
71 using RevClientMap = QHash<LoggerBase *, ClientList *>;
72 
73 static QMutex logClientMapMutex;
75 static QAtomicInt logClientCount;
76 
77 static QMutex logRevClientMapMutex;
79 
80 static QMutex logMsgListMutex;
82 static QWaitCondition logMsgListNotEmpty;
83 
87 LoggerBase::LoggerBase(const char *string) :
88  m_handle(string)
89 {
90  QMutexLocker locker(&loggerMapMutex);
91  loggerMap.insert(m_handle, this);
92 }
93 
94 
98 {
99  QMutexLocker locker(&loggerMapMutex);
100  loggerMap.remove(m_handle);
101 }
102 
103 
108 {
109  m_fd = open(filename, O_WRONLY|O_CREAT|O_APPEND, 0664);
110  m_opened = (m_fd != -1);
111  LOG(VB_GENERAL, LOG_INFO, QString("Added logging to %1")
112  .arg(filename));
113 }
114 
115 
118 {
119  if( m_opened )
120  {
121  LOG(VB_GENERAL, LOG_INFO, QString("Removed logging to %1")
122  .arg(m_handle));
123  close(m_fd);
124  m_fd = -1;
125  m_opened = false;
126  }
127 }
128 
129 FileLogger *FileLogger::create(const QString& filename, QMutex *mutex)
130 {
131  QByteArray ba = filename.toLocal8Bit();
132  const char *file = ba.constData();
133  auto *logger =
134  qobject_cast<FileLogger *>(loggerMap.value(filename, nullptr));
135 
136  if (logger)
137  return logger;
138 
139  // Need to add a new FileLogger
140  mutex->unlock();
141  // inserts into loggerMap
142  logger = new FileLogger(file);
143  mutex->lock();
144 
145  auto *clients = new ClientList;
146  logRevClientMap.insert(logger, clients);
147  return logger;
148 }
149 
153 {
154  close(m_fd);
155 
156  m_fd = open(qPrintable(m_handle), O_WRONLY|O_CREAT|O_APPEND, 0664);
157  m_opened = (m_fd != -1);
158  LOG(VB_GENERAL, LOG_INFO, QString("Rolled logging on %1") .arg(m_handle));
159 }
160 
164 {
165  if (!m_opened)
166  return false;
167 
168  QString timestamp = item->getTimestampUs();
169  QChar shortname = item->getLevelChar();
170 
171  std::string line;
172  if( item->tid() )
173  {
174  line = qPrintable(QString("%1 %2 [%3/%4] %5 %6:%7 (%8) - %9\n")
175  .arg(timestamp, shortname,
176  QString::number(item->pid()),
177  QString::number(item->tid()),
178  item->threadName(), item->file(),
179  QString::number(item->line()),
180  item->function(),
181  item->message()));
182  }
183  else
184  {
185  line = qPrintable(QString("%1 %2 [%3] %5 %6:%7 (%8) - %9\n")
186  .arg(timestamp, shortname,
187  QString::number(item->pid()),
188  item->threadName(), item->file(),
189  QString::number(item->line()),
190  item->function(),
191  item->message()));
192  }
193 
194  int result = write(m_fd, line.data(), line.size());
195 
196  if( result == -1 )
197  {
198  LOG(VB_GENERAL, LOG_ERR,
199  QString("Closed Log output on fd %1 due to errors").arg(m_fd));
200  m_opened = false;
201  close( m_fd );
202  return false;
203  }
204  return true;
205 }
206 
207 #ifndef _WIN32
208 SyslogLogger::SyslogLogger(bool open) :
211  LoggerBase(nullptr)
212 {
213  if (open)
214  {
215  openlog(nullptr, LOG_NDELAY, 0 );
216  m_opened = true;
217  }
218 
219  LOG(VB_GENERAL, LOG_INFO, "Added syslogging");
220 }
221 
223 SyslogLogger::~SyslogLogger()
224 {
225  LOG(VB_GENERAL, LOG_INFO, "Removing syslogging");
226  if (m_opened)
227  closelog();
228 }
229 
230 SyslogLogger *SyslogLogger::create(QMutex *mutex, bool open)
231 {
232  auto *logger = qobject_cast<SyslogLogger *>(loggerMap.value("", nullptr));
233  if (logger)
234  return logger;
235 
236  // Need to add a new FileLogger
237  mutex->unlock();
238  // inserts into loggerMap
239  logger = new SyslogLogger(open);
240  mutex->lock();
241 
242  auto *clients = new ClientList;
243  logRevClientMap.insert(logger, clients);
244  return logger;
245 }
246 
247 
250 bool SyslogLogger::logmsg(LoggingItem *item)
251 {
252  if (!m_opened || item->facility() <= 0)
253  return false;
254 
255  char shortname = item->getLevelChar();
256  syslog(item->level() | item->facility(), "%s[%d]: %c %s %s:%d (%s) %s",
257  qPrintable(item->appName()), item->pid(), shortname,
258  qPrintable(item->threadName()), qPrintable(item->file()), item->line(),
259  qPrintable(item->function()), qPrintable(item->message()));
260 
261  return true;
262 }
263 
264 #if CONFIG_SYSTEMD_JOURNAL
265 JournalLogger::JournalLogger() :
267  LoggerBase(nullptr)
268 {
269  LOG(VB_GENERAL, LOG_INFO, "Added journal logging");
270 }
271 
273 JournalLogger::~JournalLogger()
274 {
275  LOG(VB_GENERAL, LOG_INFO, "Removing journal logging");
276 }
277 
278 JournalLogger *JournalLogger::create(QMutex *mutex)
279 {
280  auto *logger = qobject_cast<JournalLogger *>(loggerMap.value("", nullptr));
281  if (logger)
282  return logger;
283 
284  // Need to add a new FileLogger
285  mutex->unlock();
286  // inserts into loggerMap
287  logger = new JournalLogger();
288  mutex->lock();
289 
290  auto *clients = new ClientList;
291  logRevClientMap.insert(logger, clients);
292  return logger;
293 }
294 
295 
298 bool JournalLogger::logmsg(LoggingItem *item)
299 {
300  sd_journal_send(
301  "MESSAGE=%s", qUtf8Printable(item->message()),
302  "PRIORITY=%d", item->level(),
303  "CODE_FILE=%s", qUtf8Printable(item->file()),
304  "CODE_LINE=%d", item->line(),
305  "CODE_FUNC=%s", qUtf8Printable(item->function()),
306  "SYSLOG_IDENTIFIER=%s", qUtf8Printable(item->appName()),
307  "SYSLOG_PID=%d", item->pid(),
308  "MYTH_THREAD=%s", qUtf8Printable(item->threadName()),
309  NULL
310  );
311  return true;
312 }
313 #endif
314 #endif
315 
318 DatabaseLogger::DatabaseLogger(const char *table) :
319  LoggerBase(table)
320 {
321  m_query = QString(
322  "INSERT INTO %1 "
323  " (`host`, `application`, `pid`, `tid`, `thread`, `filename`, "
324  " `line`, `function`, `msgtime`, `level`, `message`) "
325  "VALUES (:HOST, :APP, :PID, :TID, :THREAD, :FILENAME, "
326  " :LINE, :FUNCTION, :MSGTIME, :LEVEL, :MESSAGE)")
327  .arg(m_handle);
328 
329  LOG(VB_GENERAL, LOG_INFO, QString("Added database logging to table %1")
330  .arg(m_handle));
331 
332  m_thread = new DBLoggerThread(this);
333  m_thread->start();
334 }
335 
338 {
339  LOG(VB_GENERAL, LOG_INFO, "Removing database logging");
340 
342 }
343 
344 DatabaseLogger *DatabaseLogger::create(const QString& table, QMutex *mutex)
345 {
346  QByteArray ba = table.toLocal8Bit();
347  const char *tble = ba.constData();
348  auto *logger =
349  qobject_cast<DatabaseLogger *>(loggerMap.value(table, nullptr));
350 
351  if (logger)
352  return logger;
353 
354  // Need to add a new FileLogger
355  mutex->unlock();
356  // inserts into loggerMap
357  logger = new DatabaseLogger(tble);
358  mutex->lock();
359 
360  auto *clients = new ClientList;
361  logRevClientMap.insert(logger, clients);
362  return logger;
363 }
364 
367 {
368  if( m_thread )
369  {
370  m_thread->stop();
371  m_thread->wait();
372  delete m_thread;
373  m_thread = nullptr;
374  }
375 }
376 
380 {
381  if (!m_thread)
382  return false;
383 
384  if (!m_thread->isRunning())
385  {
386  m_disabledTime.start();
387  }
388 
389  if (!m_disabledTime.isValid() && m_thread->queueFull())
390  {
391  m_disabledTime.start();
392  LOG(VB_GENERAL, LOG_CRIT,
393  "Disabling DB Logging: too many messages queued");
394  return false;
395  }
396 
397  if (m_disabledTime.isValid() && m_disabledTime.hasExpired(kMinDisabledTime.count()))
398  {
399  if (isDatabaseReady() && !m_thread->queueFull())
400  {
401  m_disabledTime.invalidate();
402  LOG(VB_GENERAL, LOG_CRIT, "Reenabling DB Logging");
403  }
404  }
405 
406  if (m_disabledTime.isValid())
407  return false;
408 
409  m_thread->enqueue(item);
410  return true;
411 }
412 
413 
418 {
419  QString timestamp = item->getTimestamp();
420 
421  query.bindValue(":TID", item->tid());
422  query.bindValue(":THREAD", item->threadName());
423  query.bindValue(":FILENAME", item->file());
424  query.bindValue(":LINE", item->line());
425  query.bindValue(":FUNCTION", item->function());
426  query.bindValue(":MSGTIME", timestamp);
427  query.bindValue(":LEVEL", item->level());
428  query.bindValue(":MESSAGE", item->message());
429  query.bindValue(":APP", item->appName());
430  query.bindValue(":PID", item->pid());
431 
432  if (!query.exec())
433  {
434  // Suppress Driver not loaded errors that occur at startup.
435  // and suppress additional errors for one second after the
436  // previous error (to avoid spamming the log).
437  QSqlError err = query.lastError();
438  if ((err.type() != 1
439  || !err.nativeErrorCode().isEmpty()
440  ) &&
441  (!m_errorLoggingTime.isValid() ||
442  (m_errorLoggingTime.hasExpired(1000))))
443  {
444  MythDB::DBError("DBLogging", query);
445  m_errorLoggingTime.start();
446  }
447  return false;
448  }
449 
450  return true;
451 }
452 
456 {
457  query.prepare(m_query);
458  query.bindValue(":HOST", gCoreContext->GetHostName());
459 }
460 
464 {
465  bool ready = false;
466  MythDB *db = GetMythDB();
467 
468  if ((db) && db->HaveValidDatabase())
469  {
470  if ( !m_loggingTableExists )
472 
473  if ( m_loggingTableExists )
474  ready = true;
475  }
476 
477  return ready;
478 }
479 
483 bool DatabaseLogger::tableExists(const QString &table)
484 {
485  bool result = false;
486  MSqlQuery query(MSqlQuery::InitCon());
487  if (query.isConnected())
488  {
489  QString sql = "SELECT COLUMN_NAME "
490  " FROM INFORMATION_SCHEMA.COLUMNS "
491  " WHERE TABLE_SCHEMA = DATABASE() "
492  " AND TABLE_NAME = :TABLENAME "
493  " AND COLUMN_NAME = :COLUMNNAME;";
494  if (query.prepare(sql))
495  {
496  query.bindValue(":TABLENAME", table);
497  query.bindValue(":COLUMNNAME", "function");
498  if (query.exec() && query.next())
499  result = true;
500  }
501  }
502  return result;
503 }
504 
505 
509  MThread("DBLogger"), m_logger(logger),
510  m_queue(new QQueue<LoggingItem *>),
511  m_wait(new QWaitCondition())
512 {
513 }
514 
518 {
519  stop();
520  wait();
521 
522  QMutexLocker qLock(&m_queueMutex);
523  while (!m_queue->empty())
524  m_queue->dequeue()->DecrRef();
525  delete m_queue;
526  delete m_wait;
527  m_queue = nullptr;
528  m_wait = nullptr;
529 }
530 
533 {
534  RunProlog();
535 
536  // Wait a bit before we start logging to the DB.. If we wait too long,
537  // then short-running tasks (like mythpreviewgen) will not log to the db
538  // at all, and that's undesirable.
539  while (true)
540  {
542  break;
543 
544  QMutexLocker locker(&m_queueMutex);
545  m_wait->wait(locker.mutex(), 100);
546  }
547 
548  if (!m_aborted)
549  {
550  // We want the query to be out of scope before the RunEpilog() so
551  // shutdown occurs correctly as otherwise the connection appears still
552  // in use, and we get a qWarning on shutdown.
553  auto *query = new MSqlQuery(MSqlQuery::InitCon());
554  m_logger->prepare(*query);
555 
556  QMutexLocker qLock(&m_queueMutex);
557  while (!m_aborted || !m_queue->isEmpty())
558  {
559  if (m_queue->isEmpty())
560  {
561  m_wait->wait(qLock.mutex(), 100);
562  continue;
563  }
564 
565  LoggingItem *item = m_queue->dequeue();
566  if (!item)
567  continue;
568 
569  if (!item->message().isEmpty())
570  {
571  qLock.unlock();
572  bool logged = m_logger->logqmsg(*query, item);
573  qLock.relock();
574 
575  if (!logged)
576  {
577  m_queue->prepend(item);
578  m_wait->wait(qLock.mutex(), 100);
579  delete query;
580  query = new MSqlQuery(MSqlQuery::InitCon());
581  m_logger->prepare(*query);
582  continue;
583  }
584  }
585 
586  item->DecrRef();
587  }
588 
589  delete query;
590  }
591 
592  RunEpilog();
593 }
594 
597 {
598  QMutexLocker qLock(&m_queueMutex);
599  m_aborted = true;
600  m_wait->wakeAll();
601 }
602 
604 {
605  QMutexLocker qLock(&m_queueMutex);
606  if (!m_aborted)
607  {
608  if (item)
609  {
610  item->IncrRef();
611  }
612  m_queue->enqueue(item);
613  }
614  return true;
615 }
616 
617 
618 #ifndef _WIN32
619 
622 void logSigHup(void)
623 {
624  if (!logForwardThread)
625  return;
626 
627  // This will be running in the thread that's used by SignalHandler
628  // Emit the signal which is connected to a slot that runs in the actual
629  // handling thread.
631 }
632 #endif
633 
634 
637  MThread("LogForward")
638 {
639  moveToThread(qthread());
640 }
641 
644 {
645  stop();
646  wait();
647 }
648 
653 {
654  RunProlog();
655 
656  connect(this, &LogForwardThread::incomingSigHup,
658  Qt::QueuedConnection);
659 
660  qRegisterMetaType<QList<QByteArray> >("QList<QByteArray>");
661 
662  while (!m_aborted)
663  {
664  qApp->processEvents(QEventLoop::AllEvents, 10);
665  qApp->sendPostedEvents(nullptr, QEvent::DeferredDelete);
666 
667  {
668  QMutexLocker lock(&logMsgListMutex);
669  if (logMsgList.isEmpty() &&
670  !logMsgListNotEmpty.wait(lock.mutex(), 90))
671  {
672  continue;
673  }
674 
675  int processed = 0;
676  while (!logMsgList.isEmpty())
677  {
678  processed++;
679  LogMessage *msg = logMsgList.takeFirst();
680  lock.unlock();
681  forwardMessage(msg);
682  delete msg;
683 
684  // Force a processEvents every 128 messages so a busy queue
685  // doesn't preclude timer notifications, etc.
686  if ((processed & 127) == 0)
687  {
688  qApp->processEvents(QEventLoop::AllEvents, 10);
689  qApp->sendPostedEvents(nullptr, QEvent::DeferredDelete);
690  }
691 
692  lock.relock();
693  }
694  }
695  }
696 
697  LoggerList loggers;
698 
699  {
700  QMutexLocker lock(&loggerMapMutex);
701  loggers = loggerMap.values();
702  }
703 
704  while (!loggers.isEmpty())
705  {
706  LoggerBase *logger = loggers.takeFirst();
707  delete logger;
708  }
709 
710  RunEpilog();
711 }
712 
713 
716 {
717 #ifndef _WIN32
718  LOG(VB_GENERAL, LOG_INFO, "SIGHUP received, rolling log files.");
719 
720  /* SIGHUP was sent. Close and reopen debug logfiles */
721  QMutexLocker locker(&loggerMapMutex);
722  QMap<QString, LoggerBase *>::iterator it;
723  for (it = loggerMap.begin(); it != loggerMap.end(); ++it)
724  {
725  it.value()->reopen();
726  }
727 #endif
728 }
729 
731 {
732 #ifdef DUMP_PACKET
733  QList<QByteArray>::const_iterator it = msg->begin();
734  int i = 0;
735  for (; it != msg->end(); ++it, i++)
736  {
737  QByteArray buf = *it;
738  cout << i << ":\t" << buf.size() << endl << "\t"
739  << buf.toHex().constData() << endl << "\t"
740  << buf.constData() << endl;
741  }
742 #endif
743 
744  // First section is the client id
745  QByteArray clientBa = msg->first();
746  QString clientId = QString(clientBa.toHex());
747 
748  QByteArray json = msg->at(1);
749 
750  if (json.size() == 0)
751  {
752  // cout << "invalid msg, no json data " << qPrintable(clientId) << endl;
753  return;
754  }
755 
756  QMutexLocker lock(&logClientMapMutex);
757  LoggerListItem *logItem = logClientMap.value(clientId, nullptr);
758 
759  // cout << "msg " << clientId.toLocal8Bit().constData() << endl;
760  if (logItem)
761  {
762  logItem->m_itemEpoch = nowAsDuration<std::chrono::seconds>();
763  }
764  else
765  {
766  LoggingItem *item = LoggingItem::create(json);
767 
768  logClientCount.ref();
769  LOG(VB_FILE, LOG_DEBUG, QString("New Logging Client: ID: %1 (#%2)")
770  .arg(clientId).arg(logClientCount.fetchAndAddOrdered(0)));
771 
772  QMutexLocker lock2(&loggerMapMutex);
773  QMutexLocker lock3(&logRevClientMapMutex);
774 
775  // Need to find or create the loggers
776  auto *loggers = new LoggerList;
777 
778  // FileLogger from logFile
779  QString logfile = item->logFile();
780  if (!logfile.isEmpty())
781  {
782  LoggerBase *logger = FileLogger::create(logfile, lock2.mutex());
783 
784  ClientList *clients = logRevClientMap.value(logger);
785 
786  if (clients)
787  clients->insert(0, clientId);
788 
789  if (logger && loggers)
790  loggers->insert(0, logger);
791  }
792 
793 #ifndef _WIN32
794  // SyslogLogger from facility
795  int facility = item->facility();
796  if (facility > 0)
797  {
798  LoggerBase *logger = SyslogLogger::create(lock2.mutex());
799 
800  ClientList *clients = logRevClientMap.value(logger);
801 
802  if (clients)
803  clients->insert(0, clientId);
804 
805  if (logger && loggers)
806  loggers->insert(0, logger);
807  }
808 
809 #if CONFIG_SYSTEMD_JOURNAL
810  // Journal Logger
811  if (facility == SYSTEMD_JOURNAL_FACILITY)
812  {
813  LoggerBase *logger = JournalLogger::create(lock2.mutex());
814 
815  ClientList *clients = logRevClientMap.value(logger);
816 
817  if (clients)
818  clients->insert(0, clientId);
819 
820  if (logger && loggers)
821  loggers->insert(0, logger);
822  }
823 #endif
824 #endif
825 
826  // DatabaseLogger from table
827  QString table = item->table();
828  if (!table.isEmpty())
829  {
830  LoggerBase *logger = DatabaseLogger::create(table, lock2.mutex());
831 
832  ClientList *clients = logRevClientMap.value(logger);
833 
834  if (clients)
835  clients->insert(0, clientId);
836 
837  if (logger && loggers)
838  loggers->insert(0, logger);
839  }
840 
841  logItem = new LoggerListItem;
842  logItem->m_itemEpoch = nowAsDuration<std::chrono::seconds>();
843  logItem->m_itemList = loggers;
844  logClientMap.insert(clientId, logItem);
845 
846  item->DecrRef();
847  }
848 
849  if (logItem && logItem->m_itemList && !logItem->m_itemList->isEmpty())
850  {
851  LoggingItem *item = LoggingItem::create(json);
852  if (!item)
853  return;
854  for (auto *it : qAsConst(*logItem->m_itemList))
855  it->logmsg(item);
856  item->DecrRef();
857  }
858 }
859 
862 {
863  m_aborted = true;
864 }
865 
866 bool logForwardStart(void)
867 {
870 
871  usleep(10000);
873 }
874 
875 void logForwardStop(void)
876 {
877  if (!logForwardThread)
878  return;
879 
881  delete logForwardThread;
882  logForwardThread = nullptr;
883 
884  QMutexLocker locker(&loggerMapMutex);
885  for (auto it = loggerMap.begin(); it != loggerMap.end(); ++it)
886  {
887  it.value()->stopDatabaseAccess();
888  }
889 }
890 
891 void logForwardMessage(const QList<QByteArray> &msg)
892 {
893  auto *message = new LogMessage(msg);
894  QMutexLocker lock(&logMsgListMutex);
895 
896  bool wasEmpty = logMsgList.isEmpty();
897  logMsgList.append(message);
898 
899  if (wasEmpty)
900  logMsgListNotEmpty.wakeAll();
901 }
902 
903 /*
904  * vim:ts=4:sw=4:ai:et:si:sts=4
905  */
logClientCount
static QAtomicInt logClientCount
Definition: loggingserver.cpp:75
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:807
DatabaseLogger::logqmsg
bool logqmsg(MSqlQuery &query, LoggingItem *item)
Actually insert a log message from the queue into the database.
Definition: loggingserver.cpp:417
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:128
DatabaseLogger::m_errorLoggingTime
QElapsedTimer m_errorLoggingTime
Elapsed time since DB error logging was last done.
Definition: loggingserver.h:120
FileLogger::m_opened
bool m_opened
true when the logfile is opened
Definition: loggingserver.h:56
logForwardStop
void logForwardStop(void)
Definition: loggingserver.cpp:875
LoggingItem::getTimestamp
QString getTimestamp(const char *format="yyyy-MM-dd HH:mm:ss") const
Convert numerical timestamp to a readable date and time.
Definition: logging.cpp:206
MThread::start
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:283
LoggingItem::threadName
QString threadName
Definition: logging.h:67
dbutil.h
ReferenceCounter::DecrRef
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
Definition: referencecounter.cpp:125
loggerMap
static QMap< QString, LoggerBase * > loggerMap
Definition: loggingserver.cpp:58
logClientMapMutex
static QMutex logClientMapMutex
Definition: loggingserver.cpp:73
DBLoggerThread::~DBLoggerThread
~DBLoggerThread() override
DBLoggerThread deconstructor.
Definition: loggingserver.cpp:517
mythdb.h
LogMessageList
QList< LogMessage * > LogMessageList
Definition: loggingserver.h:125
LoggerBase
Base class for the various logging mechanisms.
Definition: loggingserver.h:24
DatabaseLogger::create
static DatabaseLogger * create(const QString &table, QMutex *mutex)
Definition: loggingserver.cpp:344
LoggingItem::logFile
QString logFile
Definition: logging.h:70
MThread::wait
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:300
DatabaseLogger::m_thread
DBLoggerThread * m_thread
The database queue handling thread.
Definition: loggingserver.h:115
FileLogger::logmsg
bool logmsg(LoggingItem *item) override
Process a log message, writing to the logfile.
Definition: loggingserver.cpp:163
logForwardThread
LogForwardThread * logForwardThread
Definition: loggingserver.cpp:60
mythburn.write
def write(text, progress=True)
Definition: mythburn.py:308
DatabaseLogger::tableExists
static bool tableExists(const QString &table)
Checks whether table exists and is ready for writing.
Definition: loggingserver.cpp:483
DatabaseLogger::logmsg
bool logmsg(LoggingItem *item) override
Process a log message, queuing it for logging to the database.
Definition: loggingserver.cpp:379
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:608
logForwardMessage
void logForwardMessage(const QList< QByteArray > &msg)
Definition: loggingserver.cpp:891
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MThread::RunProlog
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
Definition: mthread.cpp:196
logForwardStart
bool logForwardStart(void)
Definition: loggingserver.cpp:866
logfile
QString logfile
Definition: mythjobqueue.cpp:45
LoggingItem::table
QString table
Definition: logging.h:69
GetMythDB
MythDB * GetMythDB(void)
Definition: mythdb.cpp:50
build_compdb.file
file
Definition: build_compdb.py:55
LoggingItem::tid
qlonglong tid
Definition: logging.h:58
LoggerBase::~LoggerBase
~LoggerBase() override
LoggerBase Deconstructor.
Definition: loggingserver.cpp:97
DBLoggerThread::DBLoggerThread
DBLoggerThread(DatabaseLogger *logger)
DBLoggerThread constructor.
Definition: loggingserver.cpp:508
LogForwardThread::m_aborted
bool m_aborted
Flag to abort the thread.
Definition: loggingserver.h:140
DatabaseLogger::stopDatabaseAccess
void stopDatabaseAccess(void) override
Stop logging to the database and wait for the thread to stop.
Definition: loggingserver.cpp:366
DatabaseLogger::kMinDisabledTime
static constexpr std::chrono::milliseconds kMinDisabledTime
Minimum time to disable DB logging.
Definition: loggingserver.h:121
LoggingItem::level
int level
Definition: logging.h:62
close
#define close
Definition: compat.h:43
LoggingItem
The logging items that are generated by LOG() and are sent to the console.
Definition: logging.h:53
RevClientMap
QHash< LoggerBase *, ClientList * > RevClientMap
Definition: loggingserver.cpp:71
DatabaseLogger::isDatabaseReady
bool isDatabaseReady(void)
Check if the database is ready for use.
Definition: loggingserver.cpp:463
LoggingItem::getLevelChar
char getLevelChar(void)
Get the message log level as a single character.
Definition: logging.cpp:221
DatabaseLogger::m_loggingTableExists
bool m_loggingTableExists
The desired logging table exists.
Definition: loggingserver.h:118
mythlogging.h
DatabaseLogger::m_query
QString m_query
The database query to insert log messages.
Definition: loggingserver.h:116
LogForwardThread
The logging thread that forwards received messages to the consuming loggers via ZeroMQ.
Definition: loggingserver.h:129
LoggingItem::pid
int pid
Definition: logging.h:57
LogForwardThread::~LogForwardThread
~LogForwardThread() override
LogForwardThread destructor.
Definition: loggingserver.cpp:643
DBLoggerThread::stop
void stop(void)
Tell the thread to stop by setting the m_aborted flag.
Definition: loggingserver.cpp:596
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:540
compat.h
logRevClientMap
static RevClientMap logRevClientMap
Definition: loggingserver.cpp:78
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:227
LogForwardThread::handleSigHup
static void handleSigHup(void)
SIGHUP handler - reopen all open logfiles for logrollers.
Definition: loggingserver.cpp:715
logMsgList
static LogMessageList logMsgList
Definition: loggingserver.cpp:81
LogForwardThread::run
void run(void) override
Run the log forwarding thread.
Definition: loggingserver.cpp:652
LoggerBase::m_handle
QString m_handle
semi-opaque handle for identifying instance
Definition: loggingserver.h:41
MThread::qthread
QThread * qthread(void)
Returns the thread, this will always return the same pointer no matter how often you restart the thre...
Definition: mthread.cpp:233
DatabaseLogger::DatabaseLogger
DatabaseLogger(const char *table)
DatabaseLogger constructor.
Definition: loggingserver.cpp:318
MThread::RunEpilog
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:209
DatabaseLogger::DBLoggerThread
friend class DBLoggerThread
Definition: loggingserver.h:100
LoggerBase::LoggerBase
LoggerBase(const char *string)
LoggerBase Constructor.
Definition: loggingserver.cpp:87
LoggingItem::message
QString message
Definition: logging.h:71
MSqlQuery::isConnected
bool isConnected(void) const
Only updated once during object creation.
Definition: mythdbcon.h:138
DatabaseLogger::~DatabaseLogger
~DatabaseLogger() override
DatabaseLogger deconstructor.
Definition: loggingserver.cpp:337
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:54
LoggingItem::appName
QString appName
Definition: logging.h:68
FileLogger::m_fd
int m_fd
contains the file descriptor for the logfile
Definition: loggingserver.h:57
LoggingItem::file
QString file
Definition: logging.h:65
LogForwardThread::LogForwardThread
LogForwardThread()
LogForwardThread constructor.
Definition: loggingserver.cpp:636
logRevClientMapMutex
static QMutex logRevClientMapMutex
Definition: loggingserver.cpp:77
MSqlQuery::lastError
QSqlError lastError(void) const
Definition: mythdbcon.h:214
DBLoggerThread::m_aborted
volatile bool m_aborted
Used during shutdown to indicate that the thread should stop ASAP.
Definition: loggingserver.h:195
LoggingItem::line
int line
Definition: logging.h:60
ClientMap
QMap< QString, LoggerListItem * > ClientMap
Definition: loggingserver.cpp:68
logClientMap
static ClientMap logClientMap
Definition: loggingserver.cpp:74
DatabaseLogger
Database logger - logs to the MythTV database.
Definition: loggingserver.h:96
LoggerListItem::m_itemList
LoggerList * m_itemList
Definition: loggingserver.cpp:65
logMsgListNotEmpty
static QWaitCondition logMsgListNotEmpty
Definition: loggingserver.cpp:82
DatabaseLogger::m_disabledTime
QElapsedTimer m_disabledTime
Elapsed time since the DB logging was disabled.
Definition: loggingserver.h:119
mythcorecontext.h
FileLogger
File-based logger - used for logfiles and console.
Definition: loggingserver.h:45
LogForwardThread::stop
void stop(void)
Stop the thread by setting the abort flag.
Definition: loggingserver.cpp:861
DatabaseLogger::prepare
void prepare(MSqlQuery &query)
Prepare the database query for use, and bind constant values to it.
Definition: loggingserver.cpp:455
LoggingItem::create
static LoggingItem * create(const char *_file, const char *_function, int _line, LogLevel_t _level, LoggingType _type)
Create a new LoggingItem.
Definition: logging.cpp:536
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:883
logMsgListMutex
static QMutex logMsgListMutex
Definition: loggingserver.cpp:80
mythsyslog.h
logging.h
FileLogger::~FileLogger
~FileLogger() override
FileLogger deconstructor - close the logfile.
Definition: loggingserver.cpp:117
LoggingItem::getTimestampUs
QString getTimestampUs(const char *format="yyyy-MM-dd HH:mm:ss") const
Definition: logging.cpp:213
DBLoggerThread::enqueue
bool enqueue(LoggingItem *item)
Enqueues a LoggingItem onto the queue for the thread to consume.
Definition: loggingserver.cpp:603
logger
static void logger(cdio_log_level_t level, const char *message)
Definition: cddecoder.cpp:35
MThread
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:48
MThread::isRunning
bool isRunning(void) const
Definition: mthread.cpp:263
DBLoggerThread::m_logger
DatabaseLogger * m_logger
The associated logger instance.
Definition: loggingserver.h:189
DBLoggerThread::m_queueMutex
QMutex m_queueMutex
Mutex for protecting the queue.
Definition: loggingserver.h:190
LoggingItem::function
QString function
Definition: logging.h:66
ClientList
QList< QString > ClientList
Definition: loggingserver.cpp:70
MythCoreContext::GetHostName
QString GetHostName(void)
Definition: mythcorecontext.cpp:836
FileLogger::FileLogger
FileLogger(const char *filename)
FileLogger constructor.
Definition: loggingserver.cpp:106
LogForwardThread::incomingSigHup
void incomingSigHup(void)
FileLogger::reopen
void reopen(void) override
Reopen the logfile after a SIGHUP.
Definition: loggingserver.cpp:152
FileLogger::create
static FileLogger * create(const QString &filename, QMutex *mutex)
Definition: loggingserver.cpp:129
DBLoggerThread::queueFull
bool queueFull(void)
Indicates when the queue is full.
Definition: loggingserver.h:183
LoggingItem::facility
int facility
Definition: logging.h:63
exitcodes.h
loggerMapMutex
static QMutex loggerMapMutex
Definition: loggingserver.cpp:57
LoggerListItem
Definition: loggingserver.cpp:64
ReferenceCounter::IncrRef
virtual int IncrRef(void)
Increments reference count.
Definition: referencecounter.cpp:101
build_compdb.filename
filename
Definition: build_compdb.py:21
LogMessage
QList< QByteArray > LogMessage
Definition: loggingserver.h:124
loggingserver.h
LoggerListItem::m_itemEpoch
std::chrono::seconds m_itemEpoch
Definition: loggingserver.cpp:66
DBLoggerThread::m_queue
QQueue< LoggingItem * > * m_queue
Queue of LoggingItems to insert.
Definition: loggingserver.h:191
LogForwardThread::forwardMessage
static void forwardMessage(LogMessage *msg)
Definition: loggingserver.cpp:730
DBLoggerThread::run
void run(void) override
Start the thread.
Definition: loggingserver.cpp:532
LoggerList
QList< LoggerBase * > LoggerList
Definition: loggingserver.cpp:62
DBLoggerThread::m_wait
QWaitCondition * m_wait
Wait condition used for waiting for the queue to not be full.
Definition: loggingserver.h:192
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:832