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