Go to the documentation of this file.
3 #include <QMutexLocker>
4 #include <QWaitCondition>
8 #include <QCoreApplication>
10 #include <QStringList>
12 #include <QSocketNotifier>
27 #if CONFIG_SYSTEMD_JOURNAL
28 #define SD_JOURNAL_SUPPRESS_LOCATION 1
29 #include <systemd/sd-journal.h>
35 #include <sys/types.h>
46 #include <sys/syscall.h>
47 #elif defined(__FreeBSD__)
49 #include <sys/ucontext.h>
53 #include <mach/mach.h>
110 LOG(VB_GENERAL, LOG_INFO, QString(
"Added logging to %1")
120 LOG(VB_GENERAL, LOG_INFO, QString(
"Removed logging to %1")
130 QByteArray ba =
filename.toLocal8Bit();
131 const char *
file = ba.constData();
155 m_fd = open(qPrintable(
m_handle), O_WRONLY|O_CREAT|O_APPEND, 0664);
157 LOG(VB_GENERAL, LOG_INFO, QString(
"Rolled logging on %1") .
arg(
m_handle));
173 line = qPrintable(QString(
"%1 %2 [%3/%4] %5 %6:%7 (%8) - %9\n")
174 .
arg(timestamp, shortname,
175 QString::number(item->
pid()),
176 QString::number(item->
tid()),
178 QString::number(item->
line()),
184 line = qPrintable(QString(
"%1 %2 [%3] %5 %6:%7 (%8) - %9\n")
185 .
arg(timestamp, shortname,
186 QString::number(item->
pid()),
188 QString::number(item->
line()),
193 int result =
write(
m_fd, line.data(), line.size());
197 LOG(VB_GENERAL, LOG_ERR,
198 QString(
"Closed Log output on fd %1 due to errors").
arg(
m_fd));
207 SyslogLogger::SyslogLogger(
bool open) :
214 openlog(
nullptr, LOG_NDELAY, 0 );
218 LOG(VB_GENERAL, LOG_INFO,
"Added syslogging");
222 SyslogLogger::~SyslogLogger()
224 LOG(VB_GENERAL, LOG_INFO,
"Removing syslogging");
229 SyslogLogger *SyslogLogger::create(QMutex *mutex,
bool open)
231 auto *
logger = qobject_cast<SyslogLogger *>(
loggerMap.value(
"",
nullptr));
238 logger =
new SyslogLogger(open);
251 if (!m_opened || item->
facility() <= 0)
255 syslog(item->
level() | item->
facility(),
"%s[%d]: %c %s %s:%d (%s) %s",
256 qPrintable(item->
appName()), item->
pid(), shortname,
263 #if CONFIG_SYSTEMD_JOURNAL
264 JournalLogger::JournalLogger() :
268 LOG(VB_GENERAL, LOG_INFO,
"Added journal logging");
272 JournalLogger::~JournalLogger()
274 LOG(VB_GENERAL, LOG_INFO,
"Removing journal logging");
277 JournalLogger *JournalLogger::create(QMutex *mutex)
279 auto *
logger = qobject_cast<JournalLogger *>(
loggerMap.value(
"",
nullptr));
286 logger =
new JournalLogger();
300 "MESSAGE=%s", qUtf8Printable(item->
message()),
301 "PRIORITY=%d", item->
level(),
302 "CODE_FILE=%s", qUtf8Printable(item->
file()),
303 "CODE_LINE=%d", item->
line(),
304 "CODE_FUNC=%s", qUtf8Printable(item->
function()),
305 "SYSLOG_IDENTIFIER=%s", qUtf8Printable(item->
appName()),
306 "SYSLOG_PID=%d", item->
pid(),
307 "MYTH_THREAD=%s", qUtf8Printable(item->
threadName()),
322 " (host, application, pid, tid, thread, filename, "
323 " line, function, msgtime, level, message) "
324 "VALUES (:HOST, :APP, :PID, :TID, :THREAD, :FILENAME, "
325 " :LINE, :FUNCTION, :MSGTIME, :LEVEL, :MESSAGE)")
328 LOG(VB_GENERAL, LOG_INFO, QString(
"Added database logging to table %1")
338 LOG(VB_GENERAL, LOG_INFO,
"Removing database logging");
345 QByteArray ba = table.toLocal8Bit();
346 const char *tble = ba.constData();
348 qobject_cast<DatabaseLogger *>(
loggerMap.value(table,
nullptr));
391 LOG(VB_GENERAL, LOG_CRIT,
392 "Disabling DB Logging: too many messages queued");
401 LOG(VB_GENERAL, LOG_CRIT,
"Reenabling DB Logging");
438 || !err.nativeErrorCode().isEmpty()
467 if ((db) && db->HaveValidDatabase())
488 QString sql =
"SELECT COLUMN_NAME "
489 " FROM INFORMATION_SCHEMA.COLUMNS "
490 " WHERE TABLE_SCHEMA = DATABASE() "
491 " AND TABLE_NAME = :TABLENAME "
492 " AND COLUMN_NAME = :COLUMNNAME;";
510 m_wait(new QWaitCondition())
544 m_wait->wait(locker.mutex(), 100);
560 m_wait->wait(qLock.mutex(), 100);
568 if (!item->
message().isEmpty())
577 m_wait->wait(qLock.mutex(), 100);
657 Qt::QueuedConnection);
659 qRegisterMetaType<QList<QByteArray> >(
"QList<QByteArray>");
663 qApp->processEvents(QEventLoop::AllEvents, 10);
664 qApp->sendPostedEvents(
nullptr, QEvent::DeferredDelete);
685 if ((processed & 127) == 0)
687 qApp->processEvents(QEventLoop::AllEvents, 10);
688 qApp->sendPostedEvents(
nullptr, QEvent::DeferredDelete);
703 while (!loggers.isEmpty())
717 LOG(VB_GENERAL, LOG_INFO,
"SIGHUP received, rolling log files.");
721 QMap<QString, LoggerBase *>::iterator it;
724 it.value()->reopen();
732 QList<QByteArray>::const_iterator it = msg->begin();
734 for (; it != msg->end(); ++it, i++)
736 QByteArray buf = *it;
737 cout << i <<
":\t" << buf.size() << endl <<
"\t"
738 << buf.toHex().constData() << endl <<
"\t"
739 << buf.constData() << endl;
744 QByteArray clientBa = msg->first();
745 QString clientId = QString(clientBa.toHex());
747 QByteArray json = msg->at(1);
749 if (json.size() == 0)
761 logItem->
m_itemEpoch = nowAsDuration<std::chrono::seconds>();
768 LOG(VB_FILE, LOG_DEBUG, QString(
"New Logging Client: ID: %1 (#%2)")
786 clients->insert(0, clientId);
789 loggers->insert(0,
logger);
802 clients->insert(0, clientId);
805 loggers->insert(0,
logger);
808 #if CONFIG_SYSTEMD_JOURNAL
810 if (facility == SYSTEMD_JOURNAL_FACILITY)
817 clients->insert(0, clientId);
820 loggers->insert(0,
logger);
826 QString table = item->
table();
827 if (!table.isEmpty())
834 clients->insert(0, clientId);
837 loggers->insert(0,
logger);
841 logItem->
m_itemEpoch = nowAsDuration<std::chrono::seconds>();
853 for (
auto *it : qAsConst(*logItem->
m_itemList))
886 it.value()->stopDatabaseAccess();
static QAtomicInt logClientCount
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
bool logqmsg(MSqlQuery &query, LoggingItem *item)
Actually insert a log message from the queue into the database.
QSqlQuery wrapper that fetches a DB connection from the connection pool.
QElapsedTimer m_errorLoggingTime
Elapsed time since DB error logging was last done.
bool m_opened
true when the logfile is opened
void logForwardStop(void)
QString getTimestamp(const char *format="yyyy-MM-dd HH:mm:ss") const
Convert numerical timestamp to a readable date and time.
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
static QMap< QString, LoggerBase * > loggerMap
static QMutex logClientMapMutex
~DBLoggerThread() override
DBLoggerThread deconstructor.
QList< LogMessage * > LogMessageList
Base class for the various logging mechanisms.
static DatabaseLogger * create(const QString &table, QMutex *mutex)
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
DBLoggerThread * m_thread
The database queue handling thread.
bool logmsg(LoggingItem *item) override
Process a log message, writing to the logfile.
LogForwardThread * logForwardThread
def write(text, progress=True)
static bool tableExists(const QString &table)
Checks whether table exists and is ready for writing.
arg(title).arg(filename).arg(doDelete))
bool logmsg(LoggingItem *item) override
Process a log message, queuing it for logging to the database.
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
void logForwardMessage(const QList< QByteArray > &msg)
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
bool logForwardStart(void)
~LoggerBase() override
LoggerBase Deconstructor.
DBLoggerThread(DatabaseLogger *logger)
DBLoggerThread constructor.
bool m_aborted
Flag to abort the thread.
void stopDatabaseAccess(void) override
Stop logging to the database and wait for the thread to stop.
static constexpr std::chrono::milliseconds kMinDisabledTime
Minimum time to disable DB logging.
The logging items that are generated by LOG() and are sent to the console.
QHash< LoggerBase *, ClientList * > RevClientMap
bool isDatabaseReady(void)
Check if the database is ready for use.
char getLevelChar(void)
Get the message log level as a single character.
bool m_loggingTableExists
The desired logging table exists.
QString m_query
The database query to insert log messages.
The logging thread that forwards received messages to the consuming loggers via ZeroMQ.
~LogForwardThread() override
LogForwardThread destructor.
void stop(void)
Tell the thread to stop by setting the m_aborted flag.
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
static RevClientMap logRevClientMap
static void DBError(const QString &where, const MSqlQuery &query)
static void handleSigHup(void)
SIGHUP handler - reopen all open logfiles for logrollers.
static LogMessageList logMsgList
void run(void) override
Run the log forwarding thread.
QString m_handle
semi-opaque handle for identifying instance
QThread * qthread(void)
Returns the thread, this will always return the same pointer no matter how often you restart the thre...
DatabaseLogger(const char *table)
DatabaseLogger constructor.
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
friend class DBLoggerThread
LoggerBase(const char *string)
LoggerBase Constructor.
bool isConnected(void) const
Only updated once during object creation.
~DatabaseLogger() override
DatabaseLogger deconstructor.
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
int m_fd
contains the file descriptor for the logfile
LogForwardThread()
LogForwardThread constructor.
static QMutex logRevClientMapMutex
QSqlError lastError(void) const
volatile bool m_aborted
Used during shutdown to indicate that the thread should stop ASAP.
QMap< QString, LoggerListItem * > ClientMap
static ClientMap logClientMap
Database logger - logs to the MythTV database.
static QWaitCondition logMsgListNotEmpty
QElapsedTimer m_disabledTime
Elapsed time since the DB logging was disabled.
File-based logger - used for logfiles and console.
void stop(void)
Stop the thread by setting the abort flag.
void prepare(MSqlQuery &query)
Prepare the database query for use, and bind constant values to it.
static LoggingItem * create(const char *_file, const char *_function, int _line, LogLevel_t _level, LoggingType _type)
Create a new LoggingItem.
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
static QMutex logMsgListMutex
~FileLogger() override
FileLogger deconstructor - close the logfile.
QString getTimestampUs(const char *format="yyyy-MM-dd HH:mm:ss") const
bool enqueue(LoggingItem *item)
Enqueues a LoggingItem onto the queue for the thread to consume.
static void logger(cdio_log_level_t level, const char *message)
This is a wrapper around QThread that does several additional things.
bool isRunning(void) const
DatabaseLogger * m_logger
The associated logger instance.
QMutex m_queueMutex
Mutex for protecting the queue.
QList< QString > ClientList
QString GetHostName(void)
FileLogger(const char *filename)
FileLogger constructor.
void incomingSigHup(void)
void reopen(void) override
Reopen the logfile after a SIGHUP.
static FileLogger * create(const QString &filename, QMutex *mutex)
bool queueFull(void)
Indicates when the queue is full.
static QMutex loggerMapMutex
virtual int IncrRef(void)
Increments reference count.
QList< QByteArray > LogMessage
MSqlQuery query(MSqlQuery::InitCon())
std::chrono::seconds m_itemEpoch
QQueue< LoggingItem * > * m_queue
Queue of LoggingItems to insert.
static void forwardMessage(LogMessage *msg)
void run(void) override
Start the thread.
QList< LoggerBase * > LoggerList
QWaitCondition * m_wait
Wait condition used for waiting for the queue to not be full.
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.