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