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 typedef QList<LoggerBase *> LoggerList;
66 
67 typedef struct {
69  qlonglong epoch;
71 typedef QMap<QString, LoggerListItem *> ClientMap;
72 
73 typedef QList<QString> ClientList;
74 typedef QMap<LoggerBase *, ClientList *> RevClientMap;
75 
76 static QMutex logClientMapMutex;
78 static QAtomicInt logClientCount;
79 
80 static QMutex logRevClientMapMutex;
82 
83 static QMutex logMsgListMutex;
85 static QWaitCondition logMsgListNotEmpty;
86 
87 #define TIMESTAMP_MAX 30
88 #define MAX_STRING_LENGTH (LOGLINE_MAX+120)
89 
93 LoggerBase::LoggerBase(const char *string)
94 {
95  QMutexLocker locker(&loggerMapMutex);
96  if (string)
97  {
98  m_handle = strdup(string);
99  loggerMap.insert(QString(m_handle), this);
100  }
101  else
102  {
103  m_handle = nullptr;
104  loggerMap.insert(QString(""), this);
105  }
106 }
107 
108 
112 {
113  QMutexLocker locker(&loggerMapMutex);
114  loggerMap.remove(QString(m_handle));
115 
116  if (m_handle)
117  free(m_handle);
118 }
119 
120 
123 FileLogger::FileLogger(const char *filename) :
124  LoggerBase(filename), m_opened(false), m_fd(-1)
125 {
126  m_fd = open(filename, O_WRONLY|O_CREAT|O_APPEND, 0664);
127  m_opened = (m_fd != -1);
128  LOG(VB_GENERAL, LOG_INFO, QString("Added logging to %1")
129  .arg(filename));
130 }
131 
132 
135 {
136  if( m_opened )
137  {
138  LOG(VB_GENERAL, LOG_INFO, QString("Removed logging to %1")
139  .arg(m_handle));
140  close(m_fd);
141  m_fd = -1;
142  m_opened = false;
143  }
144 }
145 
146 FileLogger *FileLogger::create(QString filename, QMutex *mutex)
147 {
148  QByteArray ba = filename.toLocal8Bit();
149  const char *file = ba.constData();
150  FileLogger *logger =
151  dynamic_cast<FileLogger *>(loggerMap.value(filename, nullptr));
152 
153  if (logger)
154  return logger;
155 
156  // Need to add a new FileLogger
157  mutex->unlock();
158  // inserts into loggerMap
159  logger = new FileLogger(file);
160  mutex->lock();
161 
162  ClientList *clients = new ClientList;
163  logRevClientMap.insert(logger, clients);
164  return logger;
165 }
166 
170 {
171  close(m_fd);
172 
173  m_fd = open(m_handle, O_WRONLY|O_CREAT|O_APPEND, 0664);
174  m_opened = (m_fd != -1);
175  LOG(VB_GENERAL, LOG_INFO, QString("Rolled logging on %1") .arg(m_handle));
176 }
177 
181 {
182  char line[MAX_STRING_LENGTH];
183  char usPart[9];
184  char timestamp[TIMESTAMP_MAX];
185 
186  if (!m_opened)
187  return false;
188 
189  time_t epoch = item->epoch();
190  struct tm tm;
191  localtime_r(&epoch, &tm);
192 
193  strftime(timestamp, TIMESTAMP_MAX-8, "%Y-%m-%d %H:%M:%S",
194  (const struct tm *)&tm);
195  snprintf( usPart, 9, ".%06d", (int)(item->usec()) );
196  strcat( timestamp, usPart );
197 
198  char shortname;
199  {
200  QMutexLocker locker(&loglevelMapMutex);
201  LoglevelMap::iterator it = loglevelMap.find(item->level());
202  if (it == loglevelMap.end())
203  shortname = '-';
204  else
205  shortname = (*it)->shortname;
206  }
207 
208  if( item->tid() )
209  snprintf( line, MAX_STRING_LENGTH,
210  "%s %c [%d/%" PREFIX64 "d] %s %s:%d (%s) - %s\n",
211  timestamp, shortname, item->pid(), item->tid(),
212  item->rawThreadName(), item->rawFile(), item->line(),
213  item->rawFunction(), item->rawMessage() );
214  else
215  snprintf( line, MAX_STRING_LENGTH,
216  "%s %c [%d] %s %s:%d (%s) - %s\n",
217  timestamp, shortname, item->pid(), item->rawThreadName(),
218  item->rawFile(), item->line(), item->rawFunction(),
219  item->rawMessage() );
220 
221  int result = write(m_fd, line, strlen(line));
222 
223  if( result == -1 )
224  {
225  LOG(VB_GENERAL, LOG_ERR,
226  QString("Closed Log output on fd %1 due to errors").arg(m_fd));
227  m_opened = false;
228  close( m_fd );
229  return false;
230  }
231  return true;
232 }
233 
234 #ifndef _WIN32
235 SyslogLogger::SyslogLogger(bool open) :
238  LoggerBase(nullptr), m_opened(false)
239 {
240  if (open)
241  {
242  openlog(nullptr, LOG_NDELAY, 0 );
243  m_opened = true;
244  }
245 
246  LOG(VB_GENERAL, LOG_INFO, "Added syslogging");
247 }
248 
251 {
252  LOG(VB_GENERAL, LOG_INFO, "Removing syslogging");
253  if (m_opened)
254  closelog();
255 }
256 
257 SyslogLogger *SyslogLogger::create(QMutex *mutex, bool open)
258 {
260  dynamic_cast<SyslogLogger *>(loggerMap.value("", nullptr));
261 
262  if (logger)
263  return logger;
264 
265  // Need to add a new FileLogger
266  mutex->unlock();
267  // inserts into loggerMap
268  logger = new SyslogLogger(open);
269  mutex->lock();
270 
271  ClientList *clients = new ClientList;
272  logRevClientMap.insert(logger, clients);
273  return logger;
274 }
275 
276 
280 {
281  if (!m_opened || item->facility() <= 0)
282  return false;
283 
284  char shortname;
285 
286  {
287  QMutexLocker locker(&loglevelMapMutex);
288  LoglevelDef *lev = loglevelMap.value(item->level(), nullptr);
289  if (!lev)
290  shortname = '-';
291  else
292  shortname = lev->shortname;
293  }
294  syslog(item->level() | item->facility(), "%s[%d]: %c %s %s:%d (%s) %s",
295  item->rawAppName(), item->pid(), shortname, item->rawThreadName(),
296  item->rawFile(), item->line(), item->rawFunction(),
297  item->rawMessage());
298 
299  return true;
300 }
301 
302 #if CONFIG_SYSTEMD_JOURNAL
305  LoggerBase(nullptr)
306 {
307  LOG(VB_GENERAL, LOG_INFO, "Added journal logging");
308 }
309 
312 {
313  LOG(VB_GENERAL, LOG_INFO, "Removing journal logging");
314 }
315 
316 JournalLogger *JournalLogger::create(QMutex *mutex)
317 {
319  dynamic_cast<JournalLogger *>(loggerMap.value("", nullptr));
320 
321  if (logger)
322  return logger;
323 
324  // Need to add a new FileLogger
325  mutex->unlock();
326  // inserts into loggerMap
327  logger = new JournalLogger();
328  mutex->lock();
329 
330  ClientList *clients = new ClientList;
331  logRevClientMap.insert(logger, clients);
332  return logger;
333 }
334 
335 
339 {
340  sd_journal_send(
341  "MESSAGE=%s", item->rawMessage(),
342  "PRIORITY=%d", item->level(),
343  "CODE_FILE=%s", item->rawFile(),
344  "CODE_LINE=%d", item->line(),
345  "CODE_FUNC=%s", item->rawFunction(),
346  "SYSLOG_IDENTIFIER=%s", item->rawAppName(),
347  "SYSLOG_PID=%d", item->pid(),
348  "MYTH_THREAD=%s", item->rawThreadName(),
349  NULL
350  );
351  return true;
352 }
353 #endif
354 #endif
355 
356 const int DatabaseLogger::kMinDisabledTime = 1000;
357 
360 DatabaseLogger::DatabaseLogger(const char *table) :
361  LoggerBase(table), m_opened(false), m_loggingTableExists(false)
362 {
363  m_query = QString(
364  "INSERT INTO %1 "
365  " (host, application, pid, tid, thread, filename, "
366  " line, function, msgtime, level, message) "
367  "VALUES (:HOST, :APP, :PID, :TID, :THREAD, :FILENAME, "
368  " :LINE, :FUNCTION, :MSGTIME, :LEVEL, :MESSAGE)")
369  .arg(m_handle);
370 
371  LOG(VB_GENERAL, LOG_INFO, QString("Added database logging to table %1")
372  .arg(m_handle));
373 
374  m_thread = new DBLoggerThread(this);
375  m_thread->start();
376 
377  m_opened = true;
378  m_disabled = false;
379 }
380 
383 {
384  LOG(VB_GENERAL, LOG_INFO, "Removing database logging");
385 
387 }
388 
389 DatabaseLogger *DatabaseLogger::create(QString table, QMutex *mutex)
390 {
391  QByteArray ba = table.toLocal8Bit();
392  const char *tble = ba.constData();
394  dynamic_cast<DatabaseLogger *>(loggerMap.value(table, nullptr));
395 
396  if (logger)
397  return logger;
398 
399  // Need to add a new FileLogger
400  mutex->unlock();
401  // inserts into loggerMap
402  logger = new DatabaseLogger(tble);
403  mutex->lock();
404 
405  ClientList *clients = new ClientList;
406  logRevClientMap.insert(logger, clients);
407  return logger;
408 }
409 
412 {
413  if( m_thread )
414  {
415  m_thread->stop();
416  m_thread->wait();
417  delete m_thread;
418  m_thread = nullptr;
419  }
420 }
421 
425 {
426  if (!m_thread)
427  return false;
428 
429  if (!m_thread->isRunning())
430  {
431  m_disabled = true;
432  m_disabledTime.start();
433  }
434 
435  if (!m_disabled && m_thread->queueFull())
436  {
437  m_disabled = true;
438  m_disabledTime.start();
439  LOG(VB_GENERAL, LOG_CRIT,
440  "Disabling DB Logging: too many messages queued");
441  return false;
442  }
443 
444  if (m_disabled && m_disabledTime.elapsed() > kMinDisabledTime)
445  {
446  if (isDatabaseReady() && !m_thread->queueFull())
447  {
448  m_disabled = false;
449  LOG(VB_GENERAL, LOG_CRIT, "Reenabling DB Logging");
450  }
451  }
452 
453  if (m_disabled)
454  return false;
455 
456  m_thread->enqueue(item);
457  return true;
458 }
459 
460 
465 {
466  char timestamp[TIMESTAMP_MAX];
467 
468  time_t epoch = item->epoch();
469  struct tm tm;
470  localtime_r(&epoch, &tm);
471 
472  strftime(timestamp, TIMESTAMP_MAX-8, "%Y-%m-%d %H:%M:%S",
473  (const struct tm *)&tm);
474 
475  query.bindValue(":TID", item->tid());
476  query.bindValue(":THREAD", item->threadName());
477  query.bindValue(":FILENAME", item->file());
478  query.bindValue(":LINE", item->line());
479  query.bindValue(":FUNCTION", item->function());
480  query.bindValue(":MSGTIME", timestamp);
481  query.bindValue(":LEVEL", item->level());
482  query.bindValue(":MESSAGE", item->message());
483  query.bindValue(":APP", item->appName());
484  query.bindValue(":PID", item->pid());
485 
486  if (!query.exec())
487  {
488  // Suppress Driver not loaded errors that occur at startup.
489  // and suppress additional errors for one second after the
490  // previous error (to avoid spamming the log).
491  QSqlError err = query.lastError();
492  if ((err.type() != 1
493  || !err.nativeErrorCode().isEmpty()
494  ) &&
495  (!m_errorLoggingTime.isValid() ||
496  (m_errorLoggingTime.elapsed() > 1000)))
497  {
498  MythDB::DBError("DBLogging", query);
499  m_errorLoggingTime.start();
500  }
501  return false;
502  }
503 
504  return true;
505 }
506 
510 {
511  query.prepare(m_query);
512  query.bindValue(":HOST", gCoreContext->GetHostName());
513 }
514 
518 {
519  bool ready = false;
520  MythDB *db = GetMythDB();
521 
522  if ((db) && db->HaveValidDatabase())
523  {
524  if ( !m_loggingTableExists )
526 
527  if ( m_loggingTableExists )
528  ready = true;
529  }
530 
531  return ready;
532 }
533 
537 bool DatabaseLogger::tableExists(const QString &table)
538 {
539  bool result = false;
540  MSqlQuery query(MSqlQuery::InitCon());
541  if (query.isConnected())
542  {
543  QString sql = "SELECT COLUMN_NAME "
544  " FROM INFORMATION_SCHEMA.COLUMNS "
545  " WHERE TABLE_SCHEMA = DATABASE() "
546  " AND TABLE_NAME = :TABLENAME "
547  " AND COLUMN_NAME = :COLUMNNAME;";
548  if (query.prepare(sql))
549  {
550  query.bindValue(":TABLENAME", table);
551  query.bindValue(":COLUMNNAME", "function");
552  if (query.exec() && query.next())
553  result = true;
554  }
555  }
556  return result;
557 }
558 
559 
563  MThread("DBLogger"), m_logger(logger),
564  m_queue(new QQueue<LoggingItem *>),
565  m_wait(new QWaitCondition()), m_aborted(false)
566 {
567 }
568 
572 {
573  stop();
574  wait();
575 
576  QMutexLocker qLock(&m_queueMutex);
577  while (!m_queue->empty())
578  m_queue->dequeue()->DecrRef();
579  delete m_queue;
580  delete m_wait;
581  m_queue = nullptr;
582  m_wait = nullptr;
583 }
584 
587 {
588  RunProlog();
589 
590  // Wait a bit before we start logging to the DB.. If we wait too long,
591  // then short-running tasks (like mythpreviewgen) will not log to the db
592  // at all, and that's undesirable.
593  while (true)
594  {
596  break;
597 
598  QMutexLocker locker(&m_queueMutex);
599  m_wait->wait(locker.mutex(), 100);
600  }
601 
602  if (!m_aborted)
603  {
604  // We want the query to be out of scope before the RunEpilog() so
605  // shutdown occurs correctly as otherwise the connection appears still
606  // in use, and we get a qWarning on shutdown.
607  MSqlQuery *query = new MSqlQuery(MSqlQuery::InitCon());
608  m_logger->prepare(*query);
609 
610  QMutexLocker qLock(&m_queueMutex);
611  while (!m_aborted || !m_queue->isEmpty())
612  {
613  if (m_queue->isEmpty())
614  {
615  m_wait->wait(qLock.mutex(), 100);
616  continue;
617  }
618 
619  LoggingItem *item = m_queue->dequeue();
620  if (!item)
621  continue;
622 
623  if (item->message()[0] != QChar('\0'))
624  {
625  qLock.unlock();
626  bool logged = m_logger->logqmsg(*query, item);
627  qLock.relock();
628 
629  if (!logged)
630  {
631  m_queue->prepend(item);
632  m_wait->wait(qLock.mutex(), 100);
633  delete query;
634  query = new MSqlQuery(MSqlQuery::InitCon());
635  m_logger->prepare(*query);
636  continue;
637  }
638  }
639 
640  item->DecrRef();
641  }
642 
643  delete query;
644  }
645 
646  RunEpilog();
647 }
648 
651 {
652  QMutexLocker qLock(&m_queueMutex);
653  m_aborted = true;
654  m_wait->wakeAll();
655 }
656 
658 {
659  QMutexLocker qLock(&m_queueMutex);
660  if (!m_aborted)
661  {
662  if (item)
663  {
664  item->IncrRef();
665  }
666  m_queue->enqueue(item);
667  }
668  return true;
669 }
670 
671 
672 #ifndef _WIN32
673 
676 void logSigHup(void)
677 {
678  if (!logForwardThread)
679  return;
680 
681  // This will be running in the thread that's used by SignalHandler
682  // Emit the signal which is connected to a slot that runs in the actual
683  // handling thread.
685 }
686 #endif
687 
688 
691  MThread("LogForward"), m_aborted(false)
692 {
693  moveToThread(qthread());
694 }
695 
698 {
699  stop();
700  wait();
701 }
702 
707 {
708  RunProlog();
709 
710  connect(this, SIGNAL(incomingSigHup(void)), this, SLOT(handleSigHup(void)),
711  Qt::QueuedConnection);
712 
713  qRegisterMetaType<QList<QByteArray> >("QList<QByteArray>");
714 
715  while (!m_aborted)
716  {
717  qApp->processEvents(QEventLoop::AllEvents, 10);
718  qApp->sendPostedEvents(nullptr, QEvent::DeferredDelete);
719 
720  {
721  QMutexLocker lock(&logMsgListMutex);
722  if (logMsgList.isEmpty() &&
723  !logMsgListNotEmpty.wait(lock.mutex(), 90))
724  {
725  continue;
726  }
727 
728  int processed = 0;
729  while (!logMsgList.isEmpty())
730  {
731  processed++;
732  LogMessage *msg = logMsgList.takeFirst();
733  lock.unlock();
734  forwardMessage(msg);
735  delete msg;
736 
737  // Force a processEvents every 128 messages so a busy queue
738  // doesn't preclude timer notifications, etc.
739  if ((processed & 127) == 0)
740  {
741  qApp->processEvents(QEventLoop::AllEvents, 10);
742  qApp->sendPostedEvents(nullptr, QEvent::DeferredDelete);
743  }
744 
745  lock.relock();
746  }
747  }
748  }
749 
750  LoggerList loggers;
751 
752  {
753  QMutexLocker lock(&loggerMapMutex);
754  loggers = loggerMap.values();
755  }
756 
757  while (!loggers.isEmpty())
758  {
759  LoggerBase *logger = loggers.takeFirst();
760  delete logger;
761  }
762 
763  RunEpilog();
764 }
765 
766 
769 {
770 #ifndef _WIN32
771  LOG(VB_GENERAL, LOG_INFO, "SIGHUP received, rolling log files.");
772 
773  /* SIGHUP was sent. Close and reopen debug logfiles */
774  QMutexLocker locker(&loggerMapMutex);
775  QMap<QString, LoggerBase *>::iterator it;
776  for (it = loggerMap.begin(); it != loggerMap.end(); ++it)
777  {
778  it.value()->reopen();
779  }
780 #endif
781 }
782 
784 {
785 #ifdef DUMP_PACKET
786  QList<QByteArray>::const_iterator it = msg->begin();
787  int i = 0;
788  for (; it != msg->end(); ++it, i++)
789  {
790  QByteArray buf = *it;
791  cout << i << ":\t" << buf.size() << endl << "\t"
792  << buf.toHex().constData() << endl << "\t"
793  << buf.constData() << endl;
794  }
795 #endif
796 
797  // First section is the client id
798  QByteArray clientBa = msg->first();
799  QString clientId = QString(clientBa.toHex());
800 
801  QByteArray json = msg->at(1);
802 
803  if (json.size() == 0)
804  {
805  // cout << "invalid msg, no json data " << qPrintable(clientId) << endl;
806  return;
807  }
808 
809  QMutexLocker lock(&logClientMapMutex);
810  LoggerListItem *logItem = logClientMap.value(clientId, nullptr);
811 
812  // cout << "msg " << clientId.toLocal8Bit().constData() << endl;
813  if (logItem)
814  {
815  loggingGetTimeStamp(&logItem->epoch, nullptr);
816  }
817  else
818  {
819  LoggingItem *item = LoggingItem::create(json);
820 
821  logClientCount.ref();
822  LOG(VB_FILE, LOG_DEBUG, QString("New Logging Client: ID: %1 (#%2)")
823  .arg(clientId).arg(logClientCount.fetchAndAddOrdered(0)));
824 
825  QMutexLocker lock2(&loggerMapMutex);
826  QMutexLocker lock3(&logRevClientMapMutex);
827 
828  // Need to find or create the loggers
829  LoggerList *loggers = new LoggerList;
831 
832  // FileLogger from logFile
833  QString logfile = item->logFile();
834  if (!logfile.isEmpty())
835  {
836  logger = FileLogger::create(logfile, lock2.mutex());
837 
838  ClientList *clients = logRevClientMap.value(logger);
839 
840  if (clients)
841  clients->insert(0, clientId);
842 
843  if (logger && loggers)
844  loggers->insert(0, logger);
845  }
846 
847 #ifndef _WIN32
848  // SyslogLogger from facility
849  int facility = item->facility();
850  if (facility > 0)
851  {
852  logger = SyslogLogger::create(lock2.mutex());
853 
854  ClientList *clients = logRevClientMap.value(logger);
855 
856  if (clients)
857  clients->insert(0, clientId);
858 
859  if (logger && loggers)
860  loggers->insert(0, logger);
861  }
862 
863 #if CONFIG_SYSTEMD_JOURNAL
864  // Journal Logger
865  if (facility == SYSTEMD_JOURNAL_FACILITY)
866  {
867  logger = JournalLogger::create(lock2.mutex());
868 
869  ClientList *clients = logRevClientMap.value(logger);
870 
871  if (clients)
872  clients->insert(0, clientId);
873 
874  if (logger && loggers)
875  loggers->insert(0, logger);
876  }
877 #endif
878 #endif
879 
880  // DatabaseLogger from table
881  QString table = item->table();
882  if (!table.isEmpty())
883  {
884  logger = DatabaseLogger::create(table, lock2.mutex());
885 
886  ClientList *clients = logRevClientMap.value(logger);
887 
888  if (clients)
889  clients->insert(0, clientId);
890 
891  if (logger && loggers)
892  loggers->insert(0, logger);
893  }
894 
895  logItem = new LoggerListItem;
896  loggingGetTimeStamp(&logItem->epoch, nullptr);
897  logItem->list = loggers;
898  logClientMap.insert(clientId, logItem);
899 
900  item->DecrRef();
901  }
902 
903  if (logItem && logItem->list && !logItem->list->isEmpty())
904  {
905  LoggerList::iterator it = logItem->list->begin();
906  LoggingItem *item = LoggingItem::create(json);
907  if (!item)
908  return;
909  for (; it != logItem->list->end(); ++it)
910  {
911  (*it)->logmsg(item);
912  }
913  item->DecrRef();
914  }
915 }
916 
919 {
920  m_aborted = true;
921 }
922 
923 bool logForwardStart(void)
924 {
927 
928  usleep(10000);
930 }
931 
932 void logForwardStop(void)
933 {
934  if (!logForwardThread)
935  return;
936 
938  delete logForwardThread;
939  logForwardThread = nullptr;
940 
941  QMutexLocker locker(&loggerMapMutex);
942  for (auto it = loggerMap.begin(); it != loggerMap.end(); ++it)
943  {
944  it.value()->stopDatabaseAccess();
945  }
946 }
947 
948 void logForwardMessage(const QList<QByteArray> &msg)
949 {
950  LogMessage *message = new LogMessage(msg);
951  QMutexLocker lock(&logMsgListMutex);
952 
953  bool wasEmpty = logMsgList.isEmpty();
954  logMsgList.append(message);
955 
956  if (wasEmpty)
957  logMsgListNotEmpty.wakeAll();
958 }
959 
960 /*
961  * vim:ts=4:sw=4:ai:et:si:sts=4
962  */
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:216
QString logfile
bool m_opened
The database is opened.
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:794
bool m_loggingTableExists
The desired logging table exists.
void start(QThread::Priority=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:295
def write(text, progress=True)
Definition: mythburn.py:279
LoggerList * list
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:46
void bindValue(const QString &placeholder, const QVariant &val)
Definition: mythdbcon.cpp:875
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
~DatabaseLogger()
DatabaseLogger deconstructor.
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:135
#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
void forwardMessage(LogMessage *msg)
~LogForwardThread()
LogForwardThread destructor.
QList< QByteArray > LogMessage
static DatabaseLogger * create(QString table, QMutex *mutex)
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:312
QMap< QString, LoggerListItem * > ClientMap
const char * rawFunction() const
Definition: logging.h:134
static QMutex logMsgListMutex
QList< LoggerBase * > LoggerList
DBLoggerThread(DatabaseLogger *logger)
DBLoggerThread constructor.
bool isConnected(void)
Only updated once during object creation.
Definition: mythdbcon.h:135
static RevClientMap logRevClientMap
void reopen(void) override
Reopen the logfile after a SIGHUP.
#define SYSTEMD_JOURNAL_FACILITY
Definition: logging.h:26
Database logger - logs to the MythTV database.
Definition: loggingserver.h:98
static __inline struct tm * localtime_r(const time_t *timep, struct tm *result)
Definition: compat.h:279
QTime m_errorLoggingTime
Time when DB error logging was last done.
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:120
LoggerBase(const char *string)
LoggerBase Constructor.
int pid
Definition: logging.h:65
QList< LogMessage * > LogMessageList
static LogMessageList logMsgList
bool logmsg(LoggingItem *item) override
Process a log message for the logger instance.
void incomingSigHup(void)
The logging thread that forwards received messages to the consuming loggers via ZeroMQ.
void stop(void)
Stop the thread by setting the abort flag.
qlonglong epoch
Definition: logging.h:73
QString logFile
Definition: logging.h:79
FileLogger(const char *filename)
FileLogger constructor.
void logForwardMessage(const QList< QByteArray > &msg)
virtual int IncrRef(void)
Increments reference count.
uint usec
Definition: logging.h:68
qlonglong tid
Definition: logging.h:66
VERBOSE_PREAMBLE false
Definition: verbosedefs.h:85
bool logForwardStart(void)
QSqlError lastError(void) const
Definition: mythdbcon.h:186
bool isDatabaseReady(void)
Check if the database is ready for use.
#define close
Definition: compat.h:16
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.
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:275
static QWaitCondition logMsgListNotEmpty
void stop(void)
Tell the thread to stop by setting the m_aborted flag.
#define PREFIX64
Definition: compat.h:386
virtual ~LoggerBase()
LoggerBase Deconstructor.
QList< QString > ClientList
File-based logger - used for logfiles and console.
Definition: loggingserver.h:48
static MSqlQueryInfo InitCon(ConnectionReuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:547
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.
static JournalLogger * create(QMutex *mutex)
~DBLoggerThread()
DBLoggerThread deconstructor.
void handleSigHup(void)
SIGHUP handler - reopen all open logfiles for logrollers.
bool m_disabled
DB logging is temporarily disabled.
static QMap< QString, LoggerBase * > loggerMap
int facility
Definition: logging.h:72
const char * rawFile() const
Definition: logging.h:133
void stopDatabaseAccess(void) override
Stop logging to the database and wait for the thread to stop.
const char * rawAppName() const
Definition: logging.h:136
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:819
LoglevelMap loglevelMap
Definition: logging.cpp:101
void run(void) override
Run the log forwarding thread.
QTime m_disabledTime
Time when the DB logging was disabled.
static QMutex logRevClientMapMutex
const char * rawMessage() const
Definition: logging.h:139
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
QString message
Definition: logging.h:80
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.
QMutex loglevelMapMutex
Definition: logging.cpp:102
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
Definition: mthread.cpp:203
volatile bool m_aborted
Used during shutdown to indicate that the thread should stop ASAP.
QMutex m_queueMutex
Mutex for protecting the queue.
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:245
void logForwardStop(void)
static QAtomicInt logClientCount
char shortname
Definition: verbosedefs.h:214
static FileLogger * create(QString filename, QMutex *mutex)
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:615
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
QString file
Definition: logging.h:74
~FileLogger()
FileLogger deconstructor - close the logfile.
QString threadName
Definition: logging.h:76
QString GetHostName(void)
#define MAX_STRING_LENGTH
QMap< LoggerBase *, ClientList * > RevClientMap
static LoggingItem * create(const char *, const char *, int, LogLevel_t, LoggingType)
Create a new LoggingItem.
Definition: logging.cpp:559
LogForwardThread()
LogForwardThread constructor.
#define TIMESTAMP_MAX
QString table
Definition: logging.h:78