Index: sources/storage/Logger.cpp =================================================================== diff -u -r72494685cc15648712935311cb8ff5b208e70cb4 -r630c0a7fe305de7fc1911df4022036c4b10e473e --- sources/storage/Logger.cpp (.../Logger.cpp) (revision 72494685cc15648712935311cb8ff5b208e70cb4) +++ sources/storage/Logger.cpp (.../Logger.cpp) (revision 630c0a7fe305de7fc1911df4022036c4b10e473e) @@ -44,8 +44,16 @@ if ( ! gLongLogName ) { _fileDateFormat = "yyyy_MM_dd"; // date used in the file name } + + startTimer(_interval); } +void Logger::timerEvent(QTimerEvent *) +{ + // log flush timeouot + logTimeout(); +} + /*! * \brief Logger::init * \details Initializes the Class. @@ -138,16 +146,22 @@ connect(&_exportLogsWatcher, SIGNAL(finished ()), this , SLOT(onExportLogs())); + connect(this , SIGNAL(didLog(QString,LogType,bool)), + this , SLOT( onLog(QString,LogType,bool))); - connect(this, SIGNAL(didLog(QString,LogType,bool)), - this, SLOT( onLog(QString,LogType,bool))); + connect(&_MainTimer , SIGNAL( didDateChange ()), + this , SLOT( concurrentRemoveLogs())); - connect(&_MainTimer, SIGNAL( didDateChange ()), - this , SLOT( concurrentRemoveLogs())); - connect(&_removeLogsWatcher, SIGNAL(finished ()), this , SLOT(onRemoveLogs())); + connect(&_flushLogsWatcherA, SIGNAL(finished ()), + this , SLOT(onFlushLogsA())); + connect(&_flushLogsWatcherD, SIGNAL(finished ()), + this , SLOT(onFlushLogsD())); + connect(&_flushLogsWatcherT, SIGNAL(finished ()), + this , SLOT(onFlushLogsT())); + connect(&_DeviceController, SIGNAL( didSDCardStateChange(bool, bool)), this , SLOT( onSDCardStateChange(bool, bool))); connect(&_DeviceController, SIGNAL( didSDCardSpaceChange(bool, qint64, qint64, quint8)), @@ -195,7 +209,7 @@ moveToThread(qApp->thread()); // validated } -void Logger::onLog(const QString &vContent, LogType vLogType, bool vTimestamp) +void Logger::onLog(const QString &vContent, LogType vLogType, bool /*vTimestamp*/) { static bool notified = false; if ( ! _logStorageReady && ! gDisableSDCFailLogStop ) { @@ -205,8 +219,7 @@ } return; } - - log(vContent, vLogType, vTimestamp); + log(vContent, vLogType); } /*! @@ -307,6 +320,30 @@ return ok; } +void Logger::logTimeout() { + if( _cacheCounter ) { + _cacheCounter -- ; + } + else { + _cacheIndexA = logSwitch(_cacheIndexA); // switch the index for caching while the flush is working + _cacheIndexD = logSwitch(_cacheIndexD); // switch the index for caching while the flush is working + concurrentFlushLogT(); + _cacheCounter = _cacheTimeout; + } +} + +bool Logger::logOverflow(LogType vLogType) { + switch ( vLogType ) { + case eLogAppED : return _cacheA[_cacheIndexA].count() >= _cacheCount; + case eLogDebug : return _cacheD[_cacheIndexD].count() >= _cacheCount; + default : return _cacheD[_cacheIndexD].count() >= _cacheCount; + } +} + +int Logger::logSwitch(int vCacheIndex) { + return vCacheIndex == eCache1 ? eCache2 : eCache1;; +} + /*! * \brief Logger::log * \details Logs the content vContent in log type of vLogType. @@ -315,33 +352,89 @@ * \note This method is not thread-safe so is private and needs to be called by concurrentLog * Which uses QtConcurrent::run to run in thread and thread-safe. */ -void Logger::log(const QString &vContent, LogType vLogType, bool vTimestamp) +void Logger::log(const QString &vContent, LogType vLogType) { if ( ! checkThread() ) return; QString mContent; + QDateTime datetime = QDateTime::currentDateTime(); + + // Add timestamp + mContent = datetime.time().toString(_timeFormat) + _sepParam; + mContent += vContent; + // some messages like the version having the U08(uchar) parameters which converts to '\0' and causes problems in reading the log file. + mContent.replace('\0', "0"); + + // Add the recieved message + switch ( vLogType ) { + case eLogAppED : _cacheA[_cacheIndexA] += mContent; break; + case eLogDebug : _cacheD[_cacheIndexD] += mContent; break; + default : _cacheD[_cacheIndexD] += QString("Incorrect type of logging %1").arg(vLogType); + _cacheD[_cacheIndexD] += mContent; break; + } + + if ( logOverflow(vLogType) ) { + switch ( vLogType ) { + case eLogAppED : _cacheIndexA = logSwitch(_cacheIndexA); concurrentFlushLogA(); break; + case eLogDebug : _cacheIndexD = logSwitch(_cacheIndexD); concurrentFlushLogD(); break; + default : _cacheIndexD = logSwitch(_cacheIndexD); concurrentFlushLogD(); break; + } + } + + // console out the log if enabled. + if (_enableConsoleOut) { + qDebug().noquote() << mContent; + } +} + +/*! + * \brief Logger::flush + * \details Fluses the buffered logs of the content vContent in log type of vLogType. + * \param vContent - Log buffer + * \param vLogType - Log type + * \return number of lines flushed into log file + * \note This method is not thread-safe so is private and needs to be called by concurrentFlush + * Which uses QtConcurrent::run to run in thread and thread-safe. + */ +int Logger::flush(LogType vLogType) +{ + if ( ! checkThread() ) return 0; + + + //NOTE: the _cacheIndex has been (has to be) switched for the log to continue while we are in the temp thread to flush the log + QString mContent; + QDateTime datetime = QDateTime::currentDateTime(); + int count = 0; + // - Add header - QString currentDate = QDate::currentDate().toString(_fileDateFormat); + QString currentDate = datetime.date().toString(_fileDateFormat); if ( _logFileNameDate != currentDate ) { if ( ! _logFileNameDate.isEmpty() ) { switch ( vLogType ) { case eLogAppED : mContent = _headerA; break; case eLogDebug : mContent = _headerD; break; - // case LogType::eLogTrtmt: // this type of log will never happen here. Only put here to make sure it is intentional. - default : mContent = _headerD; break; + default : break; //TODO create another cacheType enum } - mContent += "\r\n"; + mContent += _sepLines; } _logFileNameDate = currentDate; } + // - Add content + switch ( vLogType ) { + case eLogAppED : { QAtomicInt cacheIndex = logSwitch(_cacheIndexA); count = _cacheA[cacheIndex].count(); mContent += _cacheA[cacheIndex].join(_sepLines); _cacheA[cacheIndex].clear(); } break; + case eLogDebug : { QAtomicInt cacheIndex = logSwitch(_cacheIndexD); count = _cacheD[cacheIndex].count(); mContent += _cacheD[cacheIndex].join(_sepLines); _cacheD[cacheIndex].clear(); } break; + default : { } break; //TODO create another cacheType enum + } + // - Make log file name if (_logFileNameMode.isEmpty()) { _logFileNameMode = _logFileNameMode_init; - _logFileNameTime = QDateTime::currentDateTime().time().toString(_fileTimeFormat); + _logFileNameTime = datetime.time().toString(_fileTimeFormat); } + // - make the file name QString fileName; if ( ! gLongLogName ) { fileName = _logFileNameDate @@ -357,7 +450,7 @@ // case LogType::eLogTrtmt: // this type of log will never happen here. Only put here to make sure it is intentional. switch (vLogType) { case LogType::eLogAppED: { - // ------------------------------------------------------------------------ TODO: Improve : function declaration + // ------------------------------------------------------------------------ TODO: Improve : declare function fileName += _logFileNameExt[vLogType]; static QString oFileName; if( oFileName != fileName ) { @@ -372,7 +465,7 @@ } break; case LogType::eLogDebug: { - // ------------------------------------------------------------------------ TODO: Improve : function declaration + // ------------------------------------------------------------------------ TODO: Improve : declare function fileName += _logFileNameExt[vLogType]; static QString oFileName; if( oFileName != fileName ) { @@ -392,31 +485,102 @@ LOG_DEBUG(QString("Incorrect type of logging %1").arg(vLogType)); } - // - Add timestamp - if ( vTimestamp ) - mContent = QTime::currentTime().toString(_timeFormat) + _separator; - - // - Add the content - mContent += vContent; - // some messages like the version having the U08(uchar) parameters which converts to '\0' and causes problems in reading the log file. - mContent.replace('\0', "0"); - - // - Make the log path and write to log. + // - Make the log path QString logPathName = _logPathNames[vLogType]; if (logPathName.isEmpty()) logPathName = _logPathNames[eLogDebug]; _logFileName = logPathName + fileName; + // - Write to log bool isWritten = FileHandler::write(_logFileName, mContent + "\r\n", true); - if(!isWritten) emit didLogIOFail(); + if(! isWritten) emit didLogIOFail(); - // console out the log if enabled. - if (_enableConsoleOut) { - qDebug().noquote() << mContent; - } + return count; } +int Logger::flushTimeout() { + int count = 0; + count += flush(LogType::eLogAppED); + count += flush(LogType::eLogDebug); + return count; +} + /*! + * \brief Logger::concurrentFlushLogs + * \details Flushes the log buffer to the file in a separate thread + * \return always returns true for now. + * \note This method uses QtConcurrent to execute the flush method in a separate temp thread. + */ +bool Logger::concurrentFlushLogA() +{ + qDebug() << " - " << LogType::eLogAppED << " - " << _cacheIndexA; + emit didFlushLogsA(true); + _flushElapsedA.start(); + log("Flush app Logs Starting",LogType::eLogDebug); + QFuture mFuture = QtConcurrent::run(this, &Logger::flush, LogType::eLogAppED); + _flushLogsWatcherA.setFuture(mFuture); + return true; +} + +/*! + * \brief Logger::concurrentFlushLogs + * \details Flushes the log buffer to the file in a separate thread + * \return always returns true for now. + * \note This method uses QtConcurrent to execute the flush method in a separate temp thread. + */ +bool Logger::concurrentFlushLogD() +{ + qDebug() << " - " << LogType::eLogDebug << " - " << _cacheIndexD; + emit didFlushLogsD(true); + _flushElapsedD.start(); + log("Flush err Logs Starting",LogType::eLogDebug); + QFuture mFuture = QtConcurrent::run(this, &Logger::flush, LogType::eLogDebug); + _flushLogsWatcherD.setFuture(mFuture); + return true; +} + +bool Logger::concurrentFlushLogT() +{ + qDebug() << " - " << "Timeout" << " - " << _cacheIndexA << " - " << _cacheIndexD;; + emit didFlushLogsT(true); + _flushElapsedT.start(); + log("Flush Logs Timeout Starting",LogType::eLogDebug); + QFuture mFuture = QtConcurrent::run(this, &Logger::flushTimeout); + _flushLogsWatcherT.setFuture(mFuture); + return true; +} + +/*! + * \brief Logger::onRemoveLogs + * \details Remove old logs notification slot which logs result of remove. + */ +void Logger::onFlushLogsA() +{ + log(tr("Flush app Logs Ended: %1,%2").arg(_flushLogsWatcherA.result()).arg(_flushElapsedA.elapsed()),LogType::eLogDebug); + emit didFlushLogsA(false); +} + +/*! + * \brief Logger::onRemoveLogs + * \details Remove old logs notification slot which logs result of remove. + */ +void Logger::onFlushLogsD() +{ + log(tr("Flush err Logs Ended: %1,%2").arg(_flushLogsWatcherD.result()).arg(_flushElapsedD.elapsed()),LogType::eLogDebug); + emit didFlushLogsD(false); +} + +/*! + * \brief Logger::onRemoveLogs + * \details Remove old logs notification slot which logs result of remove. + */ +void Logger::onFlushLogsT() +{ + log(tr("Flush Logs Timeout Ended: %1,%2").arg(_flushLogsWatcherT.result()).arg(_flushElapsedT.elapsed()),LogType::eLogDebug); + emit didFlushLogsT(false); +} + +/*! * \brief Logger::exportLogs * \details Exports the log files from log folder (Storage::Log_Base_Path_Name_Location) * into USB drive folder (Storage::USB_Mount_Point)