/// \brief Expire any clients in the delete list void LogForwardThread::expireClients(void) { #ifndef NOLOGSERVER QMutexLocker lock(&logClientMapMutex); QMutexLocker lock2(&logRevClientMapMutex); QMutexLocker lock3(&logClientToDelMutex); while (!logClientToDel.isEmpty()) { QString clientId = logClientToDel.takeFirst(); logClientCount.deref(); LOG(VB_GENERAL, LOG_INFO, QString("Expiring client %1 (#%2)") .arg(clientId).arg(logClientCount.fetchAndAddOrdered(0))); LoggerListItem *item = logClientMap.take(clientId); if (!item) continue; LoggerList *list = item->list; delete item; while (!list->isEmpty()) { LoggerBase *logger = list->takeFirst(); ClientList *clientList = logRevClientMap.value(logger, NULL); if (!clientList || clientList->size() == 1) { if (clientList) { logRevClientMap.remove(logger); delete clientList; } delete logger; continue; } clientList->removeAll(clientId); } delete list; } // TODO FIXME: This is not thread-safe! // just this daemon left if (logClientCount.fetchAndAddOrdered(0) == 1 && m_shutdownTimer && !m_shutdownTimer->isActive()) { LOG(VB_GENERAL, LOG_INFO, "Starting 5min shutdown timer"); m_shutdownTimer->start(5*60*1000); } #endif }
DatabaseLogger *DatabaseLogger::create(QString table, QMutex *mutex) { QByteArray ba = table.toLocal8Bit(); const char *tble = ba.constData(); DatabaseLogger *logger = dynamic_cast<DatabaseLogger *>(loggerMap.value(table, NULL)); if (logger) return logger; // Need to add a new FileLogger mutex->unlock(); // inserts into loggerMap logger = new DatabaseLogger(tble); mutex->lock(); if (!logger->setupZMQSocket()) { delete logger; return NULL; } ClientList *clients = new ClientList; logRevClientMap.insert(logger, clients); return logger; }
void DatabaseLogger::receivedMessage(const QList<QByteArray> &msg) { // Filter on the clientId QByteArray clientBa = msg.first(); QString clientId = QString(clientBa.toHex()); { QMutexLocker locker(&logRevClientMapMutex); ClientList *clients = logRevClientMap.value(this, NULL); if (!clients || !clients->contains(clientId)) return; } QByteArray json = msg.at(1); LoggingItem *item = LoggingItem::create(json); if (!logmsg(item)) item->DecrRef(); }
SyslogLogger *SyslogLogger::create(QMutex *mutex, bool open) { SyslogLogger *logger = dynamic_cast<SyslogLogger *>(loggerMap.value("", NULL)); if (logger) return logger; // Need to add a new FileLogger mutex->unlock(); // inserts into loggerMap logger = new SyslogLogger(open); mutex->lock(); if (!logger->setupZMQSocket()) { delete logger; return NULL; } ClientList *clients = new ClientList; logRevClientMap.insert(logger, clients); return logger; }
void LogForwardThread::forwardMessage(LogMessage *msg) { #ifdef DUMP_PACKET QList<QByteArray>::const_iterator it = msg->begin(); int i = 0; for (; it != msg->end(); ++it, i++) { QByteArray buf = *it; cout << i << ":\t" << buf.size() << endl << "\t" << buf.toHex().constData() << endl << "\t" << buf.constData() << endl; } #endif msgsSinceHeartbeat.ref(); // First section is the client id QByteArray clientBa = msg->first(); QString clientId = QString(clientBa.toHex()); QByteArray json = msg->at(1); if (json.size() == 0) { // This is either a ping response or a first gasp logClientMapMutex.lock(); LoggerListItem *logItem = logClientMap.value(clientId, NULL); logClientMapMutex.unlock(); if (!logItem) { // Send an initial ping so the client knows we are in the house emit pingClient(clientId); } else { // cout << "pong " << clientId.toLocal8Bit().constData() << endl; loggingGetTimeStamp(&logItem->epoch, NULL); } return; } QMutexLocker lock(&logClientMapMutex); LoggerListItem *logItem = logClientMap.value(clientId, NULL); // cout << "msg " << clientId.toLocal8Bit().constData() << endl; if (logItem) { loggingGetTimeStamp(&logItem->epoch, NULL); } else { LoggingItem *item = LoggingItem::create(json); logClientCount.ref(); LOG(VB_FILE, LOG_DEBUG, QString("New Logging Client: ID: %1 (#%2)") .arg(clientId).arg(logClientCount.fetchAndAddOrdered(0))); #ifndef NOLOGSERVER // TODO FIXME This is not thread-safe! if (logClientCount.fetchAndAddOrdered(0) > 1 && m_shutdownTimer && m_shutdownTimer->isActive()) { LOG(VB_GENERAL, LOG_INFO, "Aborting shutdown timer"); m_shutdownTimer->stop(); } #endif QMutexLocker lock2(&loggerMapMutex); QMutexLocker lock3(&logRevClientMapMutex); // Need to find or create the loggers LoggerList *loggers = new LoggerList; LoggerBase *logger; // FileLogger from logFile QString logfile = item->logFile(); logfile.detach(); if (!logfile.isEmpty()) { logger = FileLogger::create(logfile, lock2.mutex()); ClientList *clients = logRevClientMap.value(logger); if (clients) clients->insert(0, clientId); if (logger && loggers) loggers->insert(0, logger); } #ifndef _WIN32 // SyslogLogger from facility int facility = item->facility(); #if CONFIG_SYSTEMD_JOURNAL if ((facility > 0) || (facility == SYSTEMD_JOURNAL_FACILITY)) { logger = SyslogLogger::create(lock2.mutex(), facility > 0); #else if (facility > 0) { logger = SyslogLogger::create(lock2.mutex()); #endif ClientList *clients = logRevClientMap.value(logger); if (clients) clients->insert(0, clientId); if (logger && loggers) loggers->insert(0, logger); } #endif // DatabaseLogger from table QString table = item->table(); if (!table.isEmpty()) { logger = DatabaseLogger::create(table, lock2.mutex()); ClientList *clients = logRevClientMap.value(logger); if (clients) clients->insert(0, clientId); if (logger && loggers) loggers->insert(0, logger); } logItem = new LoggerListItem; loggingGetTimeStamp(&logItem->epoch, NULL); logItem->list = loggers; logClientMap.insert(clientId, logItem); item->DecrRef(); } #ifndef NOLOGSERVER m_zmqPubSock->sendMessage(*msg); #else if (logItem && logItem->list && !logItem->list->isEmpty()) { LoggerList::iterator it = logItem->list->begin(); LoggingItem *item = LoggingItem::create(json); if (!item) return; for (; it != logItem->list->end(); ++it) { (*it)->logmsg(item); } item->DecrRef(); } #endif } /// \brief Stop the thread by setting the abort flag void LogForwardThread::stop(void) { m_aborted = true; }