MythTV  0.28pre
logging.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 <QVariantMap>
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 "mythdirs.h"
23 #include "mythcorecontext.h"
24 #include "mythsystemlegacy.h"
25 #include "mythsignalingtimer.h"
26 #include "dbutil.h"
27 #include "exitcodes.h"
28 #include "compat.h"
29 
30 #define SYSLOG_NAMES
31 #ifndef _WIN32
32 #include <syslog.h>
33 #endif
34 #include <stdarg.h>
35 #include <string.h>
36 #include <sys/stat.h>
37 #include <sys/types.h>
38 #include <stdlib.h>
39 #include <fcntl.h>
40 #include <stdio.h>
41 #include <unistd.h>
42 #if HAVE_GETTIMEOFDAY
43 #include <sys/time.h>
44 #endif
45 #include <signal.h>
46 
47 // Various ways to get to thread's tid
48 #if defined(linux)
49 #include <sys/syscall.h>
50 #elif defined(__FreeBSD__)
51 extern "C" {
52 #include <sys/ucontext.h>
53 #include <sys/thr.h>
54 }
55 #elif CONFIG_DARWIN
56 #include <mach/mach.h>
57 #endif
58 
59 #ifndef NOLOGSERVER
60 // nzmqt
61 #include "nzmqt.hpp"
62 #endif
63 
64 // QJson
65 #include "qjsonwrapper/Json.h"
66 
67 #ifdef Q_OS_ANDROID
68 #include <android/log.h>
69 #endif
70 
71 static QMutex logQueueMutex;
72 static QQueue<LoggingItem *> logQueue;
73 static QRegExp logRegExp = QRegExp("[%]{1,2}");
74 
75 static LoggerThread *logThread = NULL;
76 static QMutex logThreadMutex;
77 static QHash<uint64_t, char *> logThreadHash;
78 
79 static QMutex logThreadTidMutex;
80 static QHash<uint64_t, int64_t> logThreadTidHash;
81 
82 static bool logThreadFinished = false;
83 static bool debugRegistration = false;
84 
85 typedef struct {
86  bool propagate;
87  int quiet;
88  int facility;
89  bool dblog;
90  QString path;
91  bool noserver;
93 
96 QStringList logPropagateArgList;
97 
98 #define TIMESTAMP_MAX 30
99 #define MAX_STRING_LENGTH (LOGLINE_MAX+120)
100 
101 LogLevel_t logLevel = (LogLevel_t)LOG_INFO;
102 
103 bool verboseInitialized = false;
106 
109 
110 const uint64_t verboseDefaultInt = VB_GENERAL;
111 const char *verboseDefaultStr = " general";
112 
114 QString verboseString = QString(verboseDefaultStr);
116 
120 
121 void verboseAdd(uint64_t mask, QString name, bool additive, QString helptext);
122 void loglevelAdd(int value, QString name, char shortname);
123 void verboseInit(void);
124 void verboseHelp(void);
125 
126 void loggingGetTimeStamp(qlonglong *epoch, uint *usec)
127 {
128 #if HAVE_GETTIMEOFDAY
129  struct timeval tv;
130  gettimeofday(&tv, NULL);
131  *epoch = tv.tv_sec;
132  if (usec)
133  *usec = tv.tv_usec;
134 #else
135  /* Stupid system has no gettimeofday, use less precise QDateTime */
136  QDateTime date = MythDate::current();
137  *epoch = date.toTime_t();
138  if (usec)
139  {
140  QTime time = date.time();
141  *usec = time.msec() * 1000;
142  }
143 #endif
144 }
145 
147  ReferenceCounter("LoggingItem", false),
148  m_pid(-1), m_tid(-1), m_threadId(-1), m_usec(0), m_line(0),
149  m_type(kMessage), m_level((LogLevel_t)LOG_INFO), m_facility(0), m_epoch(0),
150  m_file(NULL), m_function(NULL), m_threadName(NULL), m_appName(NULL),
151  m_table(NULL), m_logFile(NULL)
152 {
153  m_message[0]='\0';
154  m_message[LOGLINE_MAX]='\0';
155 }
156 
157 LoggingItem::LoggingItem(const char *_file, const char *_function,
158  int _line, LogLevel_t _level, LoggingType _type) :
159  ReferenceCounter("LoggingItem", false), m_pid(-1),
160  m_threadId((uint64_t)(QThread::currentThreadId())),
161  m_line(_line), m_type(_type), m_level(_level), m_facility(0),
162  m_file(strdup(_file)), m_function(strdup(_function)),
163  m_threadName(NULL), m_appName(NULL), m_table(NULL), m_logFile(NULL)
164 {
166 
167  m_message[0]='\0';
168  m_message[LOGLINE_MAX]='\0';
169  setThreadTid();
170 }
171 
173 {
174  free(m_file);
175 
176  free(m_function);
177 
178  free(m_threadName);
179 
180  free(m_appName);
181 
182  free(m_table);
183 
184  free(m_logFile);
185 }
186 
187 QByteArray LoggingItem::toByteArray(void)
188 {
189  QVariantMap variant = QJsonWrapper::qobject2qvariant(this);
190  QByteArray json = QJsonWrapper::toJson(variant);
191 
192  //cout << json.constData() << endl;
193 
194  return json;
195 }
196 
200 {
201  static const char *unknown = "thread_unknown";
202 
203  if( m_threadName )
204  return m_threadName;
205 
206  QMutexLocker locker(&logThreadMutex);
207  return logThreadHash.value(m_threadId, (char *)unknown);
208 }
209 
216 {
217  QMutexLocker locker(&logThreadTidMutex);
218  m_tid = logThreadTidHash.value(m_threadId, 0);
219  return m_tid;
220 }
221 
229 {
230  QMutexLocker locker(&logThreadTidMutex);
231 
232  m_tid = logThreadTidHash.value(m_threadId, -1);
233  if (m_tid == -1)
234  {
235  m_tid = 0;
236 
237 #if defined(Q_OS_ANDROID)
238  m_tid = (int64_t)gettid();
239 #elif defined(linux)
240  m_tid = (int64_t)syscall(SYS_gettid);
241 #elif defined(__FreeBSD__)
242  long lwpid;
243  int dummy = thr_self( &lwpid );
244  (void)dummy;
245  m_tid = (int64_t)lwpid;
246 #elif CONFIG_DARWIN
247  m_tid = (int64_t)mach_thread_self();
248 #endif
250  }
251 }
252 
257  QString table, int facility, bool noserver) :
258  MThread("Logger"),
259  m_waitNotEmpty(new QWaitCondition()),
260  m_waitEmpty(new QWaitCondition()),
261  m_aborted(false), m_initialWaiting(true),
262  m_filename(filename), m_progress(progress),
263  m_quiet(quiet), m_appname(QCoreApplication::applicationName()),
264  m_tablename(table), m_facility(facility), m_pid(getpid()), m_epoch(0),
265  m_zmqContext(NULL), m_zmqSocket(NULL), m_initialTimer(NULL),
266  m_heartbeatTimer(NULL), m_noserver(noserver)
267 {
268  char *debug = getenv("VERBOSE_THREADS");
269  if (debug != NULL)
270  {
271  LOG(VB_GENERAL, LOG_NOTICE,
272  "Logging thread registration/deregistration enabled!");
273  debugRegistration = true;
274  }
275  m_locallogs = (m_appname == MYTH_APPNAME_MYTHLOGSERVER);
276 
277 #ifdef NOLOGSERVER
278  if (!m_noserver && !logServerStart())
279  {
280  LOG(VB_GENERAL, LOG_ERR,
281  "Failed to start LogServer thread");
282  }
283 #endif
284  moveToThread(qthread());
285 }
286 
289 {
290  stop();
291  wait();
292 
293 #ifdef NOLOGSERVER
294  if (!m_noserver)
295  {
296  logServerStop();
297  }
298 #endif
299  delete m_waitNotEmpty;
300  delete m_waitEmpty;
301 }
302 
308 {
309  RunProlog();
310 
311  logThreadFinished = false;
312 
313  LOG(VB_GENERAL, LOG_INFO, "Added logging to the console");
314 
315  bool dieNow = false;
316 
317  if (!m_noserver)
318  {
319 #ifndef NOLOGSERVER
320  try
321  {
322  if (m_locallogs)
323  {
324  logServerWait();
326  }
327  else
328  {
329  m_zmqContext = nzmqt::createDefaultContext(NULL);
330  m_zmqContext->start();
331  }
332 
333  if (!m_zmqContext)
334  {
335  m_aborted = true;
336  dieNow = true;
337  }
338  else
339  {
340  qRegisterMetaType<QList<QByteArray> >("QList<QByteArray>");
341 
342  m_zmqSocket =
343  m_zmqContext->createSocket(nzmqt::ZMQSocket::TYP_DEALER, this);
344  connect(m_zmqSocket,
345  SIGNAL(messageReceived(const QList<QByteArray>&)),
346  SLOT(messageReceived(const QList<QByteArray>&)),
347  Qt::QueuedConnection);
348 
349  if (m_locallogs)
350  m_zmqSocket->connectTo("inproc://mylogs");
351  else
352  m_zmqSocket->connectTo("tcp://127.0.0.1:35327");
353  }
354  }
355  catch (nzmqt::ZMQException &e)
356  {
357  cerr << "Exception during logging socket setup: " << e.what() << endl;
358  m_aborted = true;
359  dieNow = true;
360  }
361 
362  if (!m_aborted)
363  {
364  if (!m_locallogs)
365  {
366  m_initialWaiting = true;
367  pingLogServer();
368 
369  // wait up to 150ms for mythlogserver to respond
371  SLOT(initialTimeout()));
372  m_initialTimer->start(150);
373  }
374  else
375  LOG(VB_GENERAL, LOG_INFO, "Added logging to mythlogserver locally");
376 
378 
380  m_heartbeatTimer->start(1000);
381  }
382  #else
383  logServerWait();
384  #endif
385  }
386 
387  QMutexLocker qLock(&logQueueMutex);
388 
389  while (!m_aborted || !logQueue.isEmpty())
390  {
391  qLock.unlock();
392  qApp->processEvents(QEventLoop::AllEvents, 10);
393  qApp->sendPostedEvents(NULL, QEvent::DeferredDelete);
394 
395  qLock.relock();
396  if (logQueue.isEmpty())
397  {
398  m_waitEmpty->wakeAll();
399  m_waitNotEmpty->wait(qLock.mutex(), 100);
400  continue;
401  }
402 
403  LoggingItem *item = logQueue.dequeue();
404  qLock.unlock();
405 
406  fillItem(item);
407  handleItem(item);
408  logConsole(item);
409  item->DecrRef();
410 
411  qLock.relock();
412  }
413 
414  qLock.unlock();
415 
416  // This must be before the timer stop below or we deadlock when the timer
417  // thread tries to deregister, and we wait for it.
418  logThreadFinished = true;
419 
420 #ifndef NOLOGSERVER
421  if (m_initialTimer)
422  {
423  m_initialTimer->stop();
424  delete m_initialTimer;
425  m_initialTimer = NULL;
426  }
427 
428  if (m_heartbeatTimer)
429  {
431  delete m_heartbeatTimer;
432  m_heartbeatTimer = NULL;
433  }
434 
435  if (m_zmqSocket)
436  {
437  m_zmqSocket->setLinger(0);
438  m_zmqSocket->close();
439  }
440 
441  if (!m_locallogs)
442  delete m_zmqContext;
443 #endif
444 
445  RunEpilog();
446 
447  if (dieNow)
448  {
449  qApp->processEvents();
450  }
451 }
452 
456 {
457 #ifndef NOLOGSERVER
458  if (m_initialTimer)
459  {
460  m_initialTimer->stop();
461  delete m_initialTimer;
462  m_initialTimer = NULL;
463  }
464 
465  if (m_initialWaiting)
466  {
467  // Got no response from mythlogserver, let's assume it's dead and
468  // start it up
469  launchLogServer();
470  }
471 
472  LOG(VB_GENERAL, LOG_INFO, "Added logging to mythlogserver at TCP:35327");
473 #endif
474 }
475 
479 {
480 #ifndef NOLOGSERVER
481  static bool launched = false;
482  qlonglong epoch;
483 
484  loggingGetTimeStamp(&epoch, NULL);
485  qlonglong age = (epoch - m_epoch) % 30;
486 
487  if (age == 5)
488  {
489  if (!launched)
490  {
491  launchLogServer();
492  launched = true;
493  }
494  }
495  else
496  {
497  launched = false;
498  }
499 #endif
500 }
501 
504 {
505 #ifndef NOLOGSERVER
506  // cout << "pong" << endl;
507  m_zmqSocket->sendMessage(QByteArray(""));
508 #endif
509 }
510 
513 {
514 #ifndef NOLOGSERVER
515  m_initialWaiting = false;
516  if (!m_locallogs)
517  {
518  LOG(VB_GENERAL, LOG_INFO, "Starting mythlogserver");
519 
522  kMSRunShell);
523  QStringList args;
524  args << "--daemon" << logPropagateArgs;
525 
526  MythSystemLegacy ms(GetAppBinDir() + "mythlogserver", args, mask);
527  ms.Run();
528  ms.Wait(0);
529  }
530 #endif
531 }
532 
542 void LoggerThread::messageReceived(const QList<QByteArray> &msg)
543 {
544  m_initialWaiting = false;
545  // cout << "ping" << endl;
547  pingLogServer();
548 }
549 
550 
558 {
559  if (item->m_type & kRegistering)
560  {
561  item->m_tid = item->getThreadTid();
562 
563  QMutexLocker locker(&logThreadMutex);
564  if (logThreadHash.contains(item->m_threadId))
565  {
566  char *threadName = logThreadHash.take(item->m_threadId);
567  free(threadName);
568  }
569  logThreadHash[item->m_threadId] = strdup(item->m_threadName);
570 
571  if (debugRegistration)
572  {
573  snprintf(item->m_message, LOGLINE_MAX,
574  "Thread 0x%" PREFIX64 "X (%" PREFIX64
575  "d) registered as \'%s\'",
576  (long long unsigned int)item->m_threadId,
577  (long long int)item->m_tid,
578  logThreadHash[item->m_threadId]);
579  }
580  }
581  else if (item->m_type & kDeregistering)
582  {
583  int64_t tid = 0;
584 
585  {
586  QMutexLocker locker(&logThreadTidMutex);
587  if( logThreadTidHash.contains(item->m_threadId) )
588  {
589  tid = logThreadTidHash[item->m_threadId];
590  logThreadTidHash.remove(item->m_threadId);
591  }
592  }
593 
594  QMutexLocker locker(&logThreadMutex);
595  if (logThreadHash.contains(item->m_threadId))
596  {
597  if (debugRegistration)
598  {
599  snprintf(item->m_message, LOGLINE_MAX,
600  "Thread 0x%" PREFIX64 "X (%" PREFIX64
601  "d) deregistered as \'%s\'",
602  (long long unsigned int)item->m_threadId,
603  (long long int)tid,
604  logThreadHash[item->m_threadId]);
605  }
606  char *threadName = logThreadHash.take(item->m_threadId);
607  free(threadName);
608  }
609  }
610 
611  if (m_noserver)
612  {
613  return;
614  }
615 
616  if (item->m_message[0] != '\0')
617  {
618 #ifndef NOLOGSERVER
619  // Send it to mythlogserver
621  m_zmqSocket->sendMessage(item->toByteArray());
622 #else
623  if (logServerThread)
624  {
625  QList<QByteArray> list;
626  list.append(QByteArray());
627  list.append(item->toByteArray());
629  }
630 #endif
631  }
632 }
633 
637 {
638  char line[MAX_STRING_LENGTH];
639  char usPart[9];
640  char timestamp[TIMESTAMP_MAX];
641 
642  if (m_quiet || (m_progress && item->m_level > LOG_ERR))
643  return false;
644 
645  if (!(item->m_type & kMessage))
646  return false;
647 
648  item->IncrRef();
649 
650  if (item->m_type & kStandardIO)
651  snprintf( line, MAX_STRING_LENGTH, "%s", item->m_message );
652  else
653  {
654  time_t epoch = item->epoch();
655  struct tm tm;
656  localtime_r(&epoch, &tm);
657 
658  strftime( timestamp, TIMESTAMP_MAX-8, "%Y-%m-%d %H:%M:%S",
659  (const struct tm *)&tm );
660  snprintf( usPart, 9, ".%06d", (int)(item->m_usec) );
661  strcat( timestamp, usPart );
662  char shortname;
663 
664  {
665  QMutexLocker locker(&loglevelMapMutex);
666  LoglevelDef *lev = loglevelMap.value(item->m_level, NULL);
667  if (!lev)
668  shortname = '-';
669  else
670  shortname = lev->shortname;
671  }
672 
673  snprintf( line, MAX_STRING_LENGTH, "%s %c %s\n", timestamp,
674  shortname, item->m_message );
675  }
676 
677 #ifdef Q_OS_ANDROID
678  __android_log_print(ANDROID_LOG_INFO, "mfe", line);
679 #else
680  int result = write( 1, line, strlen(line) );
681  (void)result;
682 #endif
683 
684  item->DecrRef();
685 
686  return true;
687 }
688 
689 
693 {
694  logQueueMutex.lock();
695  flush(1000);
696  m_aborted = true;
697  logQueueMutex.unlock();
698  m_waitNotEmpty->wakeAll();
699 }
700 
704 bool LoggerThread::flush(int timeoutMS)
705 {
706  QTime t;
707  t.start();
708  while (!m_aborted && !logQueue.isEmpty() && t.elapsed() < timeoutMS)
709  {
710  m_waitNotEmpty->wakeAll();
711  int left = timeoutMS - t.elapsed();
712  if (left > 0)
713  m_waitEmpty->wait(&logQueueMutex, left);
714  }
715  return logQueue.isEmpty();
716 }
717 
719 {
720  if (!item)
721  return;
722 
723  item->setPid(m_pid);
724  item->setThreadName(item->getThreadName());
725  item->setAppName(m_appname);
726  item->setTable(m_tablename);
727  item->setLogFile(m_filename);
728  item->setFacility(m_facility);
729 }
730 
731 
739 LoggingItem *LoggingItem::create(const char *_file,
740  const char *_function,
741  int _line, LogLevel_t _level,
742  LoggingType _type)
743 {
744  LoggingItem *item = new LoggingItem(_file, _function, _line, _level, _type);
745 
746  return item;
747 }
748 
750 {
751  // Deserialize buffer
752  QVariant variant = QJsonWrapper::parseJson(buf);
753 
754  LoggingItem *item = new LoggingItem;
755  QJsonWrapper::qvariant2qobject(variant.toMap(), item);
756 
757  return item;
758 }
759 
760 
772 void LogPrintLine( uint64_t mask, LogLevel_t level, const char *file, int line,
773  const char *function, int fromQString,
774  const char *format, ... )
775 {
776  va_list arguments;
777 
778  int type = kMessage;
779  type |= (mask & VB_FLUSH) ? kFlush : 0;
780  type |= (mask & VB_STDIO) ? kStandardIO : 0;
781  LoggingItem *item = LoggingItem::create(file, function, line, level,
782  (LoggingType)type);
783  if (!item)
784  return;
785 
786  char *formatcopy = NULL;
787  if( fromQString && strchr(format, '%') )
788  {
789  QString string(format);
790  format = strdup(string.replace(logRegExp, "%%").toLocal8Bit()
791  .constData());
792  formatcopy = (char *)format;
793  }
794 
795  va_start(arguments, format);
796  vsnprintf(item->m_message, LOGLINE_MAX, format, arguments);
797  va_end(arguments);
798 
799  if (formatcopy)
800  free(formatcopy);
801 
802  QMutexLocker qLock(&logQueueMutex);
803 
804 #if defined( _MSC_VER ) && defined( _DEBUG )
805  OutputDebugStringA( item->m_message );
806  OutputDebugStringA( "\n" );
807 #endif
808 
809  logQueue.enqueue(item);
810 
811  if (logThread && logThreadFinished && !logThread->isRunning())
812  {
813  while (!logQueue.isEmpty())
814  {
815  item = logQueue.dequeue();
816  qLock.unlock();
817  logThread->handleItem(item);
818  logThread->logConsole(item);
819  item->DecrRef();
820  qLock.relock();
821  }
822  }
823  else if (logThread && !logThreadFinished && (type & kFlush))
824  {
825  logThread->flush();
826  }
827 }
828 
829 
834 {
835  logPropagateArgList.clear();
836 
837  QString mask = verboseString.trimmed();
838  mask.replace(QRegExp(" "), ",");
839  mask.remove(QRegExp("^,"));
840  logPropagateArgs = " --verbose " + mask;
841  logPropagateArgList << "--verbose" << mask;
842 
843  if (logPropagateOpts.propagate)
844  {
845  logPropagateArgs += " --logpath " + logPropagateOpts.path;
846  logPropagateArgList << "--logpath" << logPropagateOpts.path;
847  }
848 
849  QString name = logLevelGetName(logLevel);
850  logPropagateArgs += " --loglevel " + name;
851  logPropagateArgList << "--loglevel" << name;
852 
853  for (int i = 0; i < logPropagateOpts.quiet; i++)
854  {
855  logPropagateArgs += " --quiet";
856  logPropagateArgList << "--quiet";
857  }
858 
859  if (logPropagateOpts.dblog)
860  {
861  logPropagateArgs += " --enable-dblog";
862  logPropagateArgList << "--enable-dblog";
863  }
864 
865 #if !defined(_WIN32) && !defined(Q_OS_ANDROID)
866  if (logPropagateOpts.facility >= 0)
867  {
868  const CODE *syslogname;
869 
870  for (syslogname = &facilitynames[0];
871  (syslogname->c_name &&
872  syslogname->c_val != logPropagateOpts.facility); syslogname++);
873 
874  logPropagateArgs += QString(" --syslog %1").arg(syslogname->c_name);
875  logPropagateArgList << "--syslog" << syslogname->c_name;
876  }
877 #endif
878 
879  if (logPropagateOpts.noserver)
880  {
881  logPropagateArgs += " --disable-mythlogserver";
882  logPropagateArgList << "--disable-mythlogserver";
883  }
884 }
885 
889 {
890  return logPropagateOpts.quiet;
891 }
892 
896 {
897  return logPropagateOpts.noserver;
898 }
899 
912 void logStart(QString logfile, int progress, int quiet, int facility,
913  LogLevel_t level, bool dblog, bool propagate, bool noserver)
914 {
915  if (logThread && logThread->isRunning())
916  return;
917 
918  logLevel = level;
919  LOG(VB_GENERAL, LOG_NOTICE, QString("Setting Log Level to LOG_%1")
920  .arg(logLevelGetName(logLevel).toUpper()));
921 
922  logPropagateOpts.propagate = propagate;
923  logPropagateOpts.quiet = quiet;
924  logPropagateOpts.facility = facility;
925  logPropagateOpts.dblog = dblog;
926  logPropagateOpts.noserver = noserver;
927 
928  if (propagate)
929  {
930  QFileInfo finfo(logfile);
931  QString path = finfo.path();
932  logPropagateOpts.path = path;
933  }
934 
936 
937  QString table = dblog ? QString("logging") : QString("");
938 
939  if (!logThread)
940  logThread = new LoggerThread(logfile, progress, quiet, table, facility, noserver);
941 
942  logThread->start();
943 }
944 
946 void logStop(void)
947 {
948  if (logThread)
949  {
950  logThread->stop();
951  logThread->wait();
952  delete logThread;
953  logThread = NULL;
954  }
955 }
956 
961 void loggingRegisterThread(const QString &name)
962 {
963  if (logThreadFinished)
964  return;
965 
966  QMutexLocker qLock(&logQueueMutex);
967 
968  LoggingItem *item = LoggingItem::create(__FILE__, __FUNCTION__,
969  __LINE__, (LogLevel_t)LOG_DEBUG,
970  kRegistering);
971  if (item)
972  {
973  item->setThreadName((char *)name.toLocal8Bit().constData());
974  logQueue.enqueue(item);
975  }
976 }
977 
981 {
982  if (logThreadFinished)
983  return;
984 
985  QMutexLocker qLock(&logQueueMutex);
986 
987  LoggingItem *item = LoggingItem::create(__FILE__, __FUNCTION__, __LINE__,
988  (LogLevel_t)LOG_DEBUG,
990  if (item)
991  logQueue.enqueue(item);
992 }
993 
994 
998 int syslogGetFacility(QString facility)
999 {
1000 #ifdef _WIN32
1001  LOG(VB_GENERAL, LOG_NOTICE,
1002  "Windows does not support syslog, disabling" );
1003  return( -2 );
1004 #elif defined(Q_OS_ANDROID)
1005  LOG(VB_GENERAL, LOG_NOTICE,
1006  "Android does not support syslog, disabling" );
1007  return( -2 );
1008 #elif defined(Q_OS_ANDROID)
1009  LOG(VB_GENERAL, LOG_NOTICE,
1010  "Android does not support syslog, disabling" );
1011  return( -2 );
1012 #else
1013  const CODE *name;
1014  int i;
1015  QByteArray ba = facility.toLocal8Bit();
1016  char *string = (char *)ba.constData();
1017 
1018  for (i = 0, name = &facilitynames[0];
1019  name->c_name && strcmp(name->c_name, string); i++, name++);
1020 
1021  return( name->c_val );
1022 #endif
1023 }
1024 
1028 LogLevel_t logLevelGet(QString level)
1029 {
1030  QMutexLocker locker(&loglevelMapMutex);
1031  if (!verboseInitialized)
1032  {
1033  locker.unlock();
1034  verboseInit();
1035  locker.relock();
1036  }
1037 
1038  for (LoglevelMap::iterator it = loglevelMap.begin();
1039  it != loglevelMap.end(); ++it)
1040  {
1041  LoglevelDef *item = (*it);
1042  if ( item->name == level.toLower() )
1043  return (LogLevel_t)item->value;
1044  }
1045 
1046  return LOG_UNKNOWN;
1047 }
1048 
1052 QString logLevelGetName(LogLevel_t level)
1053 {
1054  QMutexLocker locker(&loglevelMapMutex);
1055  if (!verboseInitialized)
1056  {
1057  locker.unlock();
1058  verboseInit();
1059  locker.relock();
1060  }
1061  LoglevelMap::iterator it = loglevelMap.find((int)level);
1062 
1063  if ( it == loglevelMap.end() )
1064  return QString("unknown");
1065 
1066  return (*it)->name;
1067 }
1068 
1075 void verboseAdd(uint64_t mask, QString name, bool additive, QString helptext)
1076 {
1077  VerboseDef *item = new VerboseDef;
1078 
1079  item->mask = mask;
1080  name.detach();
1081  // VB_GENERAL -> general
1082  name.remove(0, 3);
1083  name = name.toLower();
1084  item->name = name;
1085  item->additive = additive;
1086  helptext.detach();
1087  item->helpText = helptext;
1088 
1089  verboseMap.insert(name, item);
1090 }
1091 
1097 void loglevelAdd(int value, QString name, char shortname)
1098 {
1099  LoglevelDef *item = new LoglevelDef;
1100 
1101  item->value = value;
1102  name.detach();
1103  // LOG_CRIT -> crit
1104  name.remove(0, 4);
1105  name = name.toLower();
1106  item->name = name;
1107  item->shortname = shortname;
1108 
1109  loglevelMap.insert(value, item);
1110 }
1111 
1113 void verboseInit(void)
1114 {
1115  QMutexLocker locker(&verboseMapMutex);
1116  QMutexLocker locker2(&loglevelMapMutex);
1117  verboseMap.clear();
1118  loglevelMap.clear();
1119 
1120  // This looks funky, so I'll put some explanation here. The verbosedefs.h
1121  // file gets included as part of the mythlogging.h include, and at that
1122  // time, the normal (without _IMPLEMENT_VERBOSE defined) code case will
1123  // define the VerboseMask enum. At this point, we force it to allow us
1124  // to include the file again, but with _IMPLEMENT_VERBOSE set so that the
1125  // single definition of the VB_* values can be shared to define also the
1126  // contents of verboseMap, via repeated calls to verboseAdd()
1127 
1128 #undef VERBOSEDEFS_H_
1129 #define _IMPLEMENT_VERBOSE
1130 #include "verbosedefs.h"
1131 
1132  verboseInitialized = true;
1133 }
1134 
1135 
1138 void verboseHelp(void)
1139 {
1140  QString m_verbose = userDefaultValueStr.trimmed();
1141  m_verbose.replace(QRegExp(" "), ",");
1142  m_verbose.remove(QRegExp("^,"));
1143 
1144  cerr << "Verbose debug levels.\n"
1145  "Accepts any combination (separated by comma) of:\n\n";
1146 
1147  for (VerboseMap::Iterator vit = verboseMap.begin();
1148  vit != verboseMap.end(); ++vit )
1149  {
1150  VerboseDef *item = vit.value();
1151  QString name = QString(" %1").arg(item->name, -15, ' ');
1152  if (item->helpText.isEmpty())
1153  continue;
1154  cerr << name.toLocal8Bit().constData() << " - " <<
1155  item->helpText.toLocal8Bit().constData() << endl;
1156  }
1157 
1158  cerr << endl <<
1159  "The default for this program appears to be: '-v " <<
1160  m_verbose.toLocal8Bit().constData() << "'\n\n"
1161  "Most options are additive except for 'none' and 'all'.\n"
1162  "These two are semi-exclusive and take precedence over any\n"
1163  "other options. However, you may use something like\n"
1164  "'-v none,jobqueue' to receive only JobQueue related messages\n"
1165  "and override the default verbosity level.\n\n"
1166  "Additive options may also be subtracted from 'all' by\n"
1167  "prefixing them with 'no', so you may use '-v all,nodatabase'\n"
1168  "to view all but database debug messages.\n\n";
1169 
1170  cerr << "The 'global' loglevel is specified with --loglevel, but can be\n"
1171  << "overridden on a component by component basis by appending "
1172  << "':level'\n"
1173  << "to the component.\n"
1174  << " For example: -v gui:debug,channel:notice,record\n\n";
1175 
1176  cerr << "Some debug levels may not apply to this program.\n" << endl;
1177 }
1178 
1182 int verboseArgParse(QString arg)
1183 {
1184  QString option;
1185  int idx;
1186 
1187  if (!verboseInitialized)
1188  verboseInit();
1189 
1190  QMutexLocker locker(&verboseMapMutex);
1191 
1193  verboseString = QString(verboseDefaultStr);
1194 
1195  if (arg.startsWith('-'))
1196  {
1197  cerr << "Invalid or missing argument to -v/--verbose option\n";
1198  return GENERIC_EXIT_INVALID_CMDLINE;
1199  }
1200 
1201  QStringList verboseOpts = arg.split(QRegExp("[^\\w:]+",
1202  Qt::CaseInsensitive,
1203  QRegExp::RegExp2));
1204  for (QStringList::Iterator it = verboseOpts.begin();
1205  it != verboseOpts.end(); ++it )
1206  {
1207  option = (*it).toLower();
1208  bool reverseOption = false;
1209  QString optionLevel;
1210 
1211  if (option != "none" && option.startsWith("no"))
1212  {
1213  reverseOption = true;
1214  option = option.right(option.length() - 2);
1215  }
1216 
1217  if (option == "help")
1218  {
1219  verboseHelp();
1220  return GENERIC_EXIT_INVALID_CMDLINE;
1221  }
1222  else if (option == "important")
1223  {
1224  cerr << "The \"important\" log mask is no longer valid.\n";
1225  }
1226  else if (option == "extra")
1227  {
1228  cerr << "The \"extra\" log mask is no longer valid. Please try "
1229  "--loglevel debug instead.\n";
1230  }
1231  else if (option == "default")
1232  {
1234  {
1237  }
1238  else
1239  {
1241  verboseString = QString(verboseDefaultStr);
1242  }
1243  }
1244  else
1245  {
1246  if ((idx = option.indexOf(':')) != -1)
1247  {
1248  optionLevel = option.mid(idx + 1);
1249  option = option.left(idx);
1250  }
1251 
1252  VerboseDef *item = verboseMap.value(option);
1253 
1254  if (item)
1255  {
1256  if (reverseOption)
1257  {
1258  verboseMask &= ~(item->mask);
1259  verboseString = verboseString.remove(' ' + item->name);
1260  verboseString += " no" + item->name;
1261  }
1262  else
1263  {
1264  if (item->additive)
1265  {
1266  if (!(verboseMask & item->mask))
1267  {
1268  verboseMask |= item->mask;
1269  verboseString += ' ' + item->name;
1270  }
1271  }
1272  else
1273  {
1274  verboseMask = item->mask;
1275  verboseString = item->name;
1276  }
1277 
1278  if (!optionLevel.isEmpty())
1279  {
1280  LogLevel_t level = logLevelGet(optionLevel);
1281  if (level != LOG_UNKNOWN)
1282  componentLogLevel[item->mask] = level;
1283  }
1284  }
1285  }
1286  else
1287  {
1288  cerr << "Unknown argument for -v/--verbose: " <<
1289  option.toLocal8Bit().constData() << endl;;
1290  return GENERIC_EXIT_INVALID_CMDLINE;
1291  }
1292  }
1293  }
1294 
1295  if (!haveUserDefaultValues)
1296  {
1297  haveUserDefaultValues = true;
1300  }
1301 
1302  return GENERIC_EXIT_OK;
1303 }
1304 
1309 QString logStrerror(int errnum)
1310 {
1311  return QString("%1 (%2)").arg(strerror(errnum)).arg(errnum);
1312 }
1313 
1314 
1315 /*
1316  * vim:ts=4:sw=4:ai:et:si:sts=4
1317  */
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:216
nzmqt::ZMQContext * getZMQContext(void)
void loglevelAdd(int value, QString name, char shortname)
Add a log level to the logLevelMap.
Definition: logging.cpp:1097
QString logfile
GLenum GLsizei const GLvoid * string
void start(QThread::Priority=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:291
QString logLevelGetName(LogLevel_t level)
Map a log level enumerated value back to the name.
Definition: logging.cpp:1052
void Run(time_t timeout=0)
Runs a command inside the /bin/sh shell. Returns immediately.
avoid disabling UI drawing
Definition: mythsystem.h:35
char * m_function
Definition: logging.h:159
char m_message[LOGLINE_MAX+1]
Definition: logging.h:164
static QQueue< LoggingItem * > logQueue
Definition: logging.cpp:72
The logging thread that consumes the logging queue and dispatches each LoggingItem to mythlogserver v...
Definition: logging.h:175
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:46
void logStart(QString logfile, int progress, int quiet, int facility, LogLevel_t level, bool dblog, bool propagate, bool noserver)
Entry point to start logging for the application.
Definition: logging.cpp:912
void receivedMessage(const QList< QByteArray > &)
Handles messages received from logging clients.
virtual void start(int msec)
void LogPrintLine(uint64_t mask, LogLevel_t level, const char *file, int line, const char *function, int fromQString, const char *format,...)
Format and send a log message into the queue.
Definition: logging.cpp:772
VERBOSE_PREAMBLE false
Definition: verbosedefs.h:83
const char * verboseDefaultStr
Definition: logging.cpp:111
QString m_tablename
Cached table name for db logging.
Definition: logging.h:205
char * m_file
Definition: logging.h:158
QString name
Definition: verbosedefs.h:211
char * getThreadName(void)
Get the name of the thread that produced the LoggingItem.
Definition: logging.cpp:199
QMutex verboseMapMutex
Definition: logging.cpp:105
static QMutex logQueueMutex
Definition: logging.cpp:71
int m_facility
Cached syslog facility (or -1 to disable)
Definition: logging.h:206
void checkHeartBeat(void)
Handles heartbeat checking once a second.
Definition: logging.cpp:478
static QMutex logThreadMutex
Definition: logging.cpp:76
QMap< uint64_t, LogLevel_t > ComponentLogLevelMap
Definition: verbosedefs.h:215
QString m_filename
Filename of debug logfile.
Definition: logging.h:201
bool verboseInitialized
Definition: logging.cpp:103
bool logPropagateNoServer(void)
Check if we are propagating a "--disable-mythlogserver".
Definition: logging.cpp:895
int syslogGetFacility(QString facility)
Map a syslog facility name back to the enumerated value.
Definition: logging.cpp:998
General purpose reference counter.
bool flush(int timeoutMS=200000)
Wait for the queue to be flushed (up to a timeout)
Definition: logging.cpp:704
int dummy
Definition: programinfo.cpp:46
bool wait(unsigned long time=ULONG_MAX)
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:308
void logServerStop(void)
Entry point for stopping logging for an application.
bool m_progress
show only LOG_ERR and more important (console only)
Definition: logging.h:202
QString logPropagateArgs
Definition: logging.cpp:95
void messageReceived(const QList< QByteArray > &)
Handles messages received back from mythlogserver via ZeroMQ.
Definition: logging.cpp:542
bool m_locallogs
Are we logging locally (i.e.
Definition: logging.h:208
GLint level
static __inline struct tm * localtime_r(const time_t *timep, struct tm *result)
Definition: compat.h:274
void pingLogServer(void)
Send a ping to the log server.
Definition: logging.cpp:503
volatile bool m_initialWaiting
Waiting for the initial response from mythlogserver.
Definition: logging.h:199
The logging items that are generated by LOG() and are sent to the console and to mythlogserver via Ze...
Definition: logging.h:68
const char * filename
Definition: ioapi.h:135
void fillItem(LoggingItem *item)
Definition: logging.cpp:718
unsigned int uint
Definition: compat.h:136
void loggingGetTimeStamp(qlonglong *epoch, uint *usec)
Definition: logging.cpp:126
uint64_t verboseMask
Definition: logging.cpp:113
bool logConsole(LoggingItem *item)
Process a log message, writing to the console.
Definition: logging.cpp:636
void loggingRegisterThread(const QString &name)
Register the current thread with the given name.
Definition: logging.cpp:961
bool logServerStart(void)
Entry point to start logging for the application.
QString userDefaultValueStr
Definition: logging.cpp:118
LogLevel_t logLevelGet(QString level)
Map a log level name back to the enumerated value.
Definition: logging.cpp:1028
ComponentLogLevelMap componentLogLevel
Definition: logging.cpp:115
qlonglong m_epoch
Time last heard from the server (seconds)
Definition: logging.h:210
MythSignalingTimer * m_initialTimer
Timer for the initial startup.
Definition: logging.h:216
VerboseDef
Definition: verbosedefs.h:206
LoggingType m_type
Definition: logging.h:154
voidpf void * buf
Definition: ioapi.h:136
QWaitCondition * m_waitEmpty
Condition variable for waiting for the queue to be empty Protected by logQueueMutex.
Definition: logging.h:194
LoggerThread(QString filename, bool progress, bool quiet, QString table, int facility, bool noserver)
LoggerThread constructor.
Definition: logging.cpp:256
VerboseMap verboseMap
Definition: logging.cpp:104
pid_t m_pid
Cached pid value.
Definition: logging.h:207
MythSystemMask
Definition: mythsystem.h:32
qlonglong epoch
Definition: logging.h:80
void handleItem(LoggingItem *item)
Handles each LoggingItem, generally by handing it off to mythlogserver via ZeroMQ.
Definition: logging.cpp:557
void initialTimeout(void)
Handles the initial startup timeout when waiting for the log server to show signs of life...
Definition: logging.cpp:455
void verboseAdd(uint64_t mask, QString name, bool additive, QString helptext)
Add a verbose level to the verboseMap.
Definition: logging.cpp:1075
bool isRunning(void) const
Definition: mthread.cpp:271
bool m_noserver
Definition: logging.h:219
static bool debugRegistration
Definition: logging.cpp:83
void verboseHelp(void)
Outputs the Verbose levels and their descriptions (for –verbose help)
Definition: logging.cpp:1138
LogServerThread * logServerThread
void run(void)
Run the logging thread.
Definition: logging.cpp:307
virtual int IncrRef(void)
Increments reference count.
const char * name
Definition: ParseText.cpp:338
static LoggerThread * logThread
Definition: logging.cpp:75
void stop(void)
Stop the thread by setting the abort flag after waiting a second for the queue to be flushed...
Definition: logging.cpp:692
QMap< QString, VerboseDef * > VerboseMap
Definition: verbosedefs.h:207
nzmqt::ZMQSocket * m_zmqSocket
ZeroMQ socket to talk to mythlogserver.
Definition: logging.h:213
void launchLogServer(void)
Launches the logging server daemon.
Definition: logging.cpp:512
QString GetAppBinDir(void)
Definition: mythdirs.cpp:206
run process through shell
Definition: mythsystem.h:41
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:10
unsigned char t
Definition: ParseText.cpp:339
bool logPropagateQuiet(void)
Check if we are propagating a "--quiet".
Definition: logging.cpp:888
static QHash< uint64_t, char * > logThreadHash
Definition: logging.cpp:77
QString path
Definition: logging.cpp:90
struct v4l2_mpeg_vbi_itv0_line line[35]
Definition: videodev2.h:1039
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
LoggingType
Definition: logging.h:48
VERBOSE_PREAMBLE Most debug(nodatabase, notimestamp, noextra)") VERBOSE_MAP(VB_IMPORTANT
QString logStrerror(int errnum)
Verbose helper function for ENO macro.
Definition: logging.cpp:1309
void loggingDeregisterThread(void)
Deregister the current thread's name.
Definition: logging.cpp:980
QByteArray toByteArray(void)
Definition: logging.cpp:187
static QRegExp logRegExp
Definition: logging.cpp:73
QString m_appname
Cached application name.
Definition: logging.h:204
int verboseArgParse(QString arg)
Parse the –verbose commandline argument and set the verbose level.
Definition: logging.cpp:1182
qulonglong m_threadId
Definition: logging.h:151
uint Wait(time_t timeout=0)
LogPropagateOpts logPropagateOpts
Definition: logging.cpp:94
QWaitCondition * m_waitNotEmpty
Condition variable for waiting for the queue to not be empty Protected by logQueueMutex.
Definition: logging.h:191
virtual void stop(void)
LogLevel_t m_level
Definition: logging.h:155
VERBOSE_PREAMBLE Most Errors or other very important messages true
Definition: verbosedefs.h:91
char * m_threadName
Definition: logging.h:160
LoglevelMap loglevelMap
Definition: logging.cpp:107
char * m_table
Definition: logging.h:162
int64_t getThreadTid(void)
Get the thread ID of the thread that produced the LoggingItem.
Definition: logging.cpp:215
char * m_appName
Definition: logging.h:161
LogLevel_t logLevel
Definition: logging.cpp:101
GLint GLenum GLsizei GLint GLenum format
typedef void(APIENTRY *MYTH_GLTEXIMAGE1DPROC)(GLenum target
uint64_t userDefaultValueInt
Definition: logging.cpp:117
uint m_usec
Definition: logging.h:152
void logStop(void)
Entry point for stopping logging for an application.
Definition: logging.cpp:946
This class is essentially a workaround for a Qt 4.5.2 bug where it will get stuck in the Qt event loo...
static QMutex logThreadTidMutex
Definition: logging.cpp:79
QMutex loglevelMapMutex
Definition: logging.cpp:108
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
Definition: mthread.cpp:203
bool haveUserDefaultValues
Definition: logging.cpp:119
void setThreadTid(void)
Set the thread ID of the thread that produced the LoggingItem.
Definition: logging.cpp:228
void setPid(const int val)
Definition: logging.h:119
GLint GLenum GLsizei GLint GLenum GLenum type
QThread * qthread(void)
Returns the thread, this will always return the same pointer no matter how often you restart the thre...
Definition: mthread.cpp:241
char * m_logFile
Definition: logging.h:163
void setFacility(const int val)
Definition: logging.h:126
static QHash< uint64_t, int64_t > logThreadTidHash
Definition: logging.cpp:80
def write
Definition: mythburn.py:279
char shortname
Definition: verbosedefs.h:212
void logServerWait(void)
static bool logThreadFinished
Definition: logging.cpp:82
qlonglong m_epoch
Definition: logging.h:157
int m_quiet
silence the console (console only)
Definition: logging.h:203
QMap< int, LoglevelDef * > LoglevelMap
Definition: verbosedefs.h:214
__s32 value
Definition: videodev2.h:1042
void verboseInit(void)
Initialize the logging levels and verbose levels.
Definition: logging.cpp:1113
qlonglong m_tid
Definition: logging.h:150
void logPropagateCalc(void)
Generate the logPropagateArgs global with the latest logging level, mask, etc to propagate to all of ...
Definition: logging.cpp:833
QStringList logPropagateArgList
Definition: logging.cpp:96
nzmqt::ZMQContext * m_zmqContext
ZeroMQ context to use.
Definition: logging.h:212
Definition: logging.h:52
~LoggerThread()
LoggerThread destructor. Triggers the deletion of all loggers.
Definition: logging.cpp:288
static LoggingItem * create(const char *, const char *, int, LogLevel_t, LoggingType)
Create a new LoggingItem.
Definition: logging.cpp:739
avoid blocking LIRC & Joystick Menu
Definition: mythsystem.h:34
const uint64_t verboseDefaultInt
Definition: logging.cpp:110
QString verboseString
Definition: logging.cpp:114
bool m_aborted
Flag to abort the thread.
Definition: logging.h:197
MythSignalingTimer * m_heartbeatTimer
Timer for 1s heartbeats.
Definition: logging.h:217