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)
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(const 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)
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
303 JournalLogger::JournalLogger() :
305  LoggerBase(nullptr)
306 {
307  LOG(VB_GENERAL, LOG_INFO, "Added journal logging");
308 }
309 
311 JournalLogger::~JournalLogger()
312 {
313  LOG(VB_GENERAL, LOG_INFO, "Removing journal logging");
314 }
315 
316 JournalLogger *JournalLogger::create(QMutex *mutex)
317 {
318  JournalLogger *logger =
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 
338 bool JournalLogger::logmsg(LoggingItem *item)
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)
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 
380 {
381  LOG(VB_GENERAL, LOG_INFO, "Removing database logging");
382 
384 }
385 
386 DatabaseLogger *DatabaseLogger::create(const QString& table, QMutex *mutex)
387 {
388  QByteArray ba = table.toLocal8Bit();
389  const char *tble = ba.constData();
391  dynamic_cast<DatabaseLogger *>(loggerMap.value(table, nullptr));
392 
393  if (logger)
394  return logger;
395 
396  // Need to add a new FileLogger
397  mutex->unlock();
398  // inserts into loggerMap
399  logger = new DatabaseLogger(tble);
400  mutex->lock();
401 
402  ClientList *clients = new ClientList;
403  logRevClientMap.insert(logger, clients);
404  return logger;
405 }
406 
409 {
410  if( m_thread )
411  {
412  m_thread->stop();
413  m_thread->wait();
414  delete m_thread;
415  m_thread = nullptr;
416  }
417 }
418 
422 {
423  if (!m_thread)
424  return false;
425 
426  if (!m_thread->isRunning())
427  {
428  m_disabled = true;
429  m_disabledTime.start();
430  }
431 
432  if (!m_disabled && m_thread->queueFull())
433  {
434  m_disabled = true;
435  m_disabledTime.start();
436  LOG(VB_GENERAL, LOG_CRIT,
437  "Disabling DB Logging: too many messages queued");
438  return false;
439  }
440 
441  if (m_disabled && m_disabledTime.elapsed() > kMinDisabledTime)
442  {
443  if (isDatabaseReady() && !m_thread->queueFull())
444  {
445  m_disabled = false;
446  LOG(VB_GENERAL, LOG_CRIT, "Reenabling DB Logging");
447  }
448  }
449 
450  if (m_disabled)
451  return false;
452 
453  m_thread->enqueue(item);
454  return true;
455 }
456 
457 
462 {
463  char timestamp[TIMESTAMP_MAX];
464 
465  time_t epoch = item->epoch();
466  struct tm tm;
467  localtime_r(&epoch, &tm);
468 
469  strftime(timestamp, TIMESTAMP_MAX-8, "%Y-%m-%d %H:%M:%S",
470  (const struct tm *)&tm);
471 
472  query.bindValue(":TID", item->tid());
473  query.bindValue(":THREAD", item->threadName());
474  query.bindValue(":FILENAME", item->file());
475  query.bindValue(":LINE", item->line());
476  query.bindValue(":FUNCTION", item->function());
477  query.bindValue(":MSGTIME", timestamp);
478  query.bindValue(":LEVEL", item->level());
479  query.bindValue(":MESSAGE", item->message());
480  query.bindValue(":APP", item->appName());
481  query.bindValue(":PID", item->pid());
482 
483  if (!query.exec())
484  {
485  // Suppress Driver not loaded errors that occur at startup.
486  // and suppress additional errors for one second after the
487  // previous error (to avoid spamming the log).
488  QSqlError err = query.lastError();
489  if ((err.type() != 1
490  || !err.nativeErrorCode().isEmpty()
491  ) &&
492  (!m_errorLoggingTime.isValid() ||
493  (m_errorLoggingTime.elapsed() > 1000)))
494  {
495  MythDB::DBError("DBLogging", query);
496  m_errorLoggingTime.start();
497  }
498  return false;
499  }
500 
501  return true;
502 }
503 
507 {
508  query.prepare(m_query);
509  query.bindValue(":HOST", gCoreContext->GetHostName());
510 }
511 
515 {
516  bool ready = false;
517  MythDB *db = GetMythDB();
518 
519  if ((db) && db->HaveValidDatabase())
520  {
521  if ( !m_loggingTableExists )
523 
524  if ( m_loggingTableExists )
525  ready = true;
526  }
527 
528  return ready;
529 }
530 
534 bool DatabaseLogger::tableExists(const QString &table)
535 {
536  bool result = false;
537  MSqlQuery query(MSqlQuery::InitCon());
538  if (query.isConnected())
539  {
540  QString sql = "SELECT COLUMN_NAME "
541  " FROM INFORMATION_SCHEMA.COLUMNS "
542  " WHERE TABLE_SCHEMA = DATABASE() "
543  " AND TABLE_NAME = :TABLENAME "
544  " AND COLUMN_NAME = :COLUMNNAME;";
545  if (query.prepare(sql))
546  {
547  query.bindValue(":TABLENAME", table);
548  query.bindValue(":COLUMNNAME", "function");
549  if (query.exec() && query.next())
550  result = true;
551  }
552  }
553  return result;
554 }
555 
556 
560  MThread("DBLogger"), m_logger(logger),
561  m_queue(new QQueue<LoggingItem *>),
562  m_wait(new QWaitCondition())
563 {
564 }
565 
569 {
570  stop();
571  wait();
572 
573  QMutexLocker qLock(&m_queueMutex);
574  while (!m_queue->empty())
575  m_queue->dequeue()->DecrRef();
576  delete m_queue;
577  delete m_wait;
578  m_queue = nullptr;
579  m_wait = nullptr;
580 }
581 
584 {
585  RunProlog();
586 
587  // Wait a bit before we start logging to the DB.. If we wait too long,
588  // then short-running tasks (like mythpreviewgen) will not log to the db
589  // at all, and that's undesirable.
590  while (true)
591  {
593  break;
594 
595  QMutexLocker locker(&m_queueMutex);
596  m_wait->wait(locker.mutex(), 100);
597  }
598 
599  if (!m_aborted)
600  {
601  // We want the query to be out of scope before the RunEpilog() so
602  // shutdown occurs correctly as otherwise the connection appears still
603  // in use, and we get a qWarning on shutdown.
604  MSqlQuery *query = new MSqlQuery(MSqlQuery::InitCon());
605  m_logger->prepare(*query);
606 
607  QMutexLocker qLock(&m_queueMutex);
608  while (!m_aborted || !m_queue->isEmpty())
609  {
610  if (m_queue->isEmpty())
611  {
612  m_wait->wait(qLock.mutex(), 100);
613  continue;
614  }
615 
616  LoggingItem *item = m_queue->dequeue();
617  if (!item)
618  continue;
619 
620  if (item->message()[0] != QChar('\0'))
621  {
622  qLock.unlock();
623  bool logged = m_logger->logqmsg(*query, item);
624  qLock.relock();
625 
626  if (!logged)
627  {
628  m_queue->prepend(item);
629  m_wait->wait(qLock.mutex(), 100);
630  delete query;
631  query = new MSqlQuery(MSqlQuery::InitCon());
632  m_logger->prepare(*query);
633  continue;
634  }
635  }
636 
637  item->DecrRef();
638  }
639 
640  delete query;
641  }
642 
643  RunEpilog();
644 }
645 
648 {
649  QMutexLocker qLock(&m_queueMutex);
650  m_aborted = true;
651  m_wait->wakeAll();
652 }
653 
655 {
656  QMutexLocker qLock(&m_queueMutex);
657  if (!m_aborted)
658  {
659  if (item)
660  {
661  item->IncrRef();
662  }
663  m_queue->enqueue(item);
664  }
665  return true;
666 }
667 
668 
669 #ifndef _WIN32
670 
673 void logSigHup(void)
674 {
675  if (!logForwardThread)
676  return;
677 
678  // This will be running in the thread that's used by SignalHandler
679  // Emit the signal which is connected to a slot that runs in the actual
680  // handling thread.
682 }
683 #endif
684 
685 
688  MThread("LogForward")
689 {
690  moveToThread(qthread());
691 }
692 
695 {
696  stop();
697  wait();
698 }
699 
704 {
705  RunProlog();
706 
707  connect(this, SIGNAL(incomingSigHup(void)), this, SLOT(handleSigHup(void)),
708  Qt::QueuedConnection);
709 
710  qRegisterMetaType<QList<QByteArray> >("QList<QByteArray>");
711 
712  while (!m_aborted)
713  {
714  qApp->processEvents(QEventLoop::AllEvents, 10);
715  qApp->sendPostedEvents(nullptr, QEvent::DeferredDelete);
716 
717  {
718  QMutexLocker lock(&logMsgListMutex);
719  if (logMsgList.isEmpty() &&
720  !logMsgListNotEmpty.wait(lock.mutex(), 90))
721  {
722  continue;
723  }
724 
725  int processed = 0;
726  while (!logMsgList.isEmpty())
727  {
728  processed++;
729  LogMessage *msg = logMsgList.takeFirst();
730  lock.unlock();
731  forwardMessage(msg);
732  delete msg;
733 
734  // Force a processEvents every 128 messages so a busy queue
735  // doesn't preclude timer notifications, etc.
736  if ((processed & 127) == 0)
737  {
738  qApp->processEvents(QEventLoop::AllEvents, 10);
739  qApp->sendPostedEvents(nullptr, QEvent::DeferredDelete);
740  }
741 
742  lock.relock();
743  }
744  }
745  }
746 
747  LoggerList loggers;
748 
749  {
750  QMutexLocker lock(&loggerMapMutex);
751  loggers = loggerMap.values();
752  }
753 
754  while (!loggers.isEmpty())
755  {
756  LoggerBase *logger = loggers.takeFirst();
757  delete logger;
758  }
759 
760  RunEpilog();
761 }
762 
763 
766 {
767 #ifndef _WIN32
768  LOG(VB_GENERAL, LOG_INFO, "SIGHUP received, rolling log files.");
769 
770  /* SIGHUP was sent. Close and reopen debug logfiles */
771  QMutexLocker locker(&loggerMapMutex);
772  QMap<QString, LoggerBase *>::iterator it;
773  for (it = loggerMap.begin(); it != loggerMap.end(); ++it)
774  {
775  it.value()->reopen();
776  }
777 #endif
778 }
779 
781 {
782 #ifdef DUMP_PACKET
783  QList<QByteArray>::const_iterator it = msg->begin();
784  int i = 0;
785  for (; it != msg->end(); ++it, i++)
786  {
787  QByteArray buf = *it;
788  cout << i << ":\t" << buf.size() << endl << "\t"
789  << buf.toHex().constData() << endl << "\t"
790  << buf.constData() << endl;
791  }
792 #endif
793 
794  // First section is the client id
795  QByteArray clientBa = msg->first();
796  QString clientId = QString(clientBa.toHex());
797 
798  QByteArray json = msg->at(1);
799 
800  if (json.size() == 0)
801  {
802  // cout << "invalid msg, no json data " << qPrintable(clientId) << endl;
803  return;
804  }
805 
806  QMutexLocker lock(&logClientMapMutex);
807  LoggerListItem *logItem = logClientMap.value(clientId, nullptr);
808 
809  // cout << "msg " << clientId.toLocal8Bit().constData() << endl;
810  if (logItem)
811  {
812  loggingGetTimeStamp(&logItem->epoch, nullptr);
813  }
814  else
815  {
816  LoggingItem *item = LoggingItem::create(json);
817 
818  logClientCount.ref();
819  LOG(VB_FILE, LOG_DEBUG, QString("New Logging Client: ID: %1 (#%2)")
820  .arg(clientId).arg(logClientCount.fetchAndAddOrdered(0)));
821 
822  QMutexLocker lock2(&loggerMapMutex);
823  QMutexLocker lock3(&logRevClientMapMutex);
824 
825  // Need to find or create the loggers
826  LoggerList *loggers = new LoggerList;
828 
829  // FileLogger from logFile
830  QString logfile = item->logFile();
831  if (!logfile.isEmpty())
832  {
833  logger = FileLogger::create(logfile, lock2.mutex());
834 
835  ClientList *clients = logRevClientMap.value(logger);
836 
837  if (clients)
838  clients->insert(0, clientId);
839 
840  if (logger && loggers)
841  loggers->insert(0, logger);
842  }
843 
844 #ifndef _WIN32
845  // SyslogLogger from facility
846  int facility = item->facility();
847  if (facility > 0)
848  {
849  logger = SyslogLogger::create(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 #if CONFIG_SYSTEMD_JOURNAL
861  // Journal Logger
862  if (facility == SYSTEMD_JOURNAL_FACILITY)
863  {
864  logger = JournalLogger::create(lock2.mutex());
865 
866  ClientList *clients = logRevClientMap.value(logger);
867 
868  if (clients)
869  clients->insert(0, clientId);
870 
871  if (logger && loggers)
872  loggers->insert(0, logger);
873  }
874 #endif
875 #endif
876 
877  // DatabaseLogger from table
878  QString table = item->table();
879  if (!table.isEmpty())
880  {
881  logger = DatabaseLogger::create(table, lock2.mutex());
882 
883  ClientList *clients = logRevClientMap.value(logger);
884 
885  if (clients)
886  clients->insert(0, clientId);
887 
888  if (logger && loggers)
889  loggers->insert(0, logger);
890  }
891 
892  logItem = new LoggerListItem;
893  loggingGetTimeStamp(&logItem->epoch, nullptr);
894  logItem->list = loggers;
895  logClientMap.insert(clientId, logItem);
896 
897  item->DecrRef();
898  }
899 
900  if (logItem && logItem->list && !logItem->list->isEmpty())
901  {
902  LoggerList::iterator it = logItem->list->begin();
903  LoggingItem *item = LoggingItem::create(json);
904  if (!item)
905  return;
906  for (; it != logItem->list->end(); ++it)
907  {
908  (*it)->logmsg(item);
909  }
910  item->DecrRef();
911  }
912 }
913 
916 {
917  m_aborted = true;
918 }
919 
920 bool logForwardStart(void)
921 {
924 
925  usleep(10000);
927 }
928 
929 void logForwardStop(void)
930 {
931  if (!logForwardThread)
932  return;
933 
935  delete logForwardThread;
936  logForwardThread = nullptr;
937 
938  QMutexLocker locker(&loggerMapMutex);
939  for (auto it = loggerMap.begin(); it != loggerMap.end(); ++it)
940  {
941  it.value()->stopDatabaseAccess();
942  }
943 }
944 
945 void logForwardMessage(const QList<QByteArray> &msg)
946 {
947  LogMessage *message = new LogMessage(msg);
948  QMutexLocker lock(&logMsgListMutex);
949 
950  bool wasEmpty = logMsgList.isEmpty();
951  logMsgList.append(message);
952 
953  if (wasEmpty)
954  logMsgListNotEmpty.wakeAll();
955 }
956 
957 /*
958  * vim:ts=4:sw=4:ai:et:si:sts=4
959  */
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:782
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:294
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)
Add a single binding.
Definition: mythdbcon.cpp:863
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:136
#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
LogForwardThread * logForwardThread
static ClientMap logClientMap
int level
Definition: logging.h:72
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
QMap< QString, LoggerListItem * > ClientMap
const char * rawFunction() const
Definition: logging.h:135
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.
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:286
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:62
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:66
QList< LogMessage * > LogMessageList
static LogMessageList logMsgList
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:74
QString logFile
Definition: logging.h:80
FileLogger(const char *filename)
FileLogger constructor.
void logForwardMessage(const QList< QByteArray > &msg)
virtual int IncrRef(void)
Increments reference count.
uint usec
Definition: logging.h:69
qlonglong tid
Definition: logging.h:67
bool logForwardStart(void)
static FileLogger * create(const QString &filename, QMutex *mutex)
QSqlError lastError(void) const
Definition: mythdbcon.h:202
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.
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:70
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.
#define PREFIX64
Definition: compat.h:393
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: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.
~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:73
const char * rawFile() const
Definition: logging.h:134
void stopDatabaseAccess(void) override
Stop logging to the database and wait for the thread to stop.
const char * rawAppName() const
Definition: logging.h:137
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:76
friend class DBLoggerThread
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:807
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:140
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
QString message
Definition: logging.h:81
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:202
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:244
void logForwardStop(void)
static QAtomicInt logClientCount
char shortname
Definition: verbosedefs.h:214
QString appName
Definition: logging.h:78
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
QString file
Definition: logging.h:75
~FileLogger()
FileLogger deconstructor - close the logfile.
QString threadName
Definition: logging.h:77
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:553
LogForwardThread()
LogForwardThread constructor.
#define TIMESTAMP_MAX
QString table
Definition: logging.h:79